hyper-store 1.0.alpha1.5 → 1.0.0.lap28

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,91 @@
1
+ module HyperStore
2
+ class StateWrapper < BaseStoreClass
3
+ module ArgumentValidator
4
+ class InvalidOptionError < StandardError; end
5
+
6
+ def validate_args!(klass, *args, &block)
7
+ name, initial_value, opts = parse_arguments(*args, &block)
8
+
9
+ opts[:scope] ||= default_scope(klass)
10
+ opts[:initializer] = validate_initializer(initial_value, klass, opts)
11
+ opts[:block] = block if block
12
+
13
+ if opts[:reader]
14
+ opts[:reader] = opts[:reader] == true ? name : opts[:reader]
15
+ end
16
+
17
+ [name, opts]
18
+ end
19
+
20
+ private
21
+
22
+ def invalid_option(message)
23
+ raise InvalidOptionError, message
24
+ end
25
+
26
+ # Parses the arguments given to get the name, initial_value (if any), and options
27
+ def parse_arguments(*args)
28
+ # If the only argument is a hash, the first key => value is name => inital_value
29
+ if args.first.is_a?(Hash)
30
+ # If the first key passed in is not the name, raise an error
31
+ if [:reader, :initializer, :scope].include?(args.first.keys.first.to_sym)
32
+ message = 'The name of the state must be specified first as '\
33
+ "either 'state :name' or 'state name: nil'"
34
+ invalid_option(message)
35
+ end
36
+
37
+ name, initial_value = args[0].shift
38
+ # Otherwise just the name is passed in by itself first
39
+ else
40
+ name = args.shift
41
+ end
42
+
43
+ # [name, initial_value (can be nil), args (if nil then return an empty hash)]
44
+ [name, initial_value, args[0] || {}]
45
+ end
46
+
47
+ # Converts the initialize option to a Proc
48
+ def validate_initializer(initial_value, klass, opts) # rubocop:disable Metrics/MethodLength
49
+ # If we pass in the name as a hash with a value ex: state foo: :bar,
50
+ # we just put that value inside a Proc and return that
51
+ if initial_value != nil
52
+ dup_or_return_intial_value(initial_value)
53
+ # If we pass in the initialize option
54
+ elsif opts[:initializer]
55
+ # If it's a Symbol we convert to to a Proc that calls the method on the instance
56
+ if [Symbol, String].include?(opts[:initializer].class)
57
+ method_name = opts[:initializer]
58
+ if [:class, :shared].include?(opts[:scope])
59
+ -> { klass.send(:"#{method_name}") }
60
+ else
61
+ ->(instance) { instance.send(:"#{method_name}") }
62
+ end
63
+ # If it is already a Proc we do nothing and just return what was given
64
+ elsif opts[:initializer].is_a?(Proc)
65
+ opts[:initializer]
66
+ # If it's not a Proc or a String we raise an error and return an empty Proc
67
+ else
68
+ invalid_option("'state' option 'initialize' must either be a Symbol or a Proc")
69
+ -> {}
70
+ end
71
+ # Otherwise if it's not specified we just return an empty Proc
72
+ else
73
+ -> {}
74
+ end
75
+ end
76
+
77
+ # Dup the initial value if possible, otherwise just return it
78
+ # Ruby has no nice way of doing this...
79
+ def dup_or_return_intial_value(value)
80
+ value =
81
+ begin
82
+ value.dup
83
+ rescue
84
+ value
85
+ end
86
+
87
+ -> { value }
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module HyperStore
2
+ VERSION = '1.0.0.lap28'
3
+ end
@@ -0,0 +1,34 @@
1
+ module Hyperloop
2
+ # insure at least a stub of operation is defined. If
3
+ # Hyperloop::Operation is already loaded it will have
4
+ # defined these.
5
+ class Operation
6
+ class << self
7
+ def on_dispatch(&block)
8
+ receivers << block
9
+ end unless method_defined? :on_dispatch
10
+
11
+ def receivers
12
+ # use the force: true option so that system code needing to receive
13
+ # boot will NOT be erased on the next Hyperloop::Context.reset!
14
+ Hyperloop::Context.set_var(self, :@receivers, force: true) { [] }
15
+ end unless method_defined? :receivers
16
+ end
17
+ end
18
+ class Application
19
+ class Boot < Operation
20
+ class ReactDummyParams
21
+ attr_reader :context
22
+ def initialize(context)
23
+ @context = context
24
+ end
25
+ end
26
+ def self.run(context: nil)
27
+ params = ReactDummyParams.new(context)
28
+ receivers.each do |receiver|
29
+ receiver.call params
30
+ end
31
+ end
32
+ end unless defined? Boot
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ module Hyperloop
2
+ class Store
3
+ class << self
4
+ def inherited(child)
5
+ child.include(Mixin)
6
+ end
7
+ end
8
+ def initialize
9
+ init_store
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module Hyperloop
2
+ class Store
3
+ module Mixin
4
+ class << self
5
+ def included(base)
6
+ base.include(HyperStore::InstanceMethods)
7
+ base.extend(HyperStore::ClassMethods)
8
+ base.extend(HyperStore::DispatchReceiver)
9
+
10
+ base.singleton_class.define_singleton_method(:__state_wrapper) do
11
+ @__state_wrapper ||= Class.new(HyperStore::StateWrapper)
12
+ end
13
+
14
+ base.singleton_class.define_singleton_method(:state) do |*args, &block|
15
+ __state_wrapper.define_state_methods(base, *args, &block)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ module React
2
+ class Observable
3
+ def initialize(value, on_change = nil, &block)
4
+ @value = value
5
+ @on_change = on_change || block
6
+ end
7
+
8
+ def method_missing(method_sym, *args, &block)
9
+ @value.send(method_sym, *args, &block).tap { |result| @on_change.call @value }
10
+ end
11
+
12
+ def respond_to?(method, *args)
13
+ if [:call, :to_proc].include? method
14
+ true
15
+ else
16
+ @value.respond_to? method, *args
17
+ end
18
+ end
19
+
20
+ def call(new_value)
21
+ @on_change.call new_value
22
+ @value = new_value
23
+ end
24
+
25
+ def to_proc
26
+ lambda { |arg = @value| @on_change.call arg }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,143 @@
1
+ module React
2
+ class State
3
+
4
+ ALWAYS_UPDATE_STATE_AFTER_RENDER = Hyperloop.on_client? # if on server then we don't wait to update the state
5
+ @rendering_level = 0
6
+
7
+ class << self
8
+ attr_reader :current_observer
9
+
10
+ def has_observers?(object, name)
11
+ !observers_by_name[object][name].empty?
12
+ end
13
+
14
+ def bulk_update
15
+ saved_bulk_update_flag = @bulk_update_flag
16
+ @bulk_update_flag = true
17
+ yield
18
+ ensure
19
+ @bulk_update_flag = saved_bulk_update_flag
20
+ end
21
+
22
+ def set_state2(object, name, value, updates, exclusions = nil)
23
+ # set object's name state to value, tell all observers it has changed.
24
+ # Observers must implement update_react_js_state
25
+ object_needs_notification = object.respond_to?(:update_react_js_state)
26
+ observers_by_name[object][name].dup.each do |observer|
27
+ next if exclusions && exclusions.include?(observer)
28
+ updates[observer] += [object, name, value]
29
+ object_needs_notification = false if object == observer
30
+ end
31
+ updates[object] += [nil, name, value] if object_needs_notification
32
+ end
33
+
34
+ def initialize_states(object, initial_values) # initialize objects' name/value pairs
35
+ states[object].merge!(initial_values || {})
36
+ end
37
+
38
+ def get_state(object, name, current_observer = @current_observer)
39
+ # get current value of name for object, remember that the current object depends on this state,
40
+ # current observer can be overriden with last param
41
+ if current_observer && !new_observers[current_observer][object].include?(name)
42
+ new_observers[current_observer][object] << name
43
+ end
44
+ if @delayed_updates && @delayed_updates[object][name]
45
+ @delayed_updates[object][name][1] << current_observer
46
+ end
47
+ states[object][name]
48
+ end
49
+
50
+ # ReactDOM.unstable_batchedUpdates does not seem to improve things here, ill leave it here commented for reference
51
+ # and later investigation
52
+ #if `ReactDOM.unstable_batchedUpdates !== undefined`
53
+ # %x{
54
+ # ReactDOM.unstable_batchedUpdates(function(){
55
+ # #{updates.each { |observer, args| observer.update_react_js_state(*args) }}
56
+ # });
57
+ # }
58
+ #else # run the other one
59
+ def set_state(object, name, value, delay=ALWAYS_UPDATE_STATE_AFTER_RENDER)
60
+ states[object][name] = value
61
+ delay = false if object.respond_to?(:set_state_synchronously?) && object.set_state_synchronously?
62
+ if delay || @bulk_update_flag
63
+ @delayed_updates ||= Hash.new { |h, k| h[k] = {} }
64
+ @delayed_updates[object][name] = [value, Set.new]
65
+ @delayed_updater ||= after(0.001) do
66
+ delayed_updates = @delayed_updates
67
+ @delayed_updates = Hash.new { |h, k| h[k] = {} } # could this be nil???
68
+ @delayed_updater = nil
69
+ updates = Hash.new { |hash, key| hash[key] = Array.new }
70
+ delayed_updates.each do |object, name_hash|
71
+ name_hash.each do |name, value_and_set|
72
+ set_state2(object, name, value_and_set[0], updates, value_and_set[1])
73
+ end
74
+ end
75
+ updates.each { |observer, args| observer.update_react_js_state(*args) }
76
+ end
77
+ elsif @rendering_level == 0
78
+ updates = Hash.new { |hash, key| hash[key] = Array.new }
79
+ set_state2(object, name, value, updates)
80
+ updates.each { |observer, args| observer.update_react_js_state(*args) }
81
+ end
82
+ value
83
+ end
84
+
85
+ def will_be_observing?(object, name, current_observer)
86
+ current_observer && new_observers[current_observer][object].include?(name)
87
+ end
88
+
89
+ def is_observing?(object, name, current_observer)
90
+ current_observer && observers_by_name[object][name].include?(current_observer)
91
+ end
92
+
93
+ def update_states_to_observe(current_observer = @current_observer) # should be called after the last after_render callback, currently called after components render method
94
+ raise "update_states_to_observer called outside of watch block" unless current_observer
95
+ current_observers[current_observer].each do |object, names|
96
+ names.each do |name|
97
+ observers_by_name[object][name].delete(current_observer)
98
+ end
99
+ end
100
+ observers = current_observers[current_observer] = new_observers[current_observer]
101
+ new_observers.delete(current_observer)
102
+ observers.each do |object, names|
103
+ names.each do |name|
104
+ observers_by_name[object][name] << current_observer
105
+ end
106
+ end
107
+ end
108
+
109
+ def remove # call after component is unmounted
110
+ raise "remove called outside of watch block" unless @current_observer
111
+ current_observers[@current_observer].each do |object, names|
112
+ names.each do |name|
113
+ observers_by_name[object][name].delete(@current_observer)
114
+ end
115
+ end
116
+ current_observers.delete(@current_observer)
117
+ end
118
+
119
+ def set_state_context_to(observer, rendering = nil) # wrap all execution that may set or get states in a block so we know which observer is executing
120
+ saved_current_observer = @current_observer
121
+ @current_observer = observer
122
+ @rendering_level += 1 if rendering
123
+ return_value = yield
124
+ return_value
125
+ ensure
126
+ @current_observer = saved_current_observer
127
+ @rendering_level -= 1 if rendering
128
+ return_value
129
+ end
130
+
131
+ def states
132
+ @states ||= Hash.new { |h, k| h[k] = {} }
133
+ end
134
+
135
+ [:new_observers, :current_observers, :observers_by_name].each do |method_name|
136
+ define_method(method_name) do
137
+ instance_variable_get("@#{method_name}") ||
138
+ instance_variable_set("@#{method_name}", Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = [] } })
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyper-store
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.alpha1.5
4
+ version: 1.0.0.lap28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitch VanDuyn
@@ -10,36 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2019-06-19 00:00:00.000000000 Z
13
+ date: 2018-05-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: hyperstack-config
16
+ name: hyperloop-config
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.0.alpha1.5
21
+ version: 1.0.0.lap28
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - '='
27
27
  - !ruby/object:Gem::Version
