isomorfeus-redux 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|