JSPM

  • Created
  • Published
  • Downloads 2440056
  • Score
    100M100P100Q195836F
  • License MIT

Lightweight alternative to Ramda

Package Exports

  • rambda
  • rambda/modules/prop

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (rambda) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Build Status codecov dependencies Status

Rambda

Faster alternative to Ramda in just 10kB - Documentation

Rambda's advantages

  1. Tree-shaking

Currenly Rambda is more tree-shakable than Ramda as you can see in this tree-shaking example.

  1. Speed

Rambda is generally more performant than Ramda as the benchmarks can prove that.

You can clone this repo and run yarn run benchmark all to see for yourself.

  1. Minor helpers

For example with Rambda you can call R.path('a.b', {a: {b: 1}}) instead of R.path(['a','b'], {a: {b: 1}})

In Rambda you can use both types of expression.

This is not a major change, but some developers would prefer to use 'a.b.c' over ['a', 'b', 'c'].

Same logic is applied to R.omit method.

R.pick is similar, but the separator is , not .


Initial 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.

Rambda partially shadows Ramda's API, so you need to check in Rambda's documentation, if the methods you need are available.

Generally speaking, if you have never used methods such as R.transduce, Rambda API should be enough for your needs.

Example use

const R = require('rambda')
const result = R.compose(
  R.filter( R.equals( 2 ) ),
  R.map( R.add( 1 ) )
)({ a: 1, b: 2, c: 3 })
console.log(result) // => '{a: 2}'

Install

  • Use yarn add rambda for Webpack and Node.js usage

  • For UMD usage either use ./dist/rambda.umd.js or the CDN link at

https://cdnjs.cloudflare.com/ajax/libs/rambda/1.0.0/webVersion.js

Differences between Rambda and Ramda

  • Rambda's type detect async functions and unresolved Promises. The returned values are 'Async' and 'Promise'.

  • 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('x.y.z' == ['x','y','z']).

  • Rambda's flip works only for functions expecting two arguments.

  • Rambda's partialCurry and includes are not part of Ramda API.

  • Rambda's startsWith/endsWith work only with strings, instead with array and strings.

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) // =>  5

Source

addIndex

addIndex(fn: Function): Function

const mapWithIndex = R.addIndex(R.map)
mapWithIndex(
  (val, index) => `${val} - ${index}`,
  ['A', 'B', 'C']
) // => ['A - 0', 'B - 1', 'C - 2']

Source

adjust

adjust(replaceFn: Function, i:Number, arr:Array): Array

It replaces i index in arr with the result of replaceFn(arr[i]).

R.adjust(a => a + 1, 0, [0, 100]) // => [1, 100]

Source

all

all(fn: Function, arr: Array): Boolean

It returns true if all members of array arr returns true, when applied as argument to function fn.

const arr = [ 0, 1, 2, 3, 4 ]
const fn = x => x > -1
R.all(fn, arr) // => true

Source

allPass

allPass(rules: Array, input: any): Boolean

It returns true if all functions of rules return true, when input is their argument.

const input = {
  a : 1,
  b : 2,
}
const rules = [
  x => x.a === 1,
  x => x.b === 2,
]
R.allPass(rules, obj) // => true

Source

always

always(x: any): Function

It returns function that always returns x.

const fn = R.always(7)

fn()// => 7
fn()// => 7

Source

any

any(condition: Function, arr: Array): Boolean

It 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]) // => true
R.any(a => a * a > 10)([1, 2, 3]) // => false

Source

append

append(valueToAppend: any, arr: Array): Array

R.append('foo', ['bar', 'baz']) // => ['foo', 'bar', 'baz']

Source

both

both(x: Function, y: Function, input: any): Boolean

It returns true if both function x and function y return true, when input is their argument.

const fn = R.both(
  a => a > 10,
  a => a < 20
)
fn(15) //=> true
fn(30) //=> false

Source

compose

compose(fn1: Function, ... , fnN: Function): any

It performs right-to-left function composition.

const result = R.compose(
  R.map(x => x * 2)
  R.filter(x => x > 2),
)([1, 2, 3, 4])
console.log(result) // => [6, 8]

Source

complement

complement(fn: Function): Function

It returns complemented function that accept input as argument.

The return value of complemented is the negative boolean value of fn(input).

R.complement(R.always(0)) // => true
R.complement(R.always(true)) // => false

