Repository: plexis-js/plexis
Pull request #98 (2019-10-29 05:58:50)

feat(to-capitals): implementation of toCapitals feature #8
Implementing #8


Patch:
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 0000000..9a76efb
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,21 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 10
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+# Issues with these labels will never be considered stale
+exemptLabels:
+  - pinned
+  - security
+  - enhancement
+
+# Label to use when marking an issue as stale
+staleLabel: wontfix
+
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+  This issue has been automatically marked as stale because it has not had
+  recent activity. It will be closed if no further activity occurs. Thank you
+  for your contributions. May the force be with you!
+
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/docs/pages/api.md b/docs/pages/api.md
index d8497a1..56c357b 100644
--- a/docs/pages/api.md
+++ b/docs/pages/api.md
@@ -1,18 +1,23 @@
 ## API
 
 - [cache](/packages/cache)
+- [compare](/packages/compare)
 - [compose](/packages/compose)
 - [distance](/packages/distance)
+- [endsWith](/packages/endsWith)
 - [escapeHTML](/packages/escapeHTML)
+- [head](/packages/head)
 - [isAlpha](/packages/isAlpha)
 - [isAlphaNumeric](/packages/isAlphaNumeric)
 - [isLowerCase](/packages/isLowerCase)
 - [isNumeric](/packages/isNumeric)
+- [includes](/packages/includes)
 - [isString](/packages/isString)
 - [isUpperCase](/packages/isUpperCase)
 - [repeat](/packages/repeat)
 - [startsWith](/packages/startsWith)
 - [toCamelCase](/packages/toCamelCase)
+- [toCapitals](/packages/toCapitals)
 - [toChicago](/packages/toChicago)
 - [toChunks](/packages/toChunks)
 - [toHuman](/packages/toHuman)
@@ -25,4 +30,6 @@
 - [toTitle](/packages/toTitle)
 - [when](/packages/when)
 - [withoutDiacritics](/packages/withoutDiacritics)
+- [withoutHTML](/packages/withoutHTML)
 - [withoutIndent](/packages/withoutIndent)
