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

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.
@@ -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