Source

concat

concat(x: array|string, y: array|string): array|string

It returns a new string or array, which is the result of merging x and y.

R.concat([1, 2])([3, 4]) // => [1, 2, 3, 4]
R.concat('foo', 'bar') // => 'foobar'

contains

contains(valueToFind: any, arr: Array): Boolean

It returns true if valueToFind is part of arr.

R.contains(2, [1, 2]) // => true
R.contains(3, [1, 2]) // => false

Source

curry

curry(fn: Function): Function

It 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) // => 10

Source

dec

dec(x: number): number

It decrements a number.

R.dec(2) // => 1

defaultTo

defaultTo(defaultValue: T, inputArgument: any): T

It returns defaultValue, if inputArgument is undefined, null or NaN.

It returns inputArgument in any other case.

R.defaultTo('foo', undefined) // => 'foo'
R.defaultTo('foo', 'bar') // => 'bar'
R.defaultTo('foo', 1) // => 1

Source

divide

R.divide(71, 100) // => 0.71

drop

drop(howManyToDrop: Number, arrOrStr: Array|String): Array|String

It returns arrOrStr with howManyToDrop items dropped from the left.

R.drop(1, ['foo', 'bar', 'baz']) // => ['bar', 'baz']
R.drop(1, 'foo')  // => 'oo'

Source

dropLast

dropLast(howManyToDrop: Number, arrOrStr: Array|String): Array|String

It returns arrOrStr with howManyToDrop items dropped from the right.

R.dropLast(1, ['foo', 'bar', 'baz']) // => ['foo', 'bar']
R.dropLast(1, 'foo')  // => 'fo'

endsWith

endsWith(x: String, str: String): Boolean

R.endsWith(
  'bar',
  'foo-bar'
) // => true

R.endsWith(
  'foo',
  "foo-bar"
) // => false

either

const fn = R.either(
  a => a > 10,
  a => a % 2 === 0
)
fn(15) //=> true
fn(6) //=> true
fn(7) //=> false

equals

equals(a: any, b: any): Boolean

It returns equality match between a and b.

It doesn't handle cyclical data structures.

R.equals(1, 1) // => true
R.equals({}, {}) // => false
R.equals([1, 2, 3], [1, 2, 3]) // => true

F

R.F() // => false

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]) // => [2, 4]

find

find(findFn: Function, arr: Array): T|undefined

It 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) // => {foo: 1}

findIndex

findIndex(findFn: Function, arr: Array): Number

It 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) // => 1

flatten

flatten(arr: Array): Array

R.flatten([ 1, [ 2, [ 3 ] ] ])
// => [ 1, 2, 3 ]

flip

flip(fn: Function): Function

It returns function which calls fn with exchanged first and second argument.

const subtractFlip = R.flip(R.subtract)
R.subtractFlip(1,7)
// => 6

forEach

forEach(fn: Function, arr: Array): Array

It applies function fn over all members of array arr and returns arr.

const sideEffect = {}
const result = R.forEach(
  x => sideEffect[`foo${x}`] = x
)([1, 2])

console.log(sideEffect) //=> {foo1 : 1, foo2 : 2}
console.log(result) //=> [1, 2]

Note, that unlike Ramda's forEach, Rambda's one doesn't dispatch to forEach method of arr.

has

has(prop: String, obj: Object): Boolean

  • It returns true if obj has property prop.
R.has("a", {a: 1}) // => true
R.has("b", {a: 1}) // => false

head(arrOrStr: Array|String): any

It returns the first element of arrOrStr.

R.head([1, 2, 3]) // => 1
R.head('foo') // => 'f'

identity

identity(x: T): T

It just passes back the supplied arguments.

R.identity(7) // => 7

ifElse

ifElse(condition: Function|boolean, ifFn: Function, elseFn: Function): Function

It returns function, which expect input as argument and returns finalResult.

When this function is called, a value answer is generated as a result of condition(input).

If answer is true, then finalResult is equal to ifFn(input). If answer is false, then finalResult is equal to elseFn(input).

const fn = R.ifElse(
 x => x > 10,
 x => x*2,
 x => x*10
)
fn(8) // => 80
fn(11) // => 22

inc

inc(x: number): number

It increments a number.

R.inc(1) // => 2

includes

includes(x: any, arrOrStr: Array|String): Boolean

