Repository: plexis-js/plexis
Pull request #104 (2019-10-31 03:30:08)

Feature/includes
Hey @vorillaz,

I was just reviewing the pr after it was merged and realized that the pr could of been improved. I wanted to open this new pr to fix the examples I had and have the includes function to also handle non-string values as parameters as well and new tests for that.

Thanks


Patch:
diff --git a/docs/pages/api.md b/docs/pages/api.md
index a709fe8..56c357b 100644
--- a/docs/pages/api.md
+++ b/docs/pages/api.md
@@ -6,6 +6,7 @@
 - [distance](/packages/distance)
 - [endsWith](/packages/endsWith)
 - [escapeHTML](/packages/escapeHTML)
+- [head](/packages/head)
 - [isAlpha](/packages/isAlpha)
 - [isAlphaNumeric](/packages/isAlphaNumeric)
 - [isLowerCase](/packages/isLowerCase)
@@ -16,6 +17,7 @@
 - [repeat](/packages/repeat)
 - [startsWith](/packages/startsWith)
 - [toCamelCase](/packages/toCamelCase)
+- [toCapitals](/packages/toCapitals)
 - [toChicago](/packages/toChicago)
 - [toChunks](/packages/toChunks)
 - [toHuman](/packages/toHuman)
@@ -30,3 +32,4 @@
 - [withoutDiacritics](/packages/withoutDiacritics)
 - [withoutHTML](/packages/withoutHTML)
 - [withoutIndent](/packages/withoutIndent)
+- [tail](/packages/tail)
diff --git a/packages/head/README.md b/packages/head/README.md
new file mode 100644
index 0000000..ce11647
--- /dev/null
+++ b/packages/head/README.md
@@ -0,0 +1,24 @@
+## `head`
+
+Extracts the first length characters from the input text.
+
+`npm i @plexis/head`
+
+**Usage**
+
+```javascript
+import head from '@plexis/head';
+
+head(); // => ''
+head('Hello'); // => 'H'
+head('Hello', 2); // => 'He'
+head('Hello', 100); // => 'Hello'
+```
+
+**Aliases**
+
+```javascript
+import {head} from 'plexis';
+import {first} from 'plexis';
+import {popFirst} from 'plexis';
+```
diff --git a/packages/head/package.json b/packages/head/package.json
new file mode 100644
index 0000000..61a67f0
--- /dev/null
+++ b/packages/head/package.json
@@ -0,0 +1,26 @@
+{
+  "name": "@plexis/head",
+  "version": "0.0.21",
+  "main": "dist/index.js",
+  "module": "dist/index.esm.js",
+  "jsnext:main": "./src/index.js",
+  "files": [
+    "dist",
+    "src"
+  ],
+  "license": "MIT",
+  "keywords": [
+    "utility",
+    "string",
+    "parse",
+    "format",
+    "validate"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/plexis-js/plexis.git"
+  },
+  "publishConfig": {
+    "access": "public"
+  }
+}
diff --git a/packages/head/src/index.js b/packages/head/src/index.js
new file mode 100644
index 0000000..e4715e9
--- /dev/null
+++ b/packages/head/src/index.js
@@ -0,0 +1,23 @@
+/**
+ * @description Extracts the first length characters from the input text.
+ * @param {String} text
+ * @param {Number} length
+ * @example
+ * head(); // => ''
+ * head('Hello'); // => 'H'
+ * head('Hello', 2); // => 'He'
+ * head('Hello', 100); // => 'Hello'
+ */
+const head = (text = '', length = 1) => {
+  if (typeof text !== 'string') {
+    throw new Error('Input text must be of type string');
+  }
+
+  if (isNaN(length) || typeof length !== 'number') {
+    throw new Error('Length characters must be of type number');
+  }
+
+  return text.substr(0, length);
+};
+
+export default head;
diff --git a/packages/includes/src/index.js b/packages/includes/src/index.js
index d90ef73..3f0222e 100644
--- a/packages/includes/src/index.js
+++ b/packages/includes/src/index.js
@@ -5,14 +5,14 @@
  * @params {number} [position] - check at given position
  * @return {boolean} Whether string2 is part of string1
  * @example
- * isNumeric('1000') // returns true
- * isNumeric('Foo') // returns false
+ * includes('Foo', 'oo') // returns true
+ * includes('Foo', 'Foo', 2) // returns false
  */
 