28
- version: 1.0.alpha1.5
29
- - !ruby/object:Gem::Dependency
30
- name: hyper-state
31
- requirement: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - '='
34
- - !ruby/object:Gem::Version
35
- version: 1.0.alpha1.5
36
- type: :runtime
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - '='
41
- - !ruby/object:Gem::Version
42
- version: 1.0.alpha1.5
28
+ version: 1.0.0.lap28
43
29
  - !ruby/object:Gem::Dependency
44
30
  name: opal
45
31
  requirement: !ruby/object:Gem::Requirement
@@ -62,26 +48,6 @@ dependencies:
62
48
  version: 0.12.0
63
49
  - !ruby/object:Gem::Dependency
64
50
  name: bundler
65
- requirement: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: 1.17.3
70
- - - "<"
71
- - !ruby/object:Gem::Version
72
- version: '2.1'
73
- type: :development
74
- prerelease: false
75
- version_requirements: !ruby/object:Gem::Requirement
76
- requirements:
77
- - - ">="
78
- - !ruby/object:Gem::Version
79
- version: 1.17.3
80
- - - "<"
81
- - !ruby/object:Gem::Version
82
- version: '2.1'
83
- - !ruby/object:Gem::Dependency
84
- name: chromedriver-helper
85
51
  requirement: !ruby/object:Gem::Requirement
