Skip to content

Commit e369446

Browse files
authored
Merge pull request #33 from cyclejs-community/unified-support
Add support for multiple stream libraries (Cycle Unified)
2 parents 66779f4 + 08f83c8 commit e369446

File tree

7 files changed

+103
-45
lines changed

7 files changed

+103
-45
lines changed

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ Handle redux async actions using [Cycle.js](https://cycle.js.org/).
3030

3131
`npm install --save redux-cycles`
3232

33-
Then use `createCycleMiddleware()` which returns the redux middleware function, but also has two function properties attached to it; namely `makeActionDriver()` and `makeStateDriver()` which you can use accordingly when you call `Cycle.run` (which can be installed via `npm i -s @cycle/xstream-run`).
33+
Then use `createCycleMiddleware()` which returns the redux middleware function with two driver factories attached: `makeActionDriver()` and `makeStateDriver()`. Use them when you call the Cycle `run` function (can be installed via `npm install --save @cycle/run`).
3434

3535
```js
36-
import { run } from '@cycle/xstream-run';
36+
import { run } from '@cycle/run';
3737
import { createCycleMiddleware } from 'redux-cycles';
3838

3939
function main(sources) {
@@ -59,6 +59,21 @@ run(main, {
5959
})
6060
```
6161

62+
By default `@cycle/run` uses `xstream`. If you want to use another streaming library simply import it and use its `run` method instead.
63+
64+
For RxJS:
65+
66+
```js
67+
import { run } from '@cycle/rxjs-run';
68+
```
69+
70+
For Most.js:
71+
72+
```js
73+
import { run } from '@cycle/most-run';
74+
```
75+
76+
6277
## Example
6378

6479
Try out this [JS Bin](https://jsbin.com/bomugapuxi/2/edit?js,output).

example/configureStore.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { routerMiddleware } from 'react-router-redux';
44
import rootReducer from './reducers';
55
import main from './cycle';
66
import { createCycleMiddleware } from 'redux-cycles';
7-
import {run} from '@cycle/xstream-run';
7+
import {run} from '@cycle/run';
88
import {makeHTTPDriver} from '@cycle/http';
99
import {timeDriver} from '@cycle/time';
1010

@@ -29,6 +29,6 @@ export default function configureStore() {
2929
Time: timeDriver,
3030
HTTP: makeHTTPDriver(),
3131
})
32-
32+
3333
return store;
3434
}

example/package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
"author": "Luca Matteis",
1313
"license": "MIT",
1414
"dependencies": {
15-
"@cycle/dom": "^14.1.0",
1615
"@cycle/http": "^11.2.0",
17-
"@cycle/xstream-run": "^4.0.0",
16+
"@cycle/run": "^1.0.0",
1817
"history": "^2.1.2",
1918
"react": "^15.3.0",
2019
"react-dom": "^15.3.0",
@@ -23,16 +22,16 @@
2322
"react-router-redux": "^4.0.5",
2423
"redux": "^3.5.2",
2524
"redux-cycles": "file:../",
26-
"xstream": "^9.0.0"
25+
"xstream": "^10"
2726
},
2827
"devDependencies": {
28+
"@cycle/time": "^0.7.1",
2929
"babel-core": "^6.11.4",
3030
"babel-loader": "^6.2.4",
3131
"babel-preset-es2015": "^6.9.0",
3232
"babel-preset-react": "^6.11.1",
33-
"@cycle/time": "^0.2.1",
33+
"jest": "^18.1.0",
3434
"webpack": "^1.13.1",
35-
"webpack-dev-server": "^1.14.1",
36-
"jest": "^18.1.0"
35+
"webpack-dev-server": "^1.14.1"
3736
}
3837
}