R.includes(1, [1, 2]) // => true
R.includes('oo', 'foo') // => true
R.includes('z', 'foo') // => false

!! Note that this method is not part of Ramda API.

indexOf

indexOf(valueToFind: any, arr: Array): Number

It returns -1 or the index of the first element of arr equal of valueToFind.

R.indexOf(1, [1, 2]) // => 0

init

init(arrOrStr: Array|String): Array|String

  • It returns all but the last element of arrOrStr.
R.init([1, 2, 3])  // => [1, 2]
R.init('foo')  // => 'fo'

join

join(separator: String, arr: Array): String

R.join('-', [1, 2, 3])  // => '1-2-3'

is

isNil(xPrototype: any, x: any): boolean

It returns true is x is instance of xPrototype.

R.is(String, 'foo')  // => true
R.is(Array, 1)  // => false

isNil

isNil(x: any): Boolean

It returns true is x is either null or undefined.

R.isNil(null)  // => true
R.isNil(1)  // => false

last

last(arrOrStr: Array|String): any

  • It returns the last element of arrOrStr.
R.last(['foo', 'bar', 'baz']) // => 'baz'
R.last('foo') // => 'o'

lastIndexOf

lastIndexOf(x: any, arr: Array): Number

It returns the last index of x in array arr.

R.equals is used to determine equality between x and members of arr.

Value -1 is returned if no x is found in arr.

R.lastIndexOf(1, [1, 2, 3, 1, 2]) // => 3
R.lastIndexOf(10, [1, 2, 3, 1, 2]) // => -1

length

length(arrOrStr: Array|String): Number

R.length([1, 2, 3]) // => 3

map

map(mapFn: Function, arr: Array): Array

It returns the result of looping through arr with mapFn.

const mapFn = x => x * 2;
R.map(mapFn, [1, 2, 3]) // => [2, 4, 6]

match

match(regExpression: Regex, str: String): Array

R.match(/([a-z]a)/g, 'bananas') // => ['ba', 'na', 'na']

merge

merge(a: Object, b: Object)

It returns result of Object.assign({}, a, b).

R.merge({ 'foo': 0, 'bar': 1 }, { 'foo': 7 })
// => { 'foo': 7, 'bar': 1 }

modulo

modulo(a: Number, b: Number): Number

It returns the remainder of operation a/b.

R.module(14,3) // => 2

multiply

multiply(a: Number, b: Number): Number

It returns the result of operation a*b.

R.module(14,3) // => 2

not

not(x: any): Boolean

It returns inverted boolean version of input x.

R.not(true); //=> false
R.not(false); //=> true
R.not(0); //=> true
R.not(1); //=> false

omit

omit(propsToOmit: Array, obj: Object): Object

It returns a partial copy of an obj with omitting propsToOmit

R.omit(['a', 'd'], {a: 1, b: 2, c: 3}) // => {b: 2, c: 3}

path

path(pathToSearch: Array|String, obj: Object): any

If pathToSearch is 'a.b' then it will return 1 if obj is {a:{b:1}}.

It will return undefined, if such path is not found.

R.path('a.b', {a: {b: 1}}) // => 1
R.path(['a', 'b'], {a: {b: 2}}) // => 2
R.path(['a', 'c'], {a: {b: 2}}) // => undefined

pathOr

pathOr(defaultValue: any, pathToSearch: Array|String, obj: Object): any

pathFound is the result of calling R.path(pathToSearch, obj).

If pathFound is undefined, null or NaN, then defaultValue will be returned.

pathFound is returned in any other case.

R.pathOr(1, 'a.b', {a: {b: 2}}) // => 2
R.pathOr(1, ['a', 'b'], {a: {b: 2}}) // => 2
R.pathOr(1, ['a', 'c'], {a: {b: 2}}) // => 1

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}) // => 16
  • Note that partialCurry is method specific for Rambda and the method is not part of Ramda's API

  • You can read my argumentation for creating partialCurry here

pick

pick(propsToPick: Array, obj: Object): Object

It returns a partial copy of an obj containing only propsToPick properties.

R.pick(['a', 'c'], {a: 1, b: 2}) // => {a: 1}

pipe

pipe(fn1: Function, ... , fnN: Function): any

It performs left-to-right function composition.

