diff --git a/README.md b/README.md index 729227e..0d7c4a6 100644 --- a/README.md +++ b/README.md @@ -13,5 +13,9 @@ npm install --save zeal-redux-utils ## Usage ```javascript -import { createActionTypes, createReducer } from 'zeal-redux-utils' +import { + createActionTypes, + createReducer, + globalizeSelectors +} from 'zeal-redux-utils' ``` diff --git a/src/__tests__/globalizeSelectors-spec.js b/src/__tests__/globalizeSelectors-spec.js new file mode 100644 index 0000000..55f8ea1 --- /dev/null +++ b/src/__tests__/globalizeSelectors-spec.js @@ -0,0 +1,32 @@ +import { prop } from 'ramda' + +import globalizeSelectors from '../globalizeSelectors' + +describe('globalizeSelectors', () => { + const globalState = { + section: { + numbers: [2, 3, 4] + } + } + + const localState = prop('section') + + const selectors = { + numbers: prop('numbers'), + numberAt: (index, state) => state.numbers[index] + } + + const globalized = globalizeSelectors(localState, selectors) + + context('with a single-argument selector', () => { + test('allows the selector to work from the global state', () => { + expect(globalized.numbers(globalState)).toEqual([2, 3, 4]) + }) + }) + + context('with a multi-argument selector', () => { + test('allows the selector to work from the global state', () => { + expect(globalized.numberAt(1, globalState)).toEqual(3) + }) + }) +}) diff --git a/src/globalizeSelectors.js b/src/globalizeSelectors.js new file mode 100644 index 0000000..7486190 --- /dev/null +++ b/src/globalizeSelectors.js @@ -0,0 +1,29 @@ +import { adjust, map } from 'ramda' + +/* +Take a local state transform and an object containing selector functions. + +* The local state transform is a function that takes the global state and + returns the appropriate sub-section of the state tree (aka local state). + +* The selector functions are written to work with the local state. + +Return a new object of selector functions. The output selector functions now +work with the global state instead. + +To do this, we map a `globalize` function over the selectors. + +We assume that the state argument is always the last one, and we want to +transform it by applying the local state. We use Ramda's `adjust` function +to do that. + +The result of `globalize` is a function that takes the global state as its last +argument, transforms that state into local state, and then calls the original, +localized, selector. +*/ + +const globalize = transform => selector => (...args) => + selector(...adjust(transform, -1, args)) + +export default (localStateTransform, selectors) => + map(globalize(localStateTransform), selectors) diff --git a/src/index.js b/src/index.js index 91173d7..ea288c7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,2 +1,3 @@ export createActionTypes from './createActionTypes' export createReducer from './createReducer' +export globalizeSelectors from './globalizeSelectors'