Rambda
Faster alternative to Ramda
in just 10kB - Documentation
Argumentation
I admire Ramda
, as it is great library in what it does. My main problem was its size. Even custom builds didn't deliver satisfactory results. Also I already had Ramda
habits and I didn't want to switch to Lodash
.
Then I realized that my best solution was to publish a library that recreates the functionality of some Ramda
methods with less code.
Example use
const R = require("rambda")
const result = R.compose(
R.join("-"),
R.filter(a => a > 2),
R.flatten,
)([ [1], [2], [3], 4])
console.log(result) // => "3-4"
Install
https://cdnjs.cloudflare.com/ajax/libs/rambda/0.8.0/webVersion.js
Differences between Rambda and Ramda
Rambda shadows only small part of the Ramda's API.
A few things to note:
-
Rambda's methods should be compatible with most of the basic Ramda's methods.
For more complex and Ramda specific methods(such as R.__), you should expect a mismatch.
-
Rambda's type detect async functions. The returned value is "Async"
-
Rambda's type detect unresolved Promises
. The returned value is "Promise"
-
Rambda's map/filter work only for arrays, while Ramda's map/filter accept also objects.
-
Rambda's equals doesn't protect against circular structures as Ramda.equals does.
-
Rambda's path, pick and omit accepts both string and array as condition argument.
-
Rambda's partialCurry and includes are not part of Ramda API.
-
Rambda is tested for compatability with Ramda.flip, as this method could be useful in some cases.
If you need more Ramda methods in Rambda, you may either submit a PR
or check the extended version of Rambda - Rambdax
API
add
add(a: Number, b: Number): Number
R.add(2, 3)
addIndex
addIndex(fn: Function): Function
const mapWithIndex = R.addIndex(R.map)
mapWithIndex(
(val, index) => `${val} - ${index}`,
["A", "B", "C"]
)
adjust
adjust(replaceFn: Function, i:Number, arr:Array): Array
- Replaces
i
index in arr
with the result of replaceFn(arr[i])
R.adjust(a => a + 1, 0, [0, 100])
any
any(condition: Function, arr: Array): Boolean
- Returns true if at least one member of
arr
returns true, when passed to the condition
function
R.any(a => a * a > 8)([1, 2, 3])
R.any(a => a * a > 10)([1, 2, 3])
append
append(valueToAppend: any, arr: Array): Array
R.append('foo', ['bar', 'baz'])
compose
compose(fn1: Function, ... , fnN: Function): any
Performs right-to-left function composition
const result = R.compose(
R.map(a => a*2)
R.filter(val => val>2),
)([1, 2, 3, 4])
console.log(result) // => [6, 8]
contains
contains(valueToFind: any, arr: Array): Boolean
Returns true if valueToFind
is part of arr
R.contains(2, [1, 2])
R.contains(3, [1, 2])
curry
curry(fn: Function): Function
Returns curried version of fn
const addFourNumbers = (a, b, c, d) => a + b + c + d
const curriedAddFourNumbers = R.curry(addFourNumbers)
const f = curriedAddFourNumbers(1, 2)
const g = f(3)
g(4)
defaultTo
defaultTo(defaultArgument: T, inputArgument: any): T
Returns defaultArgument
if inputArgument
is undefined
or the type of inputArgument
is different of the type of defaultArgument
.
Returns inputArgument
in any other case.
R.defaultTo('foo', undefined)
R.defaultTo('foo')('bar')
R.defaultTo('foo')(1)
drop
drop(howManyToDrop: Number, arrOrStr: Array|String): Array|String
Returns arrOrStr
with howManyToDrop
items dropped from the left
R.drop(1, ['foo', 'bar', 'baz'])
R.drop(1, 'foo')
dropLast
dropLast(howManyToDrop: Number, arrOrStr: Array|String): Array|String
Returns arrOrStr
with howManyToDrop
items dropped from the right
R.dropLast(1, ['foo', 'bar', 'baz'])
R.dropLast(1, 'foo')
equals
equals(a: any, b: any): Boolean
- Returns equality match between
a
and b
Doesn't handles cyclical data structures
R.equals(1, 1)
R.equals({}, {})
R.equals([1, 2, 3], [1, 2, 3])
filter
filter(filterFn: Function, arr: Array): Array
Filters arr
throw boolean returning filterFn
const filterFn = a => a % 2 === 0
R.filter(filterFn, [1, 2, 3, 4])
find
find(findFn: Function, arr: Array): T|undefined
Returns undefined
or the first element of arr
satisfying findFn
const findFn = a => R.type(a.foo) === "Number"
const arr = [{foo: "bar"}, {foo: 1}]
R.find(findFn, arr)
findIndex
findIndex(findFn: Function, arr: Array): Number
Returns -1
or the index of the first element of arr
satisfying findFn
const findFn = a => R.type(a.foo) === "Number"
const arr = [{foo: "bar"}, {foo: 1}]
R.find(findFn, arr)
flatten
flatten(arr: Array): Array
R.flatten([ 1, [ 2, [ 3 ] ] ]
has
has(prop: String, obj: Object): Boolean
- Returns
true
if obj
has property prop
R.has("a", {a: 1})
R.has("b", {a: 1})
head
head(arrOrStr: Array|String): any
- Returns the first element of
arrOrStr
R.head([1, 2, 3])
R.head('foo')
ifElse
ifElse(condition: Function, ifFn: Function, elseFn: Function): Function
It returns a function that, which input
argument is passed to condition
function returns answer
.
If answer
is true
, then input
is applied to ifFn
function.
If answer
is false
, then input
is applied to elseFn
function.
const fn = R.ifElse(
x => x > 10,
x => x*2,
x => x*10
)
fn(8) // => 80
fn(11) // => 22
indexOf
indexOf(valueToFind: any, arr: Array): Number
Returns -1
or the index of the first element of arr
equal of valueToFind
R.indexOf(1, [1, 2])
init
init(arrOrStr: Array|String): Array|String
- Returns all but the last element of
arrOrStr
R.init([1, 2, 3])
R.init('foo')
join
join(separator: String, arr: Array): String
R.join('-', [1, 2, 3])
last
last(arrOrStr: Array|String): any
- Returns the last element of
arrOrStr
R.last(['foo', 'bar', 'baz'])
R.last('foo')
length
length(arrOrStr: Array|String): Number
R.length([1, 2, 3])
map
map(mapFn: Function, arr: Array): Array
Returns the result of looping through arr
with mapFn
const mapFn = x => x * 2;
R.map(mapFn, [1, 2, 3])
match
match(regExpression: Regex, str: String): Array
R.match(/([a-z]a)/g, 'bananas')
merge
merge(a: Object, b: Object)
Returns result of Object.assign({}, a, b)
R.merge({ 'foo': 0, 'bar': 1 }, { 'foo': 7 })
omit
omit(propsToOmit: Array, obj: Object): Object
- Returns a partial copy of an
obj
with omitting propsToOmit
R.omit(['a', 'd'], {a: 1, b: 2, c: 3})
path
path(pathToSearch: Array|String, obj: Object): any
- Retrieve the value at
pathToSearch
in object obj
R.path('a.b', {a: {b: 2}})
R.path(['a', 'b'], {a: {b: 2}})
R.path(['a', 'c'], {a: {b: 2}})
partialCurry
partialCurry(fn: Function|Async, a: Object, b: Object): Function|Promise
When called with function fn
and first set of input a
, it will return a function.
This function will wait to be called with second set of input b
and it will invoke fn
with the merged object of a
over b
.
fn
can be asynchronous function. In that case a Promise
holding the result of fn
is returned.
See the example below:
const fn = ({a, b, c}) => {
return (a * b) + c
}
const curried = R.partialCurry(fn, {a: 2})
curried({b: 3, c: 10})
pick
pick(propsToPick: Array, obj: Object): Object
- Returns a partial copy of an
obj
containing only propsToPick
properties
R.pick(['a', 'c'], {a: 1, b: 2}) //=> {a: 1}
pluck
pluck(property: String, arr: Array): Array
- Returns list of the values of
property
taken from the objects in array of objects arr
R.pluck('a')([{a: 1}, {a: 2}, {b: 3}]) //=> [1, 2]
prepend
prepend(valueToPrepend: any, arr: Array): Array
R.prepend('foo', ['bar', 'baz'])
prop
prop(propToFind: String, obj: Object): any
Returns undefined
or the value of property propToFind
in obj
R.prop('x', {x: 100})
R.prop('x', {a: 1})
propEq
propEq(propToFind: String, valueToMatch: any, obj: Object): Boolean
Returns true if obj
has property propToFind
and its value is equal to valueToMatch
const propToFind = "foo"
const valueToMatch = 0
R.propEq(propToFind, valueToMatch)({foo: 0})
R.propEq(propToFind, valueToMatch)({foo: 1})
range
range(start: Number, end: Number): Array
- Returns a array of numbers from
start
(inclusive) to end
(exclusive)
R.range(0, 2)
reduce
reduce(iteratorFn: Function, accumulator: any, array: Array): any
- Returns a single item by iterating through the list, successively calling the iterator function
iteratorFn
and passing it an accumulator
value and the current value from the array, and then passing the result to the next call.
The iterator function behaves like the native callback of the Array.prototype.reduce
method.
const iteratorFn = (acc, val) => acc + val
R.reduce(iteratorFn, 1, [1, 2, 3])
repeat
repeat(valueToRepeat: T, num: Number): Array
R.repeat('foo', 2)
replace
replace(strOrRegex: String|Regex, replacer: String, str: String): String
Replace strOrRegex
found in str
with replacer
R.replace('foo', 'bar', 'foo foo')
R.replace(/foo/, 'bar', 'foo foo')
R.replace(/foo/g, 'bar', 'foo foo')
sort
sort(sortFn: Function, arr: Array): Array
Returns copy of arr
sorted by sortFn
sortFn
must return Number
const sortFn = (a, b) => a - b
R.sort(sortFn, [3, 1, 2])
sortBy
sortBy(sortFn: Function, arr: Array): Array
Returns copy of arr
sorted by sortFn
sortFn
must return value for comparison
const sortFn = obj => obj.foo
R.sortBy(sortFn, [
{foo: 1},
{foo: 0}
])
split
split(separator: String, str: String): Array
R.split('-', 'a-b-c')
splitEvery
splitEvery(sliceLength: Number, arrOrString: Array|String): Array
- Splits
arrOrStr
into slices of sliceLength
R.splitEvery(2, [1, 2, 3])
R.splitEvery(3, 'foobar')
subtract
subtract(a: Number, b: Number): Number
Returns a
minus b
R.subtract(3, 1)
tail
tail(arrOrStr: Array|String): Array|String
- Returns all but the first element of
arrOrStr
R.tail([1, 2, 3])
R.tail('foo')
take
take(num: Number, arrOrStr: Array|String): Array|String
- Returns the first
num
elements of arrOrStr
R.take(1, ['foo', 'bar'])
R.take(2, ['foo'])
takeLast
takeLast(num: Number, arrOrStr: Array|String): Array|String
- Returns the last
num
elements of arrOrStr
R.takeLast(1, ['foo', 'bar'])
R.takeLast(2, ['foo'])
test
test(regExpression: Regex, str: String): Boolean
- Determines whether
str
matches regExpression
R.test(/^f/, 'foo')
R.test(/^f/, 'bar')
toLower
toLower(str: String): String
R.toLower('FOO')
toUpper
toUpper(str: String): String
R.toUpper('foo')
trim
trim(str: String): String
R.trim(' foo ')
type
type(a: any): String
R.type(() => {})
R.type(async () => {})
R.type([])
R.type({})
R.type('foo')
R.type(1)
R.type(true)
R.type(null)
R.type(/[A-z]/)
const delay = ms => new Promise(resolve => {
setTimeout(function () {
resolve()
}, ms)
})
R.type(delay)
uniq
uniq(arr: Array): Array
- Returns a new array containing only one copy of each element in
arr
R.uniq([1, 1, 2, 1])
R.uniq([1, '1'])
update
update(i: Number, replaceValue: any, arr: Array): Array
- Returns a new copy of the
arr
with the element at i
index
replaced with replaceValue
R.update(0, "foo", ['bar', 'baz'])
values
values(obj: Object): Array
- Returns array with of all values in
obj
R.values({a: 1, b: 2})
Benchmark
Flowtype
I haven't tested it fully, but the partial test shows that Ramda
definitions can be used.
You need to replace declare module ramda
with declare module rambda
on line 10 and store the file as rambda.js
in your flow-typed folder
Changelog
- 0.8.1 Add
R.ifElse
- 0.8.0 Add
R.not
, R.includes
| Take string as condition for R.pick
and R.omit
- 0.7.6 Fix incorrect implementation of
R.values
- 0.7.5 Fix incorrect implementation of
R.omit
- 0.7.4 issue #13 - Fix
R.curry
, which used to return incorrectly function
when called with more arguments - 0.7.3 Close issue #9 - Compile to
es2015
; Approve PR #10 - add R.addIndex
to the API - 0.7.2 Add
Promise
support for R.type
- 0.7.1 Close issue #7 - add
R.reduce
to the API - 0.7.0 Close issue #5 - change name of
curry
to partialCurry
; add new method curry
, which works just like Ramda's curry
- 0.6.2 Add separate documentation site via
docsify
Contribution guidelines
If you want to add another Ramda
method to the API, please feel free to submit a PR
.
The only requirement is the new method to have exact or very close implementation compared to the corresponding Ramda
method.
I give you example steps of the PR
process.
Create a method file in modules
folder.
If the new method is R.endsWith
, then the created file will be ./modules/endsWith.js
Write the function declaration and function's logic.
function endsWith(x, arrOrStr){
return arrOrStr.endsWith(x)
}
Any method, which takes more than one argument, should be curried.
We can use the standard curring used throughout Rambda
.
function endsWith(x, arrOrStr){
if(arrOrStr === undefined){
return arrOrStrHolder => endsWith(x, arrOrStrHolder)
}
return arrOrStr.endsWith(x)
}
module.exports = endsWith
Or we can also use R.curry
, but it is not as performant as the example above.
const curry = require('./curry')
function endsWith(x, arrOrStr){
if(arrOrStr === undefined){
return holder => endsWith(x, arrOrStr)
}
return arrOrStr.endsWith(x)
}
module.exports = curry(endsWith)
Edit rambda.js
file
Exported methods are sorted alphabetically
exports.dropLast = require("./modules/dropLast")
exports.endsWith = require("./modules/endsWith")
exports.equals = require("./modules/equals")
Write your test cases
Create file endsWith.js
in folder __tests__
const R = require('../rambda')
test('endsWith', () => {
expect(R.endsWith('oo')('foo')).toBeTruthy()
})
Run npm test
to validate your tests
Edit ./README.md
to add documentation
Note that your documentation should match the pattern visible across ./README.md
Lint your files
npm run lint modules/endsWith.js
npm run lint __tests__/endsWith.js
Submit PR
Expect response within 2 days.
Additional info
Projects using Rambda
Articles about Rambda