86
52
  requirements:
87
53
  - - ">="
@@ -95,33 +61,33 @@ dependencies:
95
61
  - !ruby/object:Gem::Version
96
62
  version: '0'
97
63
  - !ruby/object:Gem::Dependency
98
- name: hyper-component
64
+ name: hyper-react
99
65
  requirement: !ruby/object:Gem::Requirement
100
66
  requirements:
101
67
  - - '='
102
68
  - !ruby/object:Gem::Version
103
- version: 1.0.alpha1.5
69
+ version: 1.0.0.lap28
104
70
  type: :development
105
71
  prerelease: false
106
72
  version_requirements: !ruby/object:Gem::Requirement
107
73
  requirements:
108
74
  - - '='
109
75
  - !ruby/object:Gem::Version
110
- version: 1.0.alpha1.5
76
+ version: 1.0.0.lap28
111
77
  - !ruby/object:Gem::Dependency
112
78
  name: hyper-spec
113
79
  requirement: !ruby/object:Gem::Requirement
114
80
  requirements:
115
81
  - - '='
116
82
  - !ruby/object:Gem::Version
117
- version: 1.0.alpha1.5
83
+ version: 1.0.0.lap28
118
84
  type: :development
119
85
  prerelease: false
120
86
  version_requirements: !ruby/object:Gem::Requirement