+- [tail](/packages/tail)
diff --git a/packages/compare/README.md b/packages/compare/README.md
new file mode 100644
index 0000000..e3a0f84
--- /dev/null
+++ b/packages/compare/README.md
@@ -0,0 +1,22 @@
+## `compare`
+
+Compares input text as humans do.
+
+`npm i @plexis/compare`
+
+**Usage**
+
+```javascript
+import naturalCompare from '@plexis/compare';
+
+compare('A', 'b'); // returns 1
+compare('A woman', 'a woman'); // returns 1
+compare('b', 'B'); // returns -1
+```
+
+**Aliases**
+
+```javascript
+import compare from '@plexis/compare';
+import {compare, compareLikeHuman, naturalCompare} from 'plexis';
+```
diff --git a/packages/compare/package.json b/packages/compare/package.json
new file mode 100644
index 0000000..b062fe8
--- /dev/null
+++ b/packages/compare/package.json
@@ -0,0 +1,27 @@
+{
+  "name": "@plexis/compare",
+  "version": "0.0.21",
+  "main": "dist/index.js",
+  "module": "dist/index.esm.js",
+  "jsnext:main": "./src/index.js",
+  "files": [
+    "dist", 
+    "src"
+  ],
+  "author": "Brandon Skinner <brandon.m.skinner@gmail.com>",
+  "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/compare/src/index.js b/packages/compare/src/index.js
new file mode 100644
index 0000000..badecaa
--- /dev/null
+++ b/packages/compare/src/index.js
@@ -0,0 +1,24 @@
+/*
+ * @description Compares input text as humans do.
+ * @param {String} first
+ * @param {String} second
+ * @returns {Integer}
+ * @example
+ * compare('', '') // => 0
+ * compare('A', 'a') // => 1
+ * compare('A', 'b') // => 1
+ * compare('A woman', 'a woman') // => 1
+ * compare('b', 'B') // => -1
+ * compare('C', 'b') // => -1
+ * compare('Qux20', 'Qux5') // => -1
+ * compare('Qux10', 'Qux11') // => 1
+ */
+const compare = (first, second) => {
+  return second.localeCompare(first, undefined, {
+    numeric: true,
+    sensitivity: 'case',
+    caseFirst: 'upper'
+  });
+};
+
+export default compare;
diff --git a/packages/endsWith/README.md b/packages/endsWith/README.md
new file mode 100644
index 0000000..8ecf9a4
--- /dev/null
+++ b/packages/endsWith/README.md
@@ -0,0 +1,18 @@
+# `endsWith`
+
+Checks whether the input text ends with the given pattern
+
+`npm i @plexis/ends-with`
+
+## Usage
+
+```javascript
+import endsWith from '@plexis/ends-with';
+
+const txt = 'This is me';
+
+endsWith(txt, 'is me'); // true
+endsWith(txt, 'is m', txt.length - 1); // true
+endsWith(txt, 'is m', txt.length); // false
+endsWith(txt, 'Foo'); // false
+```
diff --git a/packages/endsWith/package.json b/packages/endsWith/package.json
new file mode 100644
index 0000000..b8cba96
--- /dev/null
+++ b/packages/endsWith/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "@plexis/ends-with",
+  "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"
+  },
+  "dependencies": {
+    "@plexis/is-string": "^0.0.21"
+  }
+}
diff --git a/packages/endsWith/src/index.js b/packages/endsWith/src/index.js
new file mode 100644
index 0000000..ad4c2f2
--- /dev/null
+++ b/packages/endsWith/src/index.js
@@ -0,0 +1,36 @@
+import isString from '@plexis/is-string';
+
+/**
+ * @description Checks whether the input text ends with the given pattern
+ *
+ * @param {String} text - String to be tested
+ * @param {String|Regex} pattern - Pattern to be checked against text
+ * @param {Number} startingPosition, optional - The position of the end of the string
+ *
+ * @example
+ *
+ * endsWith('This is me', 'is me') // true
+ * endsWith('This is me', 'is m', ('This is me').length - 1) // true
+ * endsWith('This is me', 'is m', ('This is me').length) // false
+ * endsWith('This is me', 'Foo') // false
+ */
+const endsWith = (text, pattern, startingPosition = text.length) => {
+  if (isString(pattern)) {
+    return text.endsWith(pattern, startingPosition);
+  }
+
+  if (pattern instanceof RegExp) {
+    const stringPattern = String(pattern);
+    const flags = stringPattern.slice(stringPattern.lastIndexOf('/') + 1);
+
+    const leadingAndTrailingSlashes = new RegExp(`(?:^\/|\/${flags}$)`, 'g');
+    const internalRegexString = stringPattern.replace(leadingAndTrailingSlashes, '');
+    const endsWithRegex = new RegExp(`${internalRegexString}$`, flags);
+
+    return endsWithRegex.test(text.slice(0, startingPosition));
+  }
+
+  return false;
+};
+
+export default endsWith;
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/README.md b/packages/includes/README.md
new file mode 100644
index 0000000..c0cb2e6
--- /dev/null
+++ b/packages/includes/README.md
@@ -0,0 +1,28 @@
+# `@plexis/includes`
+
+Checks if the search is part of the input string in the given position
+
+**Installation**
+`npm i @plexis/includes`
+
+**Usage**
+
+```javascript
+import includes from '@plexis/includes';
+
+includes(); // => false
+includes(''); // => false
+includes('', ''); // => true
+includes('Foo', 'Foo'); // => true
+includes('Foo', 'Foo'); // => true
+includes('Foo', 'Foo', 2); // => false
+includes('Foo', 'oo'); // => true
+includes('Foo', 'Oo'); // => false
+```
+
+**Aliases**
+
+```javascript
+import includes from '@plexis/includes';
+import {includes, has} from 'plexis';
+```
diff --git a/packages/includes/package.json b/packages/includes/package.json
new file mode 100644
index 0000000..79a90b4
--- /dev/null
+++ b/packages/includes/package.json
@@ -0,0 +1,27 @@
+{
+  "name": "@plexis/includes",
+  "version": "0.0.20",
+  "main": "dist/index.js",
+  "module": "dist/index.esm.js",
+  "jsnext:main": "./src/index.js",
+  "author": "edKim <nauthiz.jera@gmail.com>",
+  "license": "MIT",
+  "files": [
+    "dist",
+    "src"
+  ],
+  "keywords": [
+    "utility",
+    "string",
+    "parse",
+    "format",
+    "validate"
+  ],
+  "publishConfig": {
+    "access": "public"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/plexis-js/plexis.git"
+  }
+}
diff --git a/packages/includes/src/index.js b/packages/includes/src/index.js
new file mode 100644
index 0000000..d90ef73
--- /dev/null
+++ b/packages/includes/src/index.js
@@ -0,0 +1,19 @@
+/**
+ * @description Checks if the search is part of the input string in the given position
+ * @params {string} [inputString] input string
+ * @params {string) [searchString] search string
+ * @params {number} [position] - check at given position
+ * @return {boolean} Whether string2 is part of string1
+ * @example
+ * isNumeric('1000') // returns true
+ * isNumeric('Foo') // returns false
+ */
+
+const includes = (inputString = null, searchString = null, position = 0) =>
+  !!(
+    inputString !== null &&
+    searchString !== null &&
+    RegExp(searchString, 'g').test(inputString.substring(position))
+  );
+
+export default includes;
diff --git a/packages/plexis/package.json b/packages/plexis/package.json
index e0887af..b5e53ef 100644
--- a/packages/plexis/package.json
+++ b/packages/plexis/package.json
@@ -13,17 +13,22 @@
   ],
   "license": "MIT",
   "dependencies": {
+    "@plexis/compare": "^0.0.21",
     "@plexis/compose": "^0.0.21",
     "@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",
     "@plexis/is-numeric": "^0.0.21",
+    "@plexis/includes": "^0.0.20",
     "@plexis/is-string": "^0.0.21",
     "@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",
@@ -36,7 +41,9 @@
     "@plexis/to-title": "^0.0.21",
     "@plexis/when": "^0.0.21",
     "@plexis/without-diacritics": "^0.0.21",
-    "@plexis/without-indent": "^0.0.21"
+    "@plexis/without-html": "^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 042f0e2..604cc1e 100644
--- a/packages/plexis/src/index.js
+++ b/packages/plexis/src/index.js
@@ -1,13 +1,21 @@
+export {
+  default as compare,
+  default as compareLikeHuman,
+  default as naturalCompare
+} from '@plexis/compare';
 export {default as compose, default as _do} from '@plexis/compose';
 export {
   default as calcLevenshtein,
   default as distance,
   default as levenshtein
 } 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';
+export {default as includes, default as has} from '@plexis/includes';
 export {default as isString} from '@plexis/is-string';
 export {default as isUpper, default as isUpperCase} from '@plexis/is-uppercase';
 export {default as startsWith} from '@plexis/starts-with';
@@ -16,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,
@@ -51,3 +64,5 @@ export {
   default as isAlphanumeric,
   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;
diff --git a/packages/withoutHTML/README.md b/packages/withoutHTML/README.md
new file mode 100644
index 0000000..013a6cb
--- /dev/null
+++ b/packages/withoutHTML/README.md
@@ -0,0 +1,25 @@
+# `@plexis/withoutHTML`
+
+Removes HTML tags from the input text.
+
+**Installation**
+`npm i @plexis/without-html`
+
+**Usage**
+
+```javascript
+import withoutHTML from '@plexis/without-html';
+
+withoutHTML('Hello world'); // => 'Hello world'
+withoutHTML('<p>Hello</p> world'); // => ' world'
+withoutHTML('<p Hello world'); // => '<p Hello world'
+withoutHTML('<p id="">Hello world</p>'); // => ''
+withoutHTML('<p id="" Hello world</p> <b></b> from the underground'); // => ' from the underground'
+```
+
+**Aliases**
+
+```javascript
+import withoutHTML from '@plexis/without-html';
+import {withoutHTML, removeHTML} from 'plexis';
+```
diff --git a/packages/withoutHTML/package.json b/packages/withoutHTML/package.json
new file mode 100644
index 0000000..c583dc8
--- /dev/null
+++ b/packages/withoutHTML/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "@plexis/without-html",
+  "version": "0.0.21",
+  "main": "dist/index.js",
+  "module": "dist/index.esm.js",
+  "jsnext:main": "./src/index.js",
+  "files": [
+    "dist",
+    "src"
+  ],
+  "authors": [
+    "Gopi Krishna <gopiwayz@gmail.com> (https://bgopikrishna.me)"
+  ],
+  "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/withoutHTML/src/index.js b/packages/withoutHTML/src/index.js
new file mode 100644
index 0000000..9c36552
--- /dev/null
+++ b/packages/withoutHTML/src/index.js
@@ -0,0 +1,20 @@
+/**
+ * @description Remove HTML tags from the input text
+ * @param {String} text
+ * @returns {String} text without HTML
+ * @example
+ * withoutHTML('Hello world') => 'Hello world'
+ * withoutHTML('<p>Hello</p> world') => ' world'
+ * withoutHTML('<p Hello world') => '<p Hello world'
+ * withoutHTML('<p id="">Hello world</p>') => ''
+ * withoutHTML('<p id="" Hello world</p> <b></b> from the underground ') => ' from the underground'
+ */
+
+const withoutHTML = string => {
+  const wordPatt = /[^>]+>/g;
+  const stringWithOutHtml = string.replace(wordPatt, '');
+
+  return stringWithOutHtml;
+};
+
+export default withoutHTML;


Test patch:
diff --git a/packages/compare/test/index.js b/packages/compare/test/index.js
new file mode 100644
index 0000000..b4c9252
--- /dev/null
+++ b/packages/compare/test/index.js
@@ -0,0 +1,12 @@
+import compare from '../src';
+
+it('Should compare strings naturally', () => {
+  expect(compare('', '')).toBe(0);
+  expect(compare('A', 'a')).toBe(1);
+  expect(compare('A', 'b')).toBe(1);
+  expect(compare('A woman', 'a woman')).toBe(1);
+  expect(compare('b', 'B')).toBe(-1);
+  expect(compare('C', 'b')).toBe(-1);
+  expect(compare('Qux20', 'Qux5')).toBe(-1);
+  expect(compare('Qux10', 'Qux11')).toBe(1);
+});
diff --git a/packages/endsWith/test/ends-with.test.js b/packages/endsWith/test/ends-with.test.js
new file mode 100644
index 0000000..4e3baaf
--- /dev/null
+++ b/packages/endsWith/test/ends-with.test.js
@@ -0,0 +1,29 @@
+import endsWith from '../src';
+
+describe('@plexis/ends-with', () => {
+  const baseString = 'A normal string';
+
+  it('receives strings as pattern', () => {
+    expect(endsWith(baseString, 'string')).toBe(true);
+    expect(endsWith(baseString, 'normal')).toBe(false);
+  });
+
+  it('receives regex as pattern', () => {
+    expect(endsWith(baseString, /strr*[r|i]ng/)).toBe(true);
+    expect(endsWith(baseString, /normal\/\s/m)).toBe(false);
+  });
+
+  it('takes starting position into consideration for string', () => {
+    expect(endsWith(baseString, 'normal', 'A normal'.length)).toBe(true);
+    expect(endsWith(baseString, 'string', 'A normal'.length)).toBe(false);
+  });
+
+  it('takes starting position into consideration for regex', () => {
+    expect(endsWith(baseString, /n.rmal/, 'A normal'.length)).toBe(true);
+    expect(endsWith(baseString, /string/, 'A normal'.length)).toBe(false);
+  });
+
+  it('is false for non-string and non-regex patterns', () => {
+    expect(endsWith(baseString, false)).toBe(false);
+  });
+});
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
new file mode 100644
index 0000000..88b4729
--- /dev/null
+++ b/packages/includes/test/includes.test.js
@@ -0,0 +1,33 @@
+'use strict';
+
+import includes from '../src';
+
+describe('@plexis/isNumeric', () => {
+  it('no first or second string parameter given', () => {
+    expect(includes()).toBe(false);
+  });
+
+  it('no second parameter given', () => {
+    expect(includes('')).toBe(false);
+  });
+
+  it('empty string given for first and second string parameters', () => {
+    expect(includes('', '')).toBe(true);
+  });
+
+  it('Equal first string and second string parameters', () => {
+    expect(includes('Foo', 'Foo')).toBe(true);
+  });
+
+  it('Equal first string and second string with starting position of 2', () => {
+    expect(includes('Foo', 'Foo', 2)).toBe(false);
+  });
+
+  it('Second parameter as substring of first parameter', () => {
+    expect(includes('Foo', 'oo')).toBe(true);
+  });
+
+  it('Second parameter as substring of first parameter, but substring has different casing', () => {
+    expect(includes('Foo', 'Oo')).toBe(false);
+  });
+});
diff --git a/packages/plexis/test/__snapshots__/index.js.snap b/packages/plexis/test/__snapshots__/index.js.snap
index 6239750..dc1e65d 100644
--- a/packages/plexis/test/__snapshots__/index.js.snap
+++ b/packages/plexis/test/__snapshots__/index.js.snap
@@ -3,17 +3,26 @@
 exports[`allows using all the available utilities 1`] = `
 Array [
   "__esModule",
+  "compare",
+  "compareLikeHuman",
+  "naturalCompare",
   "compose",
   "_do",
   "calcLevenshtein",
   "distance",
   "levenshtein",
+  "endsWith",
   "escapeHTML",
+  "head",
+  "first",
+  "popFirst",
   "isAlpha",
   "isLower",
   "isLowerCase",
   "isNum",
   "isNumeric",
+  "includes",
+  "has",
   "isString",
   "isUpper",
   "isUpperCase",
@@ -21,6 +30,9 @@ Array [
   "camelCase",
   "camelize",
   "toCamelCase",
+  "toCapitals",
+  "toFirstCapital",
+  "capitalize",
   "toChicagoManualStyle",
   "toChicagoStyle",
   "toChicagoTitle",
@@ -53,5 +65,11 @@ Array [
   "isAlphaNumeric",
   "isAlphanumeric",
   "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');
+  });
+});
diff --git a/packages/withoutHTML/test/index.js b/packages/withoutHTML/test/index.js
new file mode 100644
index 0000000..41f8e3d
--- /dev/null
+++ b/packages/withoutHTML/test/index.js
@@ -0,0 +1,11 @@
+import withoutHTML from '../src';
+
+it('Remove HTML tags from the input text', () => {
+  expect(withoutHTML('Hello world')).toBe('Hello world');
+  expect(withoutHTML('<p>Hello</p> world')).toBe(' world');
+  expect(withoutHTML('<p Hello world')).toBe('<p Hello world');
+  expect(withoutHTML('<p id="">Hello world</p>')).toBe('');
+  expect(withoutHTML('<p id="" Hello world</p> <b></b> from the underground')).toBe(
+    ' from the underground'
+  );
+});