isomorfeus-redux 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +1 -0
- data/README.md +94 -0
- data/isomorfeus-redux.gemspec +20 -0
- data/lib/isomorfeus-redux.rb +22 -0
- data/lib/isomorfeus/promise.rb +350 -0
- data/lib/redux.rb +45 -0
- data/lib/redux/store.rb +133 -0
- data/lib/redux/version.rb +3 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3f0fa508494a00cb6c953ec0660d5a25fcdfeeadfe860b521cc60568da02357d
|
4
|
+
data.tar.gz: 7b318ed593527284d0e946067c278dceed3a4eaa0e8fbc0941b111c1f49d688a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fb7e38b768252ae140861adb4fe56afdec8b6e74704a710efec364eeaa168a849e07b66dad85b59bb4af5fbaa80d685064d27ecaedbe6abfb5b68fb027ba9d15
|
7
|
+
data.tar.gz: 93e6ee7ae5bb629f0d480b71e87c96c49299102f37b41875e670911da5987619707ae1077d4e57abc4e508cbaa2d77fd2bc4f9b26f10d4c155fe09fab7d5879c
|
data/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
gemspec
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# isomorfeus-redux
|
2
|
+
|
3
|
+
Redux for Opal Ruby.
|
4
|
+
|
5
|
+
## Versioning
|
6
|
+
isomorfeus-redux version follows the Redux version which features and API it implements.
|
7
|
+
Isomorfeus-redux 4.0.x implements features and the API of Redux 4.0 and should be used with Redux4.0
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
To install redux with the matching version:
|
11
|
+
```
|
12
|
+
yarn add redux@4.0.0
|
13
|
+
```
|
14
|
+
then add to the Gemfile:
|
15
|
+
```ruby
|
16
|
+
gem 'isomorfeus-redux'
|
17
|
+
```
|
18
|
+
then `bundle install`
|
19
|
+
and to your client code add:
|
20
|
+
```ruby
|
21
|
+
require 'isomorfeus-redux'
|
22
|
+
```
|
23
|
+
## Usage
|
24
|
+
Because isomorfeus-redux follows closely the Redux principles/implementation/API and Documentation, most things of the official Redux documentation
|
25
|
+
apply, but in the Ruby way, see:
|
26
|
+
- https://redux.js.org
|
27
|
+
|
28
|
+
Redux and accompanying libraries must be imported and available in the global namespace in the application javascript entry file,
|
29
|
+
with webpack this can be ensured by assigning them to the global namespace:
|
30
|
+
```javascript
|
31
|
+
import * as Redux from 'redux';
|
32
|
+
global.Redux = Redux;
|
33
|
+
```
|
34
|
+
|
35
|
+
Following features are presented with its differences to the Javascript Redux implementation.
|
36
|
+
Of course, in Ruby the naming is underscored, eg. `Redux.createStore` in javascript becomes `Redux.create_store` in Ruby.
|
37
|
+
|
38
|
+
### Creating a Store
|
39
|
+
A store can be created using:
|
40
|
+
```ruby
|
41
|
+
store = Redux::Store.new(reducer, preloaded_state, enhancer)
|
42
|
+
```
|
43
|
+
or:
|
44
|
+
```ruby
|
45
|
+
store = Redux.create_store(reducer, preloaded_state, enhancer)
|
46
|
+
```
|
47
|
+
- **reducer** is a javascript function. Isomorfeus provides a helper to create a reducer, see below.
|
48
|
+
- **preloaded_state** can be a Ruby Hash or a native javascript object.
|
49
|
+
- **enhancer** is a javascript function.
|
50
|
+
|
51
|
+
### Creating a Reducer
|
52
|
+
Its possible to use native javascript functions for creating a store. To use ruby conveniently for reducers a helper is provided:
|
53
|
+
```ruby
|
54
|
+
reducer = Redux.create_reducer do |prev_state, action|
|
55
|
+
# do something here
|
56
|
+
{}.merge(prev_state)
|
57
|
+
end
|
58
|
+
```
|
59
|
+
This helper wraps the ruby code block in a javascript function that takes care of converting Opal Hashes to javascript
|
60
|
+
objects and the other way around. The resulting reducer is simply javascript function, suitable for creating a store.
|
61
|
+
|
62
|
+
### Adding a reducer to the global store
|
63
|
+
The reducer must be a Javascript function and can be created with Redux.create_reducer as above:
|
64
|
+
```ruby
|
65
|
+
Redux::Store.add_reducer(your_store_key_name: reducer)
|
66
|
+
```
|
67
|
+
|
68
|
+
### Global Store
|
69
|
+
The store is available from anywhere within Opal Ruby context as:
|
70
|
+
```ruby
|
71
|
+
Isomorfeus.store
|
72
|
+
```
|
73
|
+
To get the native store from within Javascript context:
|
74
|
+
```javascript
|
75
|
+
Opal.Isomorfeus.store.native
|
76
|
+
```
|
77
|
+
### Other Rubyfications
|
78
|
+
- `dispatch` accepts a Ruby Hash
|
79
|
+
- `get_state` returns a Ruby Hash
|
80
|
+
- `subscribe` accepts a ruby block as listener:
|
81
|
+
```ruby
|
82
|
+
Isomorfeus.store.subscribe do
|
83
|
+
# something useful here
|
84
|
+
end
|
85
|
+
```
|
86
|
+
### Setup
|
87
|
+
This is done automatically within Isomorfeus. If isomorfeus-redux is used in isolation, these methods can be used:
|
88
|
+
```ruby
|
89
|
+
Redux::Store.add_middleware(middleware) # middleware must be Javascript function
|
90
|
+
Redux::Store.init! # initializes the global store
|
91
|
+
```
|
92
|
+
|
93
|
+
### Development Tools
|
94
|
+
The Redux Development Tools allow for detailed debugging of store/state changes: https://github.com/zalmoxisus/redux-devtools-extension
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require_relative 'lib/redux/version.rb'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'isomorfeus-redux'
|
6
|
+
s.version = Redux::VERSION
|
7
|
+
|
8
|
+
s.authors = ['Jan Biedermann']
|
9
|
+
s.email = ['jan@kursator.com']
|
10
|
+
s.homepage = 'http://isomorfeus.com'
|
11
|
+
s.summary = 'Redux for Opal Ruby.'
|
12
|
+
s.license = 'MIT'
|
13
|
+
s.description = 'Use a global store and write reducers for it in Opal Ruby.'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(gemfiles|s)/}) }
|
16
|
+
# s.test_files = `git ls-files -- {test,s,features}/*`.split("\n")
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_dependency 'opal', '>= 0.11.0', '< 0.12.0'
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
if RUBY_ENGINE == 'opal'
|
2
|
+
require 'native'
|
3
|
+
require 'promise'
|
4
|
+
require 'redux/version'
|
5
|
+
require 'redux'
|
6
|
+
require 'redux/store'
|
7
|
+
# store initialization happens in Isomorfeus.init, see isomorfeus-react/lib/isomorfeus/config.rb
|
8
|
+
else
|
9
|
+
require 'opal'
|
10
|
+
require 'isomorfeus/promise'
|
11
|
+
require 'redux/version'
|
12
|
+
|
13
|
+
Opal.append_path(__dir__.untaint)
|
14
|
+
|
15
|
+
if Dir.exist?(File.join('app', 'isomorfeus'))
|
16
|
+
# Opal.append_path(File.expand_path(File.join('app', 'isomorfeus', 'components')))
|
17
|
+
Opal.append_path(File.expand_path(File.join('app', 'isomorfeus'))) unless Opal.paths.include?(File.expand_path(File.join('app', 'isomorfeus')))
|
18
|
+
elsif Dir.exist?('isomorfeus')
|
19
|
+
# Opal.append_path(File.expand_path(File.join('isomorfeus', 'components')))
|
20
|
+
Opal.append_path(File.expand_path('isomorfeus')) unless Opal.paths.include?(File.expand_path('isomorfeus'))
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,350 @@
|
|
1
|
+
# taken from https://github.com/ruby-hyperloop/isomorfeus-operation/blob/edge/lib/isomorfeus-operation/promise.rb
|
2
|
+
# TODO: This is used only server side and may be used by others too and should be a separate gem maybe
|
3
|
+
|
4
|
+
class Promise
|
5
|
+
def self.value(value)
|
6
|
+
new.resolve(value)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.error(value)
|
10
|
+
new.reject(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.when(*promises)
|
14
|
+
When.new(promises)
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :error, :prev, :next
|
18
|
+
|
19
|
+
def initialize(action = {})
|
20
|
+
@action = action
|
21
|
+
|
22
|
+
@realized = false
|
23
|
+
@exception = false
|
24
|
+
@value = nil
|
25
|
+
@error = nil
|
26
|
+
@delayed = false
|
27
|
+
|
28
|
+
@prev = nil
|
29
|
+
@next = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def value
|
33
|
+
if Promise === @value
|
34
|
+
@value.value
|
35
|
+
else
|
36
|
+
@value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def act?
|
41
|
+
@action.has_key?(:success) || @action.has_key?(:always)
|
42
|
+
end
|
43
|
+
|
44
|
+
def action
|
45
|
+
@action.keys
|
46
|
+
end
|
47
|
+
|
48
|
+
def exception?
|
49
|
+
@exception
|
50
|
+
end
|
51
|
+
|
52
|
+
def realized?
|
53
|
+
!!@realized
|
54
|
+
end
|
55
|
+
|
56
|
+
def resolved?
|
57
|
+
@realized == :resolve
|
58
|
+
end
|
59
|
+
|
60
|
+
def rejected?
|
61
|
+
@realized == :reject
|
62
|
+
end
|
63
|
+
|
64
|
+
def pending?
|
65
|
+
!realized?
|
66
|
+
end
|
67
|
+
|
68
|
+
def ^(promise)
|
69
|
+
promise << self
|
70
|
+
self >> promise
|
71
|
+
|
72
|
+
promise
|
73
|
+
end
|
74
|
+
|
75
|
+
def <<(promise)
|
76
|
+
@prev = promise
|
77
|
+
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def >>(promise)
|
82
|
+
@next << promise
|
83
|
+
|
84
|
+
if exception?
|
85
|
+
promise.reject(@delayed[0])
|
86
|
+
elsif resolved?
|
87
|
+
promise.resolve(@delayed ? @delayed[0] : value)
|
88
|
+
elsif rejected?
|
89
|
+
if !@action.has_key?(:failure) || Promise === (@delayed ? @delayed[0] : @error)
|
90
|
+
promise.reject(@delayed ? @delayed[0] : error)
|
91
|
+
elsif promise.action.include?(:always)
|
92
|
+
promise.reject(@delayed ? @delayed[0] : error)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def resolve(value = nil)
|
100
|
+
if realized?
|
101
|
+
raise ArgumentError, 'the promise has already been realized'
|
102
|
+
end
|
103
|
+
|
104
|
+
if Promise === value
|
105
|
+
return (value << @prev) ^ self
|
106
|
+
end
|
107
|
+
|
108
|
+
begin
|
109
|
+
if block = @action[:success] || @action[:always]
|
110
|
+
value = block.call(value)
|
111
|
+
end
|
112
|
+
|
113
|
+
resolve!(value)
|
114
|
+
rescue Exception => e
|
115
|
+
exception!(e)
|
116
|
+
end
|
117
|
+
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
def resolve!(value)
|
122
|
+
@realized = :resolve
|
123
|
+
@value = value
|
124
|
+
|
125
|
+
if @next.any?
|
126
|
+
@next.each { |p| p.resolve(value) }
|
127
|
+
else
|
128
|
+
@delayed = [value]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def reject(value = nil)
|
133
|
+
if realized?
|
134
|
+
raise ArgumentError, 'the promise has already been realized'
|
135
|
+
end
|
136
|
+
|
137
|
+
if Promise === value
|
138
|
+
return (value << @prev) ^ self
|
139
|
+
end
|
140
|
+
|
141
|
+
begin
|
142
|
+
if block = @action[:failure] || @action[:always]
|
143
|
+
value = block.call(value)
|
144
|
+
end
|
145
|
+
|
146
|
+
if @action.has_key?(:always)
|
147
|
+
resolve!(value)
|
148
|
+
else
|
149
|
+
reject!(value)
|
150
|
+
end
|
151
|
+
rescue Exception => e
|
152
|
+
exception!(e)
|
153
|
+
end
|
154
|
+
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
def reject!(value)
|
159
|
+
@realized = :reject
|
160
|
+
@error = value
|
161
|
+
|
162
|
+
if @next.any?
|
163
|
+
@next.each { |p| p.reject(value) }
|
164
|
+
else
|
165
|
+
@delayed = [value]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def exception!(error)
|
170
|
+
@exception = true
|
171
|
+
|
172
|
+
reject!(error)
|
173
|
+
end
|
174
|
+
|
175
|
+
def then(&block)
|
176
|
+
self ^ Promise.new(success: block)
|
177
|
+
end
|
178
|
+
|
179
|
+
def then!(&block)
|
180
|
+
there_can_be_only_one!
|
181
|
+
self.then(&block)
|
182
|
+
end
|
183
|
+
|
184
|
+
alias do then
|
185
|
+
alias do! then!
|
186
|
+
|
187
|
+
def fail(&block)
|
188
|
+
self ^ Promise.new(failure: block)
|
189
|
+
end
|
190
|
+
|
191
|
+
def fail!(&block)
|
192
|
+
there_can_be_only_one!
|
193
|
+
fail(&block)
|
194
|
+
end
|
195
|
+
|
196
|
+
alias rescue fail
|
197
|
+
alias catch fail
|
198
|
+
alias rescue! fail!
|
199
|
+
alias catch! fail!
|
200
|
+
|
201
|
+
def always(&block)
|
202
|
+
self ^ Promise.new(always: block)
|
203
|
+
end
|
204
|
+
|
205
|
+
def always!(&block)
|
206
|
+
there_can_be_only_one!
|
207
|
+
always(&block)
|
208
|
+
end
|
209
|
+
|
210
|
+
alias finally always
|
211
|
+
alias ensure always
|
212
|
+
alias finally! always!
|
213
|
+
alias ensure! always!
|
214
|
+
|
215
|
+
def trace(depth = nil, &block)
|
216
|
+
self ^ Trace.new(depth, block)
|
217
|
+
end
|
218
|
+
|
219
|
+
def trace!(*args, &block)
|
220
|
+
there_can_be_only_one!
|
221
|
+
trace(*args, &block)
|
222
|
+
end
|
223
|
+
|
224
|
+
def there_can_be_only_one!
|
225
|
+
if @next.any?
|
226
|
+
raise ArgumentError, 'a promise has already been chained'
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def inspect
|
231
|
+
result = "#<#{self.class}(#{object_id})"
|
232
|
+
|
233
|
+
if @next.any?
|
234
|
+
result += " >> #{@next.inspect}"
|
235
|
+
end
|
236
|
+
|
237
|
+
if realized?
|
238
|
+
result += ": #{(@value || @error).inspect}>"
|
239
|
+
else
|
240
|
+
result += ">"
|
241
|
+
end
|
242
|
+
|
243
|
+
result
|
244
|
+
end
|
245
|
+
|
246
|
+
class Trace < self
|
247
|
+
def self.it(promise)
|
248
|
+
current = []
|
249
|
+
|
250
|
+
if promise.act? || promise.prev.nil?
|
251
|
+
current.push(promise.value)
|
252
|
+
end
|
253
|
+
|
254
|
+
if prev = promise.prev
|
255
|
+
current.concat(it(prev))
|
256
|
+
else
|
257
|
+
current
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def initialize(depth, block)
|
262
|
+
@depth = depth
|
263
|
+
|
264
|
+
super success: proc {
|
265
|
+
trace = Trace.it(self).reverse
|
266
|
+
trace.pop
|
267
|
+
|
268
|
+
if depth && depth <= trace.length
|
269
|
+
trace.shift(trace.length - depth)
|
270
|
+
end
|
271
|
+
|
272
|
+
block.call(*trace)
|
273
|
+
}
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
class When < self
|
278
|
+
def initialize(promises = [])
|
279
|
+
super()
|
280
|
+
|
281
|
+
@wait = []
|
282
|
+
|
283
|
+
promises.each {|promise|
|
284
|
+
wait promise
|
285
|
+
}
|
286
|
+
end
|
287
|
+
|
288
|
+
def each(&block)
|
289
|
+
raise ArgumentError, 'no block given' unless block
|
290
|
+
|
291
|
+
self.then {|values|
|
292
|
+
values.each(&block)
|
293
|
+
}
|
294
|
+
end
|
295
|
+
|
296
|
+
def collect(&block)
|
297
|
+
raise ArgumentError, 'no block given' unless block
|
298
|
+
|
299
|
+
self.then {|values|
|
300
|
+
When.new(values.map(&block))
|
301
|
+
}
|
302
|
+
end
|
303
|
+
|
304
|
+
def inject(*args, &block)
|
305
|
+
self.then {|values|
|
306
|
+
values.reduce(*args, &block)
|
307
|
+
}
|
308
|
+
end
|
309
|
+
|
310
|
+
alias map collect
|
311
|
+
|
312
|
+
alias reduce inject
|
313
|
+
|
314
|
+
def wait(promise)
|
315
|
+
unless Promise === promise
|
316
|
+
promise = Promise.value(promise)
|
317
|
+
end
|
318
|
+
|
319
|
+
if promise.act?
|
320
|
+
promise = promise.then
|
321
|
+
end
|
322
|
+
|
323
|
+
@wait << promise
|
324
|
+
|
325
|
+
promise.always {
|
326
|
+
try if @next.any?
|
327
|
+
}
|
328
|
+
|
329
|
+
self
|
330
|
+
end
|
331
|
+
|
332
|
+
alias and wait
|
333
|
+
|
334
|
+
def >>(*)
|
335
|
+
super.tap {
|
336
|
+
try
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
def try
|
341
|
+
if @wait.all?(&:realized?)
|
342
|
+
if promise = @wait.find(&:rejected?)
|
343
|
+
reject(promise.error)
|
344
|
+
else
|
345
|
+
resolve(@wait.map(&:value))
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
data/lib/redux.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Redux
|
2
|
+
|
3
|
+
def self.create_store(reducer, preloaded_state = nil, enhancer = nil)
|
4
|
+
Redux::Store.new(reducer, preloaded_state, enhancer)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.combine_reducers(reducers)
|
8
|
+
%x{
|
9
|
+
var real_reducers;
|
10
|
+
if (typeof reducers.$class === "function") {
|
11
|
+
real_reducers = reducers.$to_n();
|
12
|
+
} else {
|
13
|
+
real_reducers = reducers;
|
14
|
+
}
|
15
|
+
return Redux.combineReducers(real_reducers);
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.apply_middleware(*middlewares)
|
20
|
+
if middlewares.size == 1
|
21
|
+
`Redux.applyMiddleware.apply(null, middlewares[0])`
|
22
|
+
else
|
23
|
+
`Redux.applyMiddleware.apply(null, middlewares)`
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.bind_action_creators(*args)
|
28
|
+
dispatch = args.pop()
|
29
|
+
`Redux.bindActionCreators(args, dispatch)`
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.compose(*functions)
|
33
|
+
`Redux.compose(functions)`
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.create_reducer(&block)
|
37
|
+
%x{
|
38
|
+
return (function(previous_state, action) {
|
39
|
+
var new_state = block.$call(Opal.Hash.$new(previous_state), Opal.Hash.$new(action));
|
40
|
+
if (typeof new_state.$class === "function") { new_state = new_state.$to_n(); }
|
41
|
+
return new_state;
|
42
|
+
});
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
data/lib/redux/store.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
module Redux
|
2
|
+
class Store
|
3
|
+
include Native::Wrapper
|
4
|
+
|
5
|
+
def self.add_middleware(middleware)
|
6
|
+
if Isomorfeus.store
|
7
|
+
`console.warning("Adding middleware after Store initialization may have side effects! Saving state and initializing new store with restored state!")`
|
8
|
+
middlewares << middleware
|
9
|
+
preloaded_state = Isomorfeus.store.get_state
|
10
|
+
init!
|
11
|
+
else
|
12
|
+
middlewares << middleware
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add_reducer(reducer)
|
17
|
+
if Isomorfeus.store
|
18
|
+
# if the store has been initalized already, add the reducer to the instance
|
19
|
+
Isomorfeus.store.add_reducer(reducer)
|
20
|
+
else
|
21
|
+
# otherwise just add it to the reducers, so that they will be used when initializing the store
|
22
|
+
preloaded_state[reducer.keys.first] = {} unless preloaded_state.has_key?(reducer.keys.first)
|
23
|
+
reducers.merge!(reducer)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.add_reducers(new_reducers)
|
28
|
+
if Isomorfeus.store
|
29
|
+
# if the store has been initalized already, add the reducer to the instance
|
30
|
+
Isomorfeus.store.add_reducers(new_reducers)
|
31
|
+
else
|
32
|
+
# otherwise just add it to the reducers, so that they will be used when initializing the store
|
33
|
+
new_reducers.each do |key, value|
|
34
|
+
add_reducer(key => value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# called from Isomorfeus.init
|
40
|
+
def self.init!
|
41
|
+
next_reducer = Redux.combine_reducers(@reducers)
|
42
|
+
if middlewares.any?
|
43
|
+
enhancer = Redux.apply_middleware(middlewares)
|
44
|
+
Redux::Store.new(next_reducer, preloaded_state, enhancer)
|
45
|
+
else
|
46
|
+
Redux::Store.new(next_reducer, preloaded_state)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.middlewares
|
51
|
+
@middlewares ||= []
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.preloaded_state_merge!(ruby_hash)
|
55
|
+
preloaded_state.merge!(ruby_hash)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.preloaded_state
|
59
|
+
@preloaded_state ||= {}
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.preloaded_state=(ruby_hash)
|
63
|
+
@preloaded_state = ruby_hash
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.reducers
|
67
|
+
@reducers ||= {}
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(reducer, preloaded_state = `null`, enhancer = `null`)
|
71
|
+
%x{
|
72
|
+
var real_preloaded_state;
|
73
|
+
if (typeof preloaded_state.$class === "function" && preloaded_state.$class() == "Hash") {
|
74
|
+
if (preloaded_state.$size() == 0) {
|
75
|
+
real_preloaded_state = null;
|
76
|
+
} else {
|
77
|
+
real_preloaded_state = preloaded_state.$to_n();
|
78
|
+
}
|
79
|
+
} else if (preloaded_state == nil) {
|
80
|
+
real_preloaded_state = null;
|
81
|
+
} else {
|
82
|
+
real_preloaded_state = preloaded_state;
|
83
|
+
}
|
84
|
+
if (enhancer && real_preloaded_state) {
|
85
|
+
this.native = Redux.createStore(reducer, real_preloaded_state, enhancer);
|
86
|
+
} else if (real_preloaded_state) {
|
87
|
+
this.native = Redux.createStore(reducer, real_preloaded_state);
|
88
|
+
} else if (enhancer) {
|
89
|
+
this.native = Redux.createStore(reducer, enhancer);
|
90
|
+
} else {
|
91
|
+
this.native = Redux.createStore(reducer);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def add_reducer(reducer)
|
97
|
+
self.class.reducers << reducer
|
98
|
+
next_reducer = Redux.combine_reducers(*self.class.reducers)
|
99
|
+
self.replace_reducer = next_reducer
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_reducers(new_reducers)
|
103
|
+
|
104
|
+
self.class.reducers.merge!(new_reducers)
|
105
|
+
|
106
|
+
next_reducer = Redux.combine_reducers(self.class.reducers)
|
107
|
+
replace_reducer(next_reducer)
|
108
|
+
end
|
109
|
+
|
110
|
+
def dispatch(action)
|
111
|
+
%x{
|
112
|
+
if (typeof action.$class === "function" && action.$class() == "Hash") {
|
113
|
+
this.native.dispatch(action.$to_n());
|
114
|
+
} else {
|
115
|
+
this.native.dispatch(action);
|
116
|
+
}
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_state
|
121
|
+
Hash.new(`this.native.getState()`)
|
122
|
+
end
|
123
|
+
|
124
|
+
def replace_reducer(next_reducer)
|
125
|
+
`this.native.replaceReducer(next_reducer)`
|
126
|
+
end
|
127
|
+
|
128
|
+
# returns function needed to unsubscribe the listener
|
129
|
+
def subscribe(&listener)
|
130
|
+
`this.native.subscribe(function() { return listener$.call(); })`
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: isomorfeus-redux
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 4.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Biedermann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: opal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.11.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.12.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.11.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.12.0
|
33
|
+
description: Use a global store and write reducers for it in Opal Ruby.
|
34
|
+
email:
|
35
|
+
- jan@kursator.com
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- Gemfile
|
41
|
+
- README.md
|
42
|
+
- isomorfeus-redux.gemspec
|
43
|
+
- lib/isomorfeus-redux.rb
|
44
|
+
- lib/isomorfeus/promise.rb
|
45
|
+
- lib/redux.rb
|
46
|
+
- lib/redux/store.rb
|
47
|
+
- lib/redux/version.rb
|
48
|
+
homepage: http://isomorfeus.com
|
49
|
+
licenses:
|
50
|
+
- MIT
|
51
|
+
metadata: {}
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 2.7.6
|
69
|
+
signing_key:
|
70
|
+
specification_version: 4
|
71
|
+
summary: Redux for Opal Ruby.
|
72
|
+
test_files: []
|