121
87
  requirements:
122
88
  - - '='
123
89
  - !ruby/object:Gem::Version
124
- version: 1.0.alpha1.5
90
+ version: 1.0.0.lap28
125
91
  - !ruby/object:Gem::Dependency
126
92
  name: listen
127
93
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +108,14 @@ dependencies:
142
108
  requirements:
143
109
  - - "~>"
144
110
  - !ruby/object:Gem::Version
145
- version: 0.2.4
111
+ version: 0.1.15
146
112
  type: :development
147
113
  prerelease: false
148
114
  version_requirements: !ruby/object:Gem::Requirement
149
115
  requirements:
150
116
  - - "~>"
151
117
  - !ruby/object:Gem::Version
152
- version: 0.2.4
118
+ version: 0.1.15
153
119
  - !ruby/object:Gem::Dependency
154
120
  name: opal-browser
155
121
  requirement: !ruby/object:Gem::Requirement
@@ -192,34 +158,6 @@ dependencies:
192
158
  - - ">="
193
159
  - !ruby/object:Gem::Version
194
160
  version: '0'
195
- - !ruby/object:Gem::Dependency
196
- name: pry-rescue
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - ">="
200
- - !ruby/object:Gem::Version
201
- version: '0'
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - ">="
207
- - !ruby/object:Gem::Version
208
- version: '0'
209
- - !ruby/object:Gem::Dependency
210
- name: puma
211
- requirement: !ruby/object:Gem::Requirement
212
- requirements:
213
- - - ">="
214
- - !ruby/object:Gem::Version
215
- version: '0'
216
- type: :development
217
- prerelease: false
218
- version_requirements: !ruby/object:Gem::Requirement
219
- requirements:
220
- - - ">="
221
- - !ruby/object:Gem::Version
222
- version: '0'
223
161
  - !ruby/object:Gem::Dependency
224
162
  name: rails
225
163
  requirement: !ruby/object:Gem::Requirement
@@ -282,20 +220,6 @@ dependencies:
282
220
  - - "~>"