-const includes = (inputString = null, searchString = null, position = 0) =>
+const includes = (inputString, searchString, position = 0) =>
   !!(
-    inputString !== null &&
-    searchString !== null &&
+    typeof inputString === 'string' &&
+    typeof searchString === 'string' &&
     RegExp(searchString, 'g').test(inputString.substring(position))
   );
 
diff --git a/packages/plexis/package.json b/packages/plexis/package.json
index ddccfac..b5e53ef 100644
--- a/packages/plexis/package.json
+++ b/packages/plexis/package.json
@@ -18,6 +18,7 @@
     "@plexis/distance": "^0.0.21",
     "@plexis/ends-with": "^0.0.21",
     "@plexis/escape-html": "^0.0.21",
+    "@plexis/head": "^0.0.21",
     "@plexis/is-alpha": "^0.0.21",
     "@plexis/is-alphanumeric": "^0.0.21",
     "@plexis/is-lowercase": "^0.0.21",
@@ -27,6 +28,7 @@
     "@plexis/is-uppercase": "^0.0.21",
     "@plexis/starts-with": "^0.0.21",
     "@plexis/to-camel-case": "^0.0.21",
+    "@plexis/to-capitals": "^0.0.21",
     "@plexis/to-chicago": "^0.0.21",
     "@plexis/to-chunks": "^0.0.21",
     "@plexis/to-human": "^0.0.21",
@@ -40,7 +42,8 @@
     "@plexis/when": "^0.0.21",
     "@plexis/without-diacritics": "^0.0.21",
     "@plexis/without-html": "^0.0.21",
