{"id":15286890,"url":"https://github.com/h2non/hu","last_synced_at":"2025-04-13T03:57:08.327Z","repository":{"id":14139418,"uuid":"16845002","full_name":"h2non/hu","owner":"h2non","description":"Small, generic functional helper library for node.js and browsers","archived":false,"fork":false,"pushed_at":"2020-02-27T09:31:25.000Z","size":159,"stargazers_count":21,"open_issues_count":23,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-02T07:04:02.994Z","etag":null,"topics":["clojure","clojurescript","curry","functional-programming","javascript","memoize","wisp"],"latest_commit_sha":null,"homepage":"","language":"wisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/h2non.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-02-14T17:57:04.000Z","updated_at":"2024-12-21T01:39:15.000Z","dependencies_parsed_at":"2022-08-26T17:42:13.037Z","dependency_job_id":null,"html_url":"https://github.com/h2non/hu","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fhu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fhu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fhu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fhu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/h2non","download_url":"https://codeload.github.com/h2non/hu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248657795,"owners_count":21140841,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","clojurescript","curry","functional-programming","javascript","memoize","wisp"],"created_at":"2024-09-30T15:18:52.513Z","updated_at":"2025-04-13T03:57:08.299Z","avatar_url":"https://github.com/h2non.png","language":"wisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hu [![Build Status](https://secure.travis-ci.org/h2non/hu.png?branch=master)][travis] [![NPM version](https://badge.fury.io/js/hu.png)][npm] ![Total Downloads](https://img.shields.io/npm/dt/hu.svg)\n\n**hu** is a functional-oriented generic utility helper library inspired by Haskell's prelude and Lodash/Underscore/Ramda.\n\nUnlike other well-known libraries, hu only provides a reduced but very common set of useful functions.\nIt aims to be a lightweight and small library which can be easily embedded as a part of an application, library or framework without making noise.\n\nhu library works well in ES5 compliant engine. Most of its functions are implicitly curried.\n\n## Features\n\n- Complete and reliable type checking helpers\n- Collection and object iterators\n- Array and objects processors and transformers helpers\n- Functional composition and async (curry, partial, compose, memoize, defer...)\n- String manipulation helpers\n- Equality comparison functions, including deep comparison\n- Runs in node.js and browsers\n- Well tested with 100% of coverage\n- Small (~800 SLOC)\n- Dependency free\n\n## Installation\n\n#### Node.js\n\n```bash\n$ npm install hu --save\n```\n\n#### Browser\n\nVia [Bower](http://bower.io)\n```bash\n$ bower install hu\n```\n\nVia [Component](http://component.io)\n```bash\n$ component install h2non/hu\n```\n\nOr load the script remotely (just for testing or development)\n```html\n\u003cscript src=\"//cdn.rawgit.com/h2non/hu/0.1.2/hu.js\"\u003e\u003c/script\u003e\n```\n\n## Browsers Support\n\n![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png)\n--- | --- | --- | --- | --- |\n+5 | +3.5 | +9 | +10.6 | +5 |\n\n## Why hu?\n\n### Motivation\n\nFunctional programming tendency has grown (again) in the last years.\nThis paradigm, unlike others that may be more totalitarian and extended, forces a radical re-thinking in the way that programmers design and implement software.\n\nFunctional programming thinking and conversion is not always easy to apply,\nbut it's really a quite attractive and funny paradigm which could helps a lot when solving certaing kind of problems in a more theoretically\nand conceptually clean way, and tipically more efficiently.\n\n### Rationale\n\nA good approach to learn and apply functional programming principles\nis creating a functional-oriented library that assists by itself to\ndo functional programming\n\nIn fact, hu was created to define a real scenario to do funny experiments\nwith some pure functional programming principles\n\nIt's completely written in [Wisp][wisp], a homoiconic Clojure-like language, which compiles into plain JavaScript that supports s-expressions and macros, allowing to extend the compiler features with the user’s own code\n\n### So... why JavaScript?\n\nJavaScript is an ubiquitous, well-extended, multi-purpose and multi-paradigm cool language with which you can do a lot of funny things\n\nYes, I know, JavaScript is not a pure functional language, however\nits natural extensibility and meta-programming capabilities allows you to apply different\nparadigms to it and today there are a lot of languages that transpile into JavaScript that help providing a powerful syntax sugar and more features,\nlike in this case using Wisp.\n\n### Challenges\n\nhu is implemented keeping in mind the following “ambitious” functional focused goals:\n\n- Assume it's a first-class function only language\n- Pure functions as a norm\n- Immutability (when it's possible)\n- Avoid assignment, remove side-effects (when it's possible)\n- Tend to recursion instead of loops\n- Tend to high-order functions\n- Tend to functional composition\n- Tend to continuation-passing style\n- Exploit subroutines (like tail recursion call)\n- Exploit function memorization (currying, partial, caching...)\n- Macros are a great thing when used right¡, don't have fear.\n\n## API\n\n- Type checking\n  - [isBool](#isboolvalue)\n  - [isNumber](#isnumbervalue)\n  - [isFinite](#isfinitevalue)\n  - [isNaN](#isnanvalue)\n  - [isString](#isstringvalue)\n  - [isSymbol](#issymbolvalue)\n  - [isFunction](#isfunctionvalue)\n  - [isDate](#isdatevalue)\n  - [isRegExp](#isregexpvalue)\n  - [isArray](#isarrayvalue)\n  - [isObject](#isobjectvalue)\n  - [isPlainObject](#isplainobjectvalue)\n  - [isError](#iserrorvalue)\n  - [isElement](#iselementvalue)\n  - [isArgs](#isargsvalue)\n  - [isUndef](#isundefvalue)\n  - [isNull](#isnullvalue)\n  - [isEmpty](#isemptyvalue)\n  - [notEmpty](#notemptyvalue)\n  - [isMutable](#ismutablevalue)\n  - [isPrimitive](#isprimitivevalue)\n  - [isIterable](#isiterablevalue)\n- Strings\n  - [subs](#subsstr-start-end)\n  - [lines](#linesstr)\n  - [unlines](#unlinesarr)\n  - [words](#wordsstr)\n  - [unwords](#unwordsarr)\n  - [chars](#charsstr)\n  - [unchars](#uncharsarr)\n  - [char](#charnumber)\n  - [reverse](#reversestr)\n  - [repeat](#repeatnumber-str)\n  - [escape](#escapestr)\n- Numbers\n  - [odd](#oddnumber)\n  - [even](#evennumber)\n  - [lower](#lowerx-y)\n  - [higher](#higherx-y)\n  - [max](#maxnumbers)\n  - [min](#minnumbers)\n  - [inc](#incnumber)\n  - [dec](#decnumber)\n  - [signum](#signumnumber)\n  - [isNegative](#isnegativenumber)\n  - [negate](#negatenumber)\n  - [recip](#recipnumber)\n  - [div](#divnumber)\n  - [max](#maxnumbers-1)\n  - [min](#minnumbers-1)\n  - [abs](#absnumber)\n  - [round](#roundnumber)\n  - [random](#random)\n  - [floor](#floornumber)\n  - [sin](#sinnumber)\n  - [tan](#tannumber)\n  - [cos](#cosnumber)\n  - [asin](#asinnumber)\n  - [atan](#atannumber)\n  - [atan2](#atan2number)\n  - [ceil](#ceilnumber)\n  - [exp](#expnumber)\n  - [sqrt](#sqrtnumber)\n  - [PI](#pi)\n- Arrays\n  - [inArray](#inarrayarr-element)\n  - [head](#headarr)\n  - [tail](#tailarr)\n  - [last](#lastarr)\n  - [initial](#initialarr)\n  - [flatten](#flattenarr)\n- Objects\n  - [has](#hasobj-property)\n  - [keys](#keysobj)\n  - [vals](#valsobj)\n  - [keyValues](#keyvaluesobj)\n  - [toObject](#toobjectobj)\n  - [extend](#extendtarget-origins)\n  - [mixin](#mixintarget-origins)\n  - [map](#mapobj-function)\n  - [filter](#filterobj-function)\n  - [clone](#cloneobject)\n  - [merge](#mergex-y)\n- Collections\n  - [each](#eachobj-function)\n  - [size](#sizeobj)\n  - [compact](#compactobj)\n- Functions\n  - [constant](#constantvalue)\n  - [apply](#applyfn-args)\n  - [bind](#bindfn-ctx)\n  - [partial](#partialfn--partialargs-)\n  - [curry](#curryfn--ctx-)\n  - [compose](#composefn)\n  - [memoize](#memoizefn-resolver)\n  - [wrap](#wrapfn-wrapperfn--args-)\n  - [once](#oncefn)\n  - [throttle](#throttlefn)\n  - [times](#timesfn-number)\n  - [defer](#deferfn-ms--args-)\n  - [debounce](#debouncefn-ms--args-)\n- Equality\n  - [isEqual](#isequalx-y)\n  - [isPatternEqual](#ispatternequalx-y)\n  - [isDateEqual](#isdateequalx-y)\n  - [isArrayEqual](#isarrayequalx-y)\n  - [isObjectEqual](#isobjectequalx-y)\n- Miscellaneous\n  - [log](#logmsg)\n  - [isBrowser](#isbrowser)\n  - [noop](#noop)\n  - [now](#now)\n  - [_global](#_global)\n\n### Overview example\n\nJavaScript Harmony (ES6)\n```js\nvar { log, filter, even, inc } = require('hu')\n\nlog(map(filter({a: 1, b: 2}, even), inc))\n// → { b: 3 }\n```\n\nOr with the funny LiveScript\n```livescript\n(a: 1, b: 2)\n  |\u003e filter _, even\n  |\u003e map _, inc\n  |\u003e log\n```\n\n### Type checking\n\n#### isBool(value)\nReturn: `boolean` | Alias: `isBoolean`\n\nChecks if the given value is a boolean type\n\n#### isNumber(value)\nReturn: `boolean`\n\nChecks if the given value is a number type\n\n#### isFinite(value)\nReturn: `boolean`\n\nChecks if the given value is a finite number,\nor it can be coerced into it\n\n#### isNaN(value)\nReturn: `boolean`\n\nIs it NaN (not a number)?\nMore accurate than the native isNaN function\n\n#### isString(value)\nReturn: `boolean`\n\nChecks if the given value is a string type\n\n#### isSymbol(value)\nReturn: `boolean`\n\nChecks if the given value is a symbol type\n\n#### isFunction(value)\nReturn: `boolean` | Alias: `isFn`\n\nChecks if the given value is a function type\n\n#### isDate(value)\nReturn: `boolean`\n\nChecks if the given value is a date type\n\n#### isRegExp(value)\nReturn: `boolean` | Alias: `isPattern`\n\nChecks if the given value is a regexp type\n\n#### isArray(value)\nReturn: `boolean`\n\nChecks if the given value is an array type\n\n#### isObject(value)\nReturn: `boolean`\n\nChecks if the given value is an object type\n\n#### isPlainObject(value)\nReturn: `boolean`\n\nChecks if the given value is a native object type (it was createdd by the Object native constructor)\n\n#### isError(value)\nReturn: `boolean`\n\nChecks if the given value is an error type\n\n#### isElement(value)\nReturn: `boolean`\n\nChecks if the given value is a DOM element object instance\n\n#### isArgs(value)\nReturn: `boolean` | Alias: `isArguments`\n\nChecks if the given value is an arguments object\n\n#### isUndef(value)\nReturn: `boolean` | Alias: `isUndefined`\n\nChecks if the given value is a undefined, void o null type\n\n#### isNull(value)\nReturn: `boolean`\n\nChecks if the given value is a null type\n\n#### isEmpty(value)\nReturn: `boolean`\n\nChecks if the given value is empty.\nArrays, strings, or arguments objects with a length of 0 and objects with no own enumerable properties are considered empty values\n\n#### notEmpty(value)\nReturn: `boolean` | Alias: `isNotEmpty`\n\nChecks if the given value is not empty\n\n#### isMutable(value)\nReturn: `boolean`\n\nChecks if the given value is a mutable data type.\nObjects, arrays, date objects, arguments objects and functions are considered mutable data types\n\n#### isPrimitive(value)\nReturn: `boolean`\n\nChecks if the given value is a primitive value type.\nStrings, numbers, booleans, symbols and null are considered primitives values\n\n#### isIterable(value)\nReturn: `boolean` | Alias: `canIterate`\n\nChecks if the given value can be iterated.\nObjects, arrays, and arguments objects are considered iterables data types\n\n### Strings\n\n#### subs(str, start, end)\nReturn: `string`\n\nExtract characters from the given string\n\n#### lines(str)\nReturn: `array`\n\nSplit the given string by end of line tokens\n\n#### unlines(arr)\nReturn: `string`\n\nJoin the given array into a string separated by\nend line token\n\n#### words(str)\nReturn: `array`\n\nReturns an array of words (spaces separated)\n\n#### unwords(arr)\nReturn: `string`\n\nJoin words of the given array into a string spaces separated\n\n#### chars(str)\nReturn: `array`\n\nReturn an array of characters of the given string\n\n#### unchars(arr)\nReturn: `string`\n\nJoin the strings of the given array\n\n#### char(number)\nReturn: `string`\n\nReturn the given unicode number into his\nequivalent character\n\n#### reverse(str)\nReturn: `string`\n\nReverse characters of the given string\n\n#### repeat(number, str)\nReturn: `string`\n\nRepeat the given string\n\n#### escape(str)\nReturn: `string`\n\nConverts the characters \u0026, \u003c, \u003e, \", and ' in the given string\nto their corresponding HTML entities\n\n### Numbers\n\n#### odd(number)\nReturn: `boolean` | Alias: `isOdd`\n\nReturns `true` if the given number is odd\n\n#### even(number)\nReturn: `boolean` | Alias: `isEven`\n\nReturns `true` if the given number is even\n\n#### lower(x, y)\nReturn: `boolean` | Alias: `isLower` | Curried: `true`\n\nReturns `true` if x it's lower than y\n\n#### higher(x, y)\nReturn: `boolean` | Alias: `isHigher` | Curried: `true`\n\nReturns `true` if x it's lower than y\n\n#### max(...numbers)\nReturn: `number`\n\nReturns the number with the highest value\n\n#### min(...numbers)\nReturn: `number`\n\nReturns the number with the lower value\n\n#### inc(number)\nReturn: `number`\n\nIncrement the given value\n\n#### dec(number)\nReturn: `number`\n\nDecrement the given value\n\n#### signum(number)\nReturn: `number`\n\nTakes a number and returns either -1, 0,\nor 1 depending on the sign of the number\n\n#### isNegative(number)\nReturn: `boolean`\n\nReturns `true` if the given number is negative\n\n#### negate(number)\nReturn: `number`\n\nThe negation of the given number\n\n#### recip(number)\nReturn: `number`\n\nOne over the number: ie 1 / x\n\n#### div(number)\nReturn: `number`\n\nDivision truncated down toward negative infinity\n\n#### max(...numbers)\nReturn: `number`\n\nReturns the largest of zero or more numbers\n\n#### min(...numbers)\nReturn: `number`\n\nReturns the smallest of zero or more numbers\n\n#### abs(number)\nReturn: `number`\n\nReturns the absolute value of a number\n\n#### round(number)\nReturn: `number`\n\nReturns the value of a number rounded to the nearest integer\n\n#### random()\nReturn: `number`\n\nReturns a pseudo-random number between 0 and 1\n\n#### floor(number)\nReturn: `number`\n\nReturns the largest integer less than or equal to a number\n\n#### sin(number)\nReturn: `number`\n\nReturns the sine of a number\n\n#### tan(number)\nReturn: `number`\n\nReturns the tangent of a number\n\n#### cos(number)\nReturn: `number`\n\nReturns the cosine of a number\n\n#### asin(number)\nReturn: `number`\n\nReturns the arcsine of a number\n\n#### atan(number)\nReturn: `number`\n\nReturns the arctangent of a number\n\n#### atan2(number)\nReturn: `number`\n\nReturns the cosine of a number\n\n#### ceil(number)\nReturn: `number`\n\nReturns the smallest integer greater than or equal to a number\n\n#### exp(number)\nReturn: `number`\n\nReturns Ex, where x is the argument, and E is Euler's\nconstant (2.718...), the base of the natural logarithm\n\n#### sqrt(number)\nReturn: `number`\n\nReturns the positive square root of a number\n\n#### PI\nType: `number`\n\nRatio of the circumference of a circle to\nits diameter, approximately 3.14159\n\n### Arrays\n\n#### inArray(arr, element)\nReturn: `boolean` | Curried: `true`\n\nChecks if an element exists in the given array\n\n#### head(arr)\nReturn: `mixed` | Alias: `first`\n\nFirst item of the given array\n\n```js\nhu.head([1, 2, 3]) // → 1\n```\n\n#### tail(arr)\nReturn: `array` | Alias: `rest`\n\nEverything but the first item of the list\n\n```js\nhu.tail([1, 2, 3]) // → [2, 3]\n```\n\n#### last(arr)\nReturn: `mixed` | Alias: `end`\n\nThe last item of the list\n\n```js\nhu.last([1, 2, 3]) // → 3\n```\n\n#### initial(arr)\nReturn: `array`\n\nEverything but the last item of the list\n\n```js\nhu.initial([1, 2, 3]) // → [1, 2]\n```\n\n#### flatten(arr)\nReturn: `array`\n\nRecursively flatten elements of a multidimensional list into a one dimension list.\n\n```js\nhu.flatten([1, [2], [3, [4, [5]]]]) // → [1, 2, 3, 4, 5]\n```\n\n### Objects\n\n#### has(obj, property)\nReturn: `boolean`\n\nChecks if the specified property name exists as a\nown property of the given object\n\n```js\nhu.has({a: true}, 'a') // → true\n```\n\n#### keys(obj)\nReturn: `array`\n\nReturns a sequence of the map's keys\n\n```js\nhu.keys({a: true}) // → ['a']\n```\n\n#### vals(obj)\nReturn: `array`\n\nReturns a sequence of the map's values\n\n```js\nhu.vals({a: true}) // → [true]\n```\n\n#### keyValues(obj)\nReturn: `array` | Alias: `pairs`\n\nReturns a two dimensional array of an object’s key-value pairs\n\n```js\nhu.keyValues({a: true}) // → [['a', true]]\n```\n\n#### toObject(obj)\nReturn: `array`\n\nCreates an object of given arguments.\nOdd indexed arguments are used for keys and evens for values\n\n```js\nhu.toObject('a', true) // → {a: true}\n```\n\n#### extend(target, ...origins)\nReturn: `object` | Alias: `assign`\n\nAssigns own enumerable properties of source object(s) to the destination object\n\n```js\nhu.extend({x: true}, {y: false}) // → {x: true, y: false}\n```\n\n#### mixin(target, ...origins)\nReturn: `object`\n\nAdds function properties of a source object to the destination object\n\n```js\nvar methods = {\n  something: function () {\n    // cool stuff\n  }\n}\nhu.mixin({x: true}, methods)\n// → {x: true, something: function () {}}\n```\n\n#### map(obj, function)\nReturn: `object` | Alias: `mapValues` | Curried: `true`\n\nMaps object values by applying with the value return\nof each callback call on each one\n\n```js\nfunction mapper(val) {\n  return val * 2\n}\nhu.map({x: 2}, mapper) // → {x: 4}\n```\n\n#### filter(obj, function)\nReturn: `object` | Alias: `filterValues` | Curried: `true`\n\nIterates over properties of an object,\nreturning an filtered new object of all\nelements where the callback returns true\n\n```js\nfunction filter(val) {\n  return val \u003e 1\n}\nhu.map({x: 1, y: 2}, filter) // → {y: 2}\n```\n\n#### clone(object)\nReturn: `object`\n\nCreates a clone of the given object\n\n```js\nvar obj = {x: 1}\nvar newObj = hu.clone(obj)\nnewObj === obj // → false\n```\n\n#### merge(x, y)\nReturn: `object`\n\nSimilar to `extend`, it returns an object that consists\nof the rest of the maps conj-ed onto the first\n\nIf a key occurs in more than one map, the mapping from\nthe latter (left-to-right) will be the mapping in the result\n\n```js\nvar obj1 = {x: {y: {z: 2}}}\nvar obj2 = {x: {y: {a: 1}}}\nvar newObj = hu.merge(obj1, obj2)\n// → {x: {y: {z: 2, a: 1}}}\n```\n\n### Collections\n\n#### each(obj, function)\nReturn: `object` | Alias:  `forEach`\n\nIterates over elements of an iterable object,\nexecuting the callback for each element.\nIt will return the same given object\n\n```js\nhu.each([1, 2], function (n) {\n  console.log('Value:', n)\n})\n```\n\n#### size(obj)\nReturn: `number`\n\nGets the size of the given collection\n\n```js\nhu.size({x: 1, y: 2}) // → 2\n```\n\n#### compact(obj)\nReturn: `object|array` | Alias: `clean`\n\nReturns a new collection which\ncontains only the not empty values\n\n```js\nhu.compact([1, null, undefined, \"\", 5])\n// → [1, 5]\n```\n\n### Functions\n\n#### constant(value)\nReturn: `function` | Alias: `identity`\n\nReturns a function that returns the given value\n\n```js\nvar getter = hu.constant('john')\ngetter() === 'john' // → true\n```\n\n#### apply(fn, args)\nReturn: `mixed`\n\nInvokes a function binding itself function object context\nwith the given arguments as array\n\n```js\nfunction myFn(x, y) { return x * y }\nhu.apply(myFn, [2, 2]) // → 4\n```\n\n#### bind(fn, ctx)\nReturn: `function`\n\nCreates a function that, when called, invokes the function\nwith the this binding of thisArg and prepends any additional\nbind arguments to those provided to the bound function\n\n```js\nfunction func(greeting) {\n  return greeting + ' ' + this.name\n}\nfunc = hu.bind(func, { 'name': 'john' }, 'hi')\nfunc() // → 'hi john'\n```\n\n#### partial(fn, [ ...partialArgs ])\nReturn: `function`\n\nCreates a function that, when called, invokes\nfunc with any additional partial arguments\nprepended to those provided to the new function\n\n```js\nfunction greet(greeting, name) {\n  return greeting + ' ' + name;\n}\nvar hi = hu.partial(greet, 'hi');\nhi('john') // → 'hi john'\n```\n\n#### curry(fn, [ ctx ])\nReturn: `function`\n\nCreates a function which accepts one or more\narguments of the given function that when invoked either\nexecutes the function returning its result\n\n```js\nvar curried = hu.curry(function(a, b, c) {\n  console.log(a + b + c)\n})\ncurried(1)(2)(3) // → 6\ncurried(1, 2)(3) // → 6\ncurried(1, 2, 3) // → 6\n```\n\n#### compose(...fn)\nReturn: `function`\n\nCreates a function that is the composition of the provided functions, where each function consumes the return value of the function that follows\n\n```js\nfunction name(name) {\n  return name.toLowerCase() + '!'\n}\nfunction greet(name) {\n  return 'Hi ' + name\n}\nvar welcome = hu.compose(name, greet);\nwelcome('John') // → 'Hi john!'\n```\n\n#### memoize(fn, resolver)\nReturn: `function`\n\nCreates a function that memoizes the result\nof the the given function. If resolver is provided\nit will be used to determine the cache key for\nstoring the result based on the arguments provided\nto the memoized function.\nThe resolver function just uses the first argument\nto the memoized function as the key\n\n```js\nvar multiply = hu.memoize(function (n) {\n  return n * 2\n})\nmultiply(2) // → 4 (computed value)\nmultiply(2) // → 4 (memoized value)\n```\n\nWith custom resolver function to define memoized values\n```js\nvar multiply = hu.memoize(function (n) {\n  return n * 2\n}, function (n) {\n  return n === 2 ? n + 1 : n\n})\nmultiply(1) // → 2 (computed value)\nmultiply(2) // → 4 (computed value)\nmultiply(3) // → 4 (memoized value, from 2 value)\n```\n\n#### wrap(fn, wrapperFn, [ ...args ])\nReturn: `function` | Curried: `true`\n\nCreates a function that provides value to the wrapper\nfunction as its first argument. Additional arguments\nprovided to the function are appended to those provided\nto the wrapper function\n\n```js\nfunction hello(name) {\n  return \"hi \" + name;\n}\nhello = hu.wrap(hello, function (fn, text, type) {\n  return \"before, \" + fn(\"moe\") + \", \" + text + \": \" + type + \", after\"\n}, \"type\")\nhello(\"salutation\") // → 'before, hi moe, type: salutation, after'\n```\n\n#### once(fn)\nReturn: `function`\n\nCreates a function that is restricted to execute function\nonce time. Subsuquents calls to the function will return\nthe memoized value of the initial call\n\n```js\nvar times = 0\nvar init = hu.once(function () {\n  return times += 1\n})\ninit() // → 1\ninit() // → 1\n```\n\n#### throttle(fn)\nReturn: `function` | Curried: `true`\n\nCreates a function that, when executed, will only call the fn\nfunction at most once per every wait milliseconds\n\n```js\nvar test = hu.throttle(function () {\n  console.log(Date.now())\n}, 100)\ntest() // → first call\ntest() // → no call\nsetTimeout(test, 150) // → second call\n```\n\n#### times(fn, number)\nReturn: `function` | Curried: `true`\n\nCreates a function that is restricted to be executed\na finite number of times. Subsuquents calls to the\nfunction will return the memoized value of the latest call\n\n```js\nvar times = 0\nvar init = hu.times(function () {\n  return times += 1\n}, 2)\ninit(); // → 1\ninit(); // → 2\ninit(); // → 2\n```\n\n#### defer(fn, ms, [ ...args ])\nReturn: `void`\n\nExecutes the given function after wait milliseconds. You can provide arguments that will be passed to the function when it's invoked\n\n```js\nfunction delayed(text) {\n  console.log(text)\n}\nhu.defer(delayed, 1000, 'later')\n// → logs 'later' after one second\n```\n\n#### debounce(fn, ms, [ ...args ])\nReturn: `function`\n\nReturn a function that executes the given function after wait\nmilliseconds when it's called. You can provide arguments\nthat will be passed to the function when it will be invoked\n\n```js\nfunction delayed(text, name) {\n  console.log(text, name)\n}\nvar lazy = hu.debounce(delayed, 1000, 'later')\nlazy('call') // → logs 'later call' after one second\n```\n\n### Equality\n\n#### isEqual(x, y)\nReturn: `boolean` | Alias: `equal`, `deepEqual`, 'isDeepEqual'\n\nCompares primitives types and data objects in a type-independent manner.\nClojure's immutable data structures define -equiv (and thus =)\nas a value, not an identity, comparison.\n\n#### isPatternEqual(x, y)\nReturn: `boolean` | Alias: `isRegExpEqual`, `patternEqual` | Curried: `true`\n\nCheck if the given dates are equal\n\n#### isDateEqual(x, y)\nReturn: `boolean` | Alias: `dateEqual` | Curried: `true`\n\nCheck if the given dates are equal\n\n#### isArrayEqual(x, y)\nReturn: `boolean` | Alias: `arrayEqual` | Curried: `true`\n\nCheck if the given arrays has the same elements\n\n#### isObjectEqual(x, y)\nReturn: `boolean` | Alias: `objectEqual` | Curried: `true`\n\nChecks if the given objects values and keys are equals\n\n### Miscellaneous\n\n#### log(...msg)\nReturn: `undefined`\n\nWrite the given arguments in the console\n\n#### isBrowser\nType: `boolean`\n\nChecks if the current runtime JavaScript environment is in a browser context\n\n#### noop()\nReturn: `void`\n\nThe no-operation function, that returns `void`\n\n#### now()\nReturn: `number`\n\nReturns an integer timestamp for the current time\n\n#### _global()\nReturn: `object`\n\nEnvironment specific global object\n\n## Contributing\n\nWanna help? Cool! It will be really apreciated :)\n\nYou must add new test cases for any new feature or refactor you do,\nalways following the same design/code patterns that already exist\n\nTests specs are completely written in Wisp language.\nTake a look to the language [documentation][wisp] if you are new with it.\nYou should follow the Wisp language coding conventions\n\n### Development\n\nOnly [node.js](http://nodejs.org) is required for development\n\nClone/fork this repository\n```\n$ git clone https://github.com/h2non/hu.git \u0026\u0026 cd hu\n```\n\nInstall package dependencies\n```\n$ npm install\n```\n\nCompile code\n```\n$ make compile\n```\n\nRun tests\n```\n$ make test\n```\n\nBrowser sources bundle generation\n```\n$ make browser\n```\n\nRelease a new version\n```\n$ make release\n```\n\n## License\n\nCopyright (c) Tomas Aparicio\n\nReleased under the MIT license\n\n[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/h2non/hu.js/trend.png)](https://bitdeli.com/free \"Bitdeli Badge\")\n\n[wisp]: https://github.com/Gozala/wisp\n[travis]: http://travis-ci.org/h2non/hu\n[npm]: http://npmjs.org/package/hu\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh2non%2Fhu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fh2non%2Fhu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh2non%2Fhu/lists"}