package.json

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,42 +31,48 @@
3131
},
3232
"license": "MIT",
3333
"babel": {
34-
"presets": ["es2015"]
34+
"presets": [
35+
"es2015"
36+
]
3537
},
3638
"eslintConfig": {
3739
"env": {
38-
"browser": true,
39-
"es6": true,
40-
"node": true
40+
"browser": true,
41+
"es6": true,
42+
"node": true
4143
},
4244
"extends": "eslint:recommended",
4345
"parserOptions": {
44-
"sourceType": "module"
46+
"sourceType": "module"
4547
},
4648
"rules": {
47-
"indent": [
48-
"error",
49-
2
50-
],
51-
"linebreak-style": [
52-
"error",
53-
"unix"
54-
],
55-
"quotes": [
56-
"error",
57-
"single"
58-
],
59-
"semi": [
60-
"error",
61-
"never"
62-
]
49+
"indent": [
50+
"error",
51+
2
52+
],
53+
"linebreak-style": [
54+
"error",
55+
"unix"
56+
],
57+
"quotes": [
58+
"error",
59+
"single"
60+
],
61+
"semi": [
62+
"error",
63+
"never"
64+
]
6365
}
6466
},
6567
"dependencies": {
66-
"xstream": "^9.0.0"
68+
"@cycle/run": "*"
69+
},
70+
"peerDependencies": {
71+
"xstream": "*"
6772
},
6873
"devDependencies": {
69-
"@cycle/xstream-run": "^4.0.0",
74+
"@cycle/rxjs-run": "^4.1.0",
75+
"rxjs": "^5.2.0",
7076
"babel-cli": "^6.18.0",
7177
"babel-jest": "^18.0.0",
7278
"babel-preset-es2015": "^6.9.0",

src/combineCycles.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default function combineCycles(...mains) {
1212
.reduce((combinedSinks, driver) => {
1313
const driverSinks = sinks
1414
.filter(sink => sink[driver])
15-
.map(sink => sink[driver])
15+
.map(sink => xs.from(sink[driver]))
1616

1717
combinedSinks[driver] = xs.merge(...driverSinks)
1818
return combinedSinks

src/createCycleMiddleware.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import xs from 'xstream'
2+
import {adapt} from '@cycle/run/lib/adapt'
23

34
export default function createCycleMiddleware () {
45
let store = null
@@ -33,20 +34,20 @@ export default function createCycleMiddleware () {
3334
complete: () => {},
3435
})
3536

36-
return xs.create({
37+
return adapt(xs.create({
3738
start: listener => {
3839
actionListener = listener
3940
},
4041
stop: () => {},
41-
})
42+
}))
4243
}
4344
}
4445

4546
cycleMiddleware.makeStateDriver = () => {
4647
const isSame = {}
4748
return function stateDriver() {
4849
const getCurrent = store.getState
49-
return xs.create({
50+
return adapt(xs.create({
5051
start: listener => {
5152
stateListener = listener
5253
},
@@ -62,7 +63,7 @@ export default function createCycleMiddleware () {
6263
return currState
6364
}, getCurrent)
6465
.map(state => state === getCurrent ? getCurrent() : state)
65-
.filter(state => state !== isSame)
66+
.filter(state => state !== isSame))
6667
}
6768
}
6869

test/createCycleMiddleware.test.js

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
/* eslint-disable no-undef */
2-
import { createCycleMiddleware } from '../'
2+
/* eslint-disable no-console */
3+
import { createCycleMiddleware, combineCycles } from '../'
34
import { createStore, applyMiddleware } from 'redux'
45
import xs from 'xstream'
5-
import {run} from '@cycle/xstream-run'
6+
import {run} from '@cycle/run'
7+
import {run as rxjsRun} from '@cycle/rxjs-run'
8+
import {Observable} from 'rxjs/Rx'
9+
import {setAdapt} from '@cycle/run/lib/adapt'
610
jest.useFakeTimers()
711

812
function initStore(main, drivers, reducer = null, r = run) {
@@ -23,7 +27,9 @@ function initStore(main, drivers, reducer = null, r = run) {
2327
return store
2428
}
2529

26-
describe('Redux cycle middleware', () => {
30+
describe('Redux cycle middleware xstream', () => {
31+
beforeEach(() => setAdapt(stream => stream))
32+
2733
it('dispatches a PING to see whether the middleware dispatches a PONG', (done) => {
2834
function main(sources) {
2935
const pong$ = sources.ACTION
@@ -40,7 +46,7 @@ describe('Redux cycle middleware', () => {
4046
{ type: 'PING' },
4147
{ type: 'PONG' }
4248
]
43-
const store = initStore(main, {})
49+
const store = initStore(combineCycles(main), {})
4450

4551
store.dispatch({ type: 'PING' })
4652

@@ -54,9 +60,9 @@ describe('Redux cycle middleware', () => {
5460
const pong$ = sources.ACTION
5561
.filter(action => action.type === 'PING')
5662
.map(() =>
57-
xs.periodic(10000)
58-
.take(1)
59-
.mapTo({ type: 'PONG' })
63+
xs.periodic(10000)
64+
.take(1)
65+
.mapTo({ type: 'PONG' })
6066
)
6167
.flatten()
6268

@@ -145,3 +151,34 @@ describe('Redux cycle middleware', () => {
145151

146152
})
147153
})
154+
155+
describe('Redux cycle middleware RxJS', () => {
156+
beforeEach(() => setAdapt(stream => Observable.from(stream)))
157+
158+
it('uses rxjs-run with Cycle Unified', (done) => {
159+
function main(sources) {
160+
const pong$ = sources.ACTION
161+
.filter(action => action.type === 'PING')
162+
.do(_ => _) // do() only exists in RxJS
163+
.mapTo({ type: 'PONG' })
164+
165+
return {
166+
ACTION: pong$
167+
}
168+
}
169+
170+
const store = initStore(combineCycles(main), {}, null, rxjsRun)
171+
172+
store.dispatch({ type: 'PING' })
173+
174+
const expectedActions = [
175+
{ type: '@@redux/INIT' },
176+
{ type: 'PING' },
177+
{ type: 'PONG' }
178+
]
179+
expect(store.getState()).toMatchObject(expectedActions)
180+
181+
done()
182+
183+
})
184+
})

0 commit comments

Comments
 (0)