const result = R.pipe(
  R.filter(val => val > 2),
  R.map(a => a * 2)
)([1, 2, 3, 4])
console.log(result) // => [6, 8]

pluck

pluck(property: String, arr: Array): Array

It 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(x: any, arr: Array): Array

It adds x to the start of the array arr.

R.prepend('foo', ['bar', 'baz']) // => ['foo', 'bar', 'baz']

prop

prop(propToFind: String, obj: Object): any

It returns undefined or the value of property propToFind in obj

R.prop('x', {x: 100}) // => 100
R.prop('x', {a: 1}) // => undefined

propEq

propEq(propToFind: String, valueToMatch: any, obj: Object): Boolean

It 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}) // => true
R.propEq(propToFind, valueToMatch)({foo: 1}) // => false

range

range(start: Number, end: Number): Array

It returns a array of numbers from start(inclusive) to end(exclusive).

R.range(0, 2)   // => [0, 1]

reduce

reduce(iteratorFn: Function, accumulator: any, array: Array): any

It 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])   // => 7

reject

reject(fn: Function, arr: Array): Array

It has the opposite effect of R.filter.

It will return those members of arr that return false when applied to function fn.

const fn = x => x % 2 === 1
R.reject(fn, [1, 2, 3, 4]) // => [2, 4]

repeat

repeat(valueToRepeat: T, num: Number): Array

R.repeat('foo', 2) // => ['foo', 'foo']

replace

replace(strOrRegex: String|Regex, replacer: String, str: String): String

Replace strOrRegex found in str with replacer

R.replace('foo', 'bar', 'foo foo') // => 'bar foo'
R.replace(/foo/, 'bar', 'foo foo') // => 'bar foo'
R.replace(/foo/g, 'bar', 'foo foo') // => 'bar bar'

reverse

const arr = [1, 2]
R.reverse(arr)
console.log(arr) // => [2, 1]

sort

sort(sortFn: Function, arr: Array): Array

It returns copy of arr sorted by sortFn.

sortFn must return Number

const sortFn = (a, b) => a - b
R.sort(sortFn, [3, 1, 2]) // => [1, 2, 3]

sortBy

sortBy(sortFn: Function, arr: Array): Array

It 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}
])
// => [{foo: 0}, {foo: 1}]

split

split(separator: String, str: String): Array

R.split('-', 'a-b-c') // => ['a', 'b', 'c']

splitEvery

splitEvery(sliceLength: Number, arrOrString: Array|String): Array

  • Splits arrOrStr into slices of sliceLength
R.splitEvery(2, [1, 2, 3]) // => [[1, 2], [3]]
R.splitEvery(3, 'foobar') // => ['foo', 'bar']

startsWith

startsWith(x: string, str: String): Boolean

R.startsWith(
  'foo',
  'foo-bar'
) // => true

R.startsWith(
  'bar',
  'foo-bar'
) // => false

subtract

subtract(a: Number, b: Number): Number

R.subtract(3, 1) // => 2

T

R.T() // => true

tail

tail(arrOrStr: Array|String): Array|String

  • It returns all but the first element of arrOrStr
R.tail([1, 2, 3])  // => [2, 3]
R.tail('foo')  // => 'oo'

take

take(num: Number, arrOrStr: Array|String): Array|String

  • It returns the first num elements of arrOrStr.
R.take(1, ['foo', 'bar']) // => ['foo']
R.take(2, ['foo']) // => 'fo'

takeLast

takeLast(num: Number, arrOrStr: Array|String): Array|String

  • It returns the last num elements of arrOrStr.
R.takeLast(1, ['foo', 'bar']) // => ['bar']
R.takeLast(2, ['foo']) // => 'oo'

test

test(regExpression: Regex, str: String): Boolean

  • Determines whether str matches regExpression
R.test(/^f/, 'foo') // => true
R.test(/^f/, 'bar') // => false

times

times(fn: Function, n: Number): Array

It returns the result of applying function fn over members of range array. The range array includes numbers between 0 and n(exclusive).

R.times(R.identity, 5); //=> [0, 1, 2, 3, 4]

toLower

toLower(str: String): String

R.toLower('FOO') // => 'foo'

toString

toString(x: any): String

R.toString([1, 2]) // => '1,2'

toUpper

toUpper(str: String): String

R.toUpper('foo') // => 'FOO'

trim

trim(str: String): String

R.trim('  foo  ') // => 'foo'

