diff --git a/src/internal/ap.js b/src/internal/ap.js new file mode 100644 index 0000000000..27e9722fd2 --- /dev/null +++ b/src/internal/ap.js @@ -0,0 +1,28 @@ +import fl from 'fantasy-land'; +import { ap as apR, curryN, pathSatisfies, both, anyPass } from 'ramda'; + +import isFunction from '../isFunction'; + + +const isFunctor = anyPass([pathSatisfies(isFunction, ['map']), pathSatisfies(isFunction, [fl.map])]); +const isApply = both( + isFunctor, + anyPass([pathSatisfies(isFunction, ['ap']), pathSatisfies(isFunction, [fl.ap])]) +); + + +const ap = curryN(2, (applyF, applyX) => { + // return original ramda `ap` if not Apply spec + if (!isApply(applyF) || !isApply(applyX)) { return apR(applyF, applyX) } + + try { + // new version of `ap` starting from ramda version > 0.23.0 + return applyF.ap(applyX); + } catch (e) { + // old version of `ap` till ramda version <= 0.23.0 + return applyX.ap(applyF); + } +}); + + +export default ap; diff --git a/src/liftFN.js b/src/liftFN.js index 71b9d9b99e..ae5570b970 100644 --- a/src/liftFN.js +++ b/src/liftFN.js @@ -1,22 +1,6 @@ -import { curry, head, slice, reduce, ap as apR, curryN, map, add, flip } from 'ramda'; +import { curry, head, slice, reduce, curryN, map } from 'ramda'; -import Identity from './internal/fantasy-land/Identity'; - -const m1 = Identity.of(1); -const m2 = Identity.of(2).map(add); - - -export const createAp = (ap1, ap2) => { - try { - // new version of `ap` starting from ramda version > 0.23.0 - return ap1.ap(ap2) && apR; - } catch (e) { - // old version of `ap` till ramda version <= 0.23.0 - return curryN(2, flip(apR)); - } -}; - -const ap = createAp(m2, m1); +import ap from './internal/ap'; /** * "lifts" a function to be the specified arity, so that it may "map over" objects that satisfy diff --git a/test/internal/ap.js b/test/internal/ap.js new file mode 100644 index 0000000000..718a3ba13d --- /dev/null +++ b/test/internal/ap.js @@ -0,0 +1,23 @@ +import { add, multiply } from 'ramda'; + +import eq from '../shared/eq'; +import _ap from '../../src/internal/ap'; +import Identity from '../../src/internal/fantasy-land/Identity'; + + +describe('ap', function() { + const m1 = Identity.of(1); + const m2 = Identity.of(2).map(add); + + it('tests new fantasyland spec compatibility', function() { + eq(_ap(m1, m2), Identity.of(3)); + }); + + it('tests old fantasyland spec compatibility', function() { + eq(_ap(m2, m1), Identity.of(3)); + }); + + it('tests for non Apply spec', function() { + eq(_ap([multiply(2), add(3)], [1, 2, 3]), [2, 4, 6, 4, 5, 6]); + }); +}); diff --git a/test/liftFN.js b/test/liftFN.js index e542985a01..bad63e17ab 100644 --- a/test/liftFN.js +++ b/test/liftFN.js @@ -4,7 +4,6 @@ import { add, reduce } from 'ramda'; import RA from '../src/index'; import eq from './shared/eq'; -import { createAp } from '../src/liftFN'; import Identity from '../src/internal/fantasy-land/Identity'; @@ -50,27 +49,4 @@ describe('liftFN', function() { eq(typeof f4, 'function'); eq(f4(addN)(Maybe.Some(1), Maybe.Some(1), Maybe.Some(1), Maybe.Some(1)), Maybe.Some(4)); }); - - it('test old fantasyland spec compatibility', function() { - const m1 = Identity.of(1); - const m2 = Identity.of(2).map(add); - - eq(createAp(m1, m2)(m1, m2), Identity.of(3)); - }); - - it('test new fantasyland spec compatibility', function() { - const m1 = Identity.of(1); - const m2 = Identity.of(2).map(add); - const ap = createAp(m1, m2); - - eq(ap(m1, m2), Identity.of(3)); - }); - - it('test old fantasyland spec compatibility', function() { - const m1 = Maybe.Some(1); - const m2 = Maybe.Some(2).map(add); - const ap = createAp(m1, m2); - - eq(ap(m1, m2), Maybe.Some(3)); - }); }); diff --git a/test/mocha.opts b/test/mocha.opts index d121db90b4..b601d470b7 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,4 +1,4 @@ --reporter mocha-multi-reporters --reporter-options configFile=test/mocha-multi.json --compilers babel-register -test/*.js +test/**/*.js