-    "@plexis/without-indent": "^0.0.21"
+    "@plexis/without-indent": "^0.0.21",
+    "@plexis/tail": "^0.0.21"
   },
   "keywords": [
     "utility",
diff --git a/packages/plexis/src/index.js b/packages/plexis/src/index.js
index dfdcfbe..604cc1e 100644
--- a/packages/plexis/src/index.js
+++ b/packages/plexis/src/index.js
@@ -11,6 +11,7 @@ export {
 } from '@plexis/distance';
 export {default as endsWith} from '@plexis/ends-with';
 export {default as escapeHTML} from '@plexis/escape-html';
+export {default as head, default as first, default as popFirst} from '@plexis/head';
 export {default as isAlpha} from '@plexis/is-alpha';
 export {default as isLower, default as isLowerCase} from '@plexis/is-lowercase';
 export {default as isNum, default as isNumeric} from '@plexis/is-numeric';
@@ -23,6 +24,11 @@ export {
   default as camelize,
   default as toCamelCase
 } from '@plexis/to-camel-case';
+export {
+  default as toCapitals,
+  default as toFirstCapital,
+  default as capitalize
+} from '@plexis/to-capitals';
 export {
   default as toChicagoManualStyle,
   default as toChicagoStyle,
@@ -59,3 +65,4 @@ export {
   default as isAlphaDigit
 } from '@plexis/is-alphanumeric';
 export {default as withoutHTML, default as removeHTML} from '@plexis/without-html';
+export {default as tail, default as rest, default as last, default as pop} from '@plexis/tail';
diff --git a/packages/tail/README.md b/packages/tail/README.md
new file mode 100644
index 0000000..80c8a8d
--- /dev/null
+++ b/packages/tail/README.md
@@ -0,0 +1,24 @@
+## `head`
+
+Extracts the last length characters from the input text
+
+`npm i @plexis/tail`
+
+**Usage**
+
+```javascript
+import tail from '@plexis/tail';
+tail(); // => ''
+tail('Hello'); // => 'o'
+tail('Hello', 2); // => 'lo'
+tail('Hello', 100); // => 'Hello'
+```
+
+**Aliases**
+
+```javascript
+import {tail} from 'plexis';
+import {rest} from 'plexis';
+import {last} from 'plexis';
+import {pop} from 'plexis';
+```
diff --git a/packages/tail/package.json b/packages/tail/package.json
new file mode 100644
index 0000000..bad04e3
--- /dev/null
+++ b/packages/tail/package.json
@@ -0,0 +1,26 @@
+{
+    "name": "@plexis/tail",
+    "version": "0.0.21",
+    "main": "dist/index.js",
+    "module": "dist/index.esm.js",
+    "jsnext:main": "./src/index.js",
+    "files": [
+      "dist",
+      "src"
+    ],
+    "license": "MIT",
+    "keywords": [
+      "utility",
+      "string",
+      "parse",
+      "format",
+      "validate"
+    ],
+    "repository": {
+      "type": "git",
+      "url": "git+https://github.com/plexis-js/plexis.git"
+    },
+    "publishConfig": {
+      "access": "public"
+    }
+  }
\ No newline at end of file
diff --git a/packages/tail/src/index.js b/packages/tail/src/index.js
new file mode 100644
index 0000000..266fc68
--- /dev/null
+++ b/packages/tail/src/index.js
@@ -0,0 +1,15 @@
+/**
+ * @description Extracts the last length characters from the input text
+ * @param {String} text
+ * @param {Number} endingPosition, optional
+ * @example
+ * tail(); // returns ''
+ * tail('Hello'); // returns 'o'
+ * tail('Hello', 2); // returns 'lo'
+ * tail('Hello', 100); // returns 'Hello'
+ */
+
+const tail = (text, endingPosition = 1) =>
+  text ? text.substring(text.length - endingPosition) : '';
+
+export default tail;
diff --git a/packages/toCapitals/README.md b/packages/toCapitals/README.md
new file mode 100644
index 0000000..c674303
--- /dev/null
+++ b/packages/toCapitals/README.md
@@ -0,0 +1,22 @@
+## `@plexis/to-capitals`
+
+Converts the first character of the input text to upper case. If the second parameter is true, the method converts the rest of the subject to lower case.
+
+`npm i @plexis/to-capitals`
+
+**Usage**
+
+```javascript
+import toCapitals from '@plexis/to-capitals';
+
+toCapitals('foo Bar'); // returns 'Foo Bar'
+toCapitals('fOO Bar'); // returns 'FOO Bar'
+toCapitals('fOO Bar', true); // returns 'Foo bar'
+```
+
+**Aliases**
+
+```javascript
+import toCapitals from '@plexis/to-capitals';
+import {toCapitals, toFirstCapital, capitalize} from 'plexis';
+```
diff --git a/packages/toCapitals/package.json b/packages/toCapitals/package.json
new file mode 100644
index 0000000..76084cd
--- /dev/null
+++ b/packages/toCapitals/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "@plexis/to-capitals",
+  "version": "0.0.21",
+  "main": "dist/index.js",
+  "module": "dist/index.esm.js",
+  "jsnext:main": "./src/index.js",
+  "description": "Converts the first character of the input text to upper case. If the second parameter is true, the method converts the rest of the subject to lower case",
+  "keywords": [
+    "utility",
+    "string"
+  ],
+  "author": "Angel Gonzalez <angelbroz@gmail.com>",
+  "homepage": "https://github.com/plexis-js/plexis#readme",
+  "license": "MIT",
+  "files": [
+    "lib"
+  ],
+  "publishConfig": {
+    "access": "public"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/plexis-js/plexis.git"
+  },
+  "bugs": {
+    "url": "https://github.com/plexis-js/plexis/issues"
+  }
+}
\ No newline at end of file
diff --git a/packages/toCapitals/src/index.js b/packages/toCapitals/src/index.js
new file mode 100644
index 0000000..cb1518a
--- /dev/null
+++ b/packages/toCapitals/src/index.js
@@ -0,0 +1,17 @@
+/**
+ * @description Converts the first character of the input text to upper case. If the second parameter is true, the method converts the rest of the subject to lower case.
+ * @param {String} text
+ * @param {Boolean} isLowercase
+ * @example
+ * toPred('foo Bar') // returns 'Foo Bar'
+ * toPred('fOO Bar') // returns 'FOO Bar'
+ * toPred('fOO Bar', true) // returns 'Foo bar'
+ */
+const toCapitals = (text = '', isLowercase = false) => {
+  let firstCharacter = text.charAt(0).toUpperCase();
+  let restOfString = isLowercase ? text.slice(1).toLowerCase() : text.slice(1);
+
+  return firstCharacter + restOfString;
+};
+
+export default toCapitals;


Test patch:
diff --git a/packages/head/test/index.js b/packages/head/test/index.js
new file mode 100644
index 0000000..1d837fd
--- /dev/null
+++ b/packages/head/test/index.js
@@ -0,0 +1,40 @@
+import head from '../src';
+
+describe('returns the first length characters from the input text', () => {
+  const cases = [{text: 'John'}, {text: 'Doe', length: 2}, {text: 'Hello', length: 100}];
+  const expected = ['J', 'Do', 'Hello'];
+
+  cases.forEach(({text, length}, i) => {
+    test(`head(${text},${length})`, () => {
+      expect(head(text, length)).toBe(expected[i]);
+    });
+  });
+});
+
+test('returns empty string if there is no input text provided', () => {
+  expect(head()).toBe('');
+});
+
+describe('throws error if text is invalid', () => {
+  const invalids = [null, NaN, {key: 'value'}, ['invalid'], 55];
+
+  invalids.forEach(invalid => {
+    test(`head(${invalid})`, () => {
+      expect(() => {
+        head(invalid);
+      }).toThrow();
+    });
+  });
+});
+
+describe('throws error if length is invalid', () => {
+  const invalids = [NaN, null, '55', {key: 'value'}, ['invalid']];
+
+  invalids.forEach(invalid => {
+    test(`head('Hello',${invalid})`, () => {
+      expect(() => {
+        head('Hello', invalid);
+      }).toThrow();
+    });
+  });
+});
diff --git a/packages/includes/test/includes.test.js b/packages/includes/test/includes.test.js
index 88b4729..27b24cd 100644
--- a/packages/includes/test/includes.test.js
+++ b/packages/includes/test/includes.test.js
@@ -30,4 +30,12 @@ describe('@plexis/isNumeric', () => {
   it('Second parameter as substring of first parameter, but substring has different casing', () => {
     expect(includes('Foo', 'Oo')).toBe(false);
   });
+  
+  it('Second parameter as non string value', () => {
+    expect(includes('Foo', false)).toBe(false);
+  });
+
+  it('First parameter as non string value', () => {
+    expect(includes(null, 'Foo')).toBe(false);
+  });
 });
diff --git a/packages/plexis/test/__snapshots__/index.js.snap b/packages/plexis/test/__snapshots__/index.js.snap
index 6780a90..dc1e65d 100644
--- a/packages/plexis/test/__snapshots__/index.js.snap
+++ b/packages/plexis/test/__snapshots__/index.js.snap
@@ -13,6 +13,9 @@ Array [
   "levenshtein",
   "endsWith",
   "escapeHTML",
+  "head",
+  "first",
+  "popFirst",
   "isAlpha",
   "isLower",
   "isLowerCase",
@@ -27,6 +30,9 @@ Array [
   "camelCase",
   "camelize",
   "toCamelCase",
+  "toCapitals",
+  "toFirstCapital",
+  "capitalize",
   "toChicagoManualStyle",
   "toChicagoStyle",
   "toChicagoTitle",
@@ -61,5 +67,9 @@ Array [
   "isAlphaDigit",
   "withoutHTML",
   "removeHTML",
+  "tail",
+  "rest",
+  "last",
+  "pop",
 ]
 `;
diff --git a/packages/tail/test/index.js b/packages/tail/test/index.js
new file mode 100644
index 0000000..d26b091
--- /dev/null
+++ b/packages/tail/test/index.js
@@ -0,0 +1,8 @@
+import tail from '../src';
+
+it('Extracts the last length characters from the input text', () => {
+  expect(tail()).toBe('');
+  expect(tail('Hello')).toBe('o');
+  expect(tail('Hello', 2)).toBe('lo');
+  expect(tail('Hello', 100)).toBe('Hello');
+});
diff --git a/packages/toCapitals/test/index.js b/packages/toCapitals/test/index.js
new file mode 100644
index 0000000..d3afafb
--- /dev/null
+++ b/packages/toCapitals/test/index.js
@@ -0,0 +1,23 @@
+import toCapitals from '../src';
+
+describe('@plexis/to-capitals', () => {
+  it('no params, should be empty string', () => {
+    expect(toCapitals()).toBe('');
+  });
+
+  it('empty string,, should be empty strin', () => {
+    expect(toCapitals('')).toBe('');
+  });
+
+  it('should capitalize only first letter, the rest of the string must be intact', () => {
+    expect(toCapitals('foO bar')).toBe('FoO bar');
+  });
+
+  it('should capitalize only first letter, the rest of the string must be intact', () => {
+    expect(toCapitals('foO bAr')).toBe('FoO bAr');
+  });
+
+  it('should capitalize the first letter, the rest of the subject to lower case.', () => {
+    expect(toCapitals('FOO BAR', true)).toBe('Foo bar');
+  });
+});