type

type(a: any): String

R.type(() => {}) // => "Function"
R.type(async () => {}) // => "Async"
R.type([]) // => "Array"
R.type({}) // => "Object"
R.type('foo') // => "String"
R.type(1) // => "Number"
R.type(true) // => "Boolean"
R.type(null) // => "Null"
R.type(/[A-z]/) // => "RegExp"

const delay = ms => new Promise(resolve => {
  setTimeout(function () {
    resolve()
  }, ms)
})
R.type(delay) // => "Promise"

uniq

uniq(arr: Array): Array

It returns a new array containing only one copy of each element in arr.

R.uniq([1, 1, 2, 1]) // => [1, 2]
R.uniq([1, '1'])     // => [1, '1']

update

update(i: Number, replaceValue: any, arr: Array): Array

It returns a new copy of the arr with the element at i index replaced with replaceValue.

R.update(0, "foo", ['bar', 'baz']) // => ['foo', baz]

values

values(obj: Object): Array

It returns array with of all values in obj.

R.values({a: 1, b: 2}) // => [1, 2]

without

without(a: Array, b: Array): Array

It will return a new array based on b array.

This array contains all members of b array, that doesn't exist in a array.

Method R.equals is used to determine the existance of b members in a array.

R.without([1, 2], [1, 2, 3, 4]) // => [3, 4]

Benchmark

Screen Screen

Tree-shaking

bundlephobia

Typings

  • Typescript

Rambda's typings are located at ./index.d.ts, so your IDE should be able to pick it up without any additional actions.

  • Flowtype

You can use 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

  • 1.0.3 R.ifElse accept also boolean as condition argument
  • 1.0.2 Remove typedDefaultTo and typedPathOr | Add R.pickAll and R.none
  • 1.0.0 Major change as build is now ES6 not ES5 compatible (Related to issue #46)| Making Rambda fully tree-shakeable| Edit Typescript definition
  • 0.9.8 Revert to ES5 compatible build - issue #46
  • 0.9.7 Refactor for Rollup tree-shake | Remove R.padEnd and R.padStart
  • 0.9.6 Close issue #44 - R.reverse mutates the array
  • 0.9.5 Close issue #45 - invalid Typescript typings
  • 0.9.4 Add R.reject and R.without (PR#41 PR#42) | Remove 'browser' field in package.json due to Webpack bug 4674
  • 0.9.3 Add R.forEach and R.times
  • 0.9.2 Add Typescript definitions
  • 0.9.1 Close issue #36 - move current behaviour of defaultTo to a new method typedDefaultTo; make defaultTo follow Ramda spec; add pathOr; add typedPathOr.
  • 0.9.0 Add R.pipe PR#35
  • 0.8.9 Add R.isNil
  • 0.8.8 Migrate to ES modules PR33 | Add R.flip to the API | R.map/filter works with objects
  • 0.8.7 Change Webpack with Rollup - PR29
  • 0.8.6 Add R.tap and R.identity
  • 0.8.5 Add R.all, R.allPass, R.both, R.either and R.complement
  • 0.8.4 Learning to run yarn test before yarn publish the hard way
  • 0.8.3 Add R.always, R.T and R.F
  • 0.8.2 Add concat, padStart, padEnd, lastIndexOf, toString, reverse, endsWith and startsWith methods
  • 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

Browse by category

Function

addIndex

always

compose

curry

F

identity

T

tap

Math

add

divide

modulo

multiply

subtract

List

adjust

all

any

append

concat

contains

drop

dropLast

endsWith

filter

find

findIndex

flatten

head

indexOf

init

join

last

lastIndexOf

length

map

pluck

prepend

range

reduce

repeat

reverse

sort

splitEvery

startsWith

tail

take

takeLast

uniq

update

Logic

allPass

both

complement

defaultTo

either

ifElse

not

Object

has

merge

omit

path

pick

prop

values

Relation

equals

propEq

sortBy

String

match

replace

split

test

toLower

toString

toUpper

trim

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 yarn 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

yarn run lint modules/endsWith.js

yarn run lint __tests__/endsWith.js

Submit PR

Expect response within 2 days.

Additional info

Running benchmarks

  • To run all benchmarks

yarn run benchmark all

  • To run single or number of benchmarks

yarn run benchmark add compose filter

Libraries using Rambda

Articles about Rambda