283
221
  - !ruby/object:Gem::Version
284
222
  version: 3.7.0
285
- - !ruby/object:Gem::Dependency
286
- name: rspec-rails
287
- requirement: !ruby/object:Gem::Requirement
288
- requirements:
289
- - - ">="
290
- - !ruby/object:Gem::Version
291
- version: '0'
292
- type: :development
293
- prerelease: false
294
- version_requirements: !ruby/object:Gem::Requirement
295
- requirements:
296
- - - ">="
297
- - !ruby/object:Gem::Version
298
- version: '0'
299
223
  - !ruby/object:Gem::Dependency
300
224
  name: rspec-steps
301
225
  requirement: !ruby/object:Gem::Requirement
@@ -328,30 +252,16 @@ dependencies:
328
252
  name: sqlite3
329
253
  requirement: !ruby/object:Gem::Requirement
330
254
  requirements:
331
- - - "~>"
332
- - !ruby/object:Gem::Version
333
- version: 1.3.6
334
- type: :development
335
- prerelease: false
336
- version_requirements: !ruby/object:Gem::Requirement
337
- requirements:
338
- - - "~>"
339
- - !ruby/object:Gem::Version
340
- version: 1.3.6
341
- - !ruby/object:Gem::Dependency
342
- name: timecop
343
- requirement: !ruby/object:Gem::Requirement
344
- requirements:
345
- - - "~>"
255
+ - - ">="
346
256
  - !ruby/object:Gem::Version
347
- version: 0.8.1
257
+ version: '0'
348
258
  type: :development
349
259
  prerelease: false
350
260
  version_requirements: !ruby/object:Gem::Requirement
351
261
  requirements:
352
- - - "~>"
262
+ - - ">="
353
263
  - !ruby/object:Gem::Version
354
- version: 0.8.1
264
+ version: '0'
355
265
  description:
356
266
  email:
357
267
  - mitch@catprint.com
@@ -361,22 +271,31 @@ extensions: []
361
271
  extra_rdoc_files: []
362
272
  files:
363
273
  - ".gitignore"
274
+ - ".rubocop.yml"
364
275
  - ".travis.yml"
276
+ - CODE_OF_CONDUCT.md
277
+ - DOCS.md
365
278
  - Gemfile
279
+ - LICENSE.txt
280
+ - README.md
366
281
  - Rakefile
367
282
  - bin/console
368
283
  - bin/setup
284
+ - dciy.toml
369
285
  - hyper-store.gemspec
370
286
  - lib/hyper-store.rb
371
- - lib/hyperstack/internal/store/class_methods.rb
372
- - lib/hyperstack/internal/store/dispatch_receiver.rb
373
- - lib/hyperstack/internal/store/instance_methods.rb
374
- - lib/hyperstack/internal/store/mutator_wrapper.rb
375
- - lib/hyperstack/internal/store/observable.rb
376
- - lib/hyperstack/internal/store/state_wrapper.rb
377
- - lib/hyperstack/internal/store/state_wrapper/argument_validator.rb
378
- - lib/hyperstack/legacy/store.rb
379
- - lib/hyperstack/legacy/store/version.rb
287
+ - lib/hyper-store/class_methods.rb
288
+ - lib/hyper-store/dispatch_receiver.rb
289
+ - lib/hyper-store/instance_methods.rb
290
+ - lib/hyper-store/mutator_wrapper.rb
291
+ - lib/hyper-store/state_wrapper.rb
292
+ - lib/hyper-store/state_wrapper/argument_validator.rb
293
+ - lib/hyper-store/version.rb
294
+ - lib/hyperloop/application/boot.rb
295
+ - lib/hyperloop/store.rb
296
+ - lib/hyperloop/store/mixin.rb
297
+ - lib/react/observable.rb
298
+ - lib/react/state.rb
380
299
  homepage: https://ruby-hyperloop.org
381
300
  licenses:
382
301
  - MIT
@@ -396,7 +315,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
396
315
  - !ruby/object:Gem::Version
397
316
  version: 1.3.1
398
317
  requirements: []
399
- rubygems_version: 3.0.4
318
+ rubyforge_project:
319
+ rubygems_version: 2.7.6
400
320
  signing_key:
401
321
  specification_version: 4
402
322
  summary: Flux Stores and more for Hyperloop