hyper-store 1.0.alpha1.8 → 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.
@@ -1,36 +0,0 @@
1
- module Hyperstack
2
- module Internal
3
- module Store
4
- module ClassMethods
5
- attr_accessor :__shared_states, :__class_states, :__instance_states
6
-
7
- def state(*args, &block)
8
- # If we're passing in any arguments then we are calling the macro to define a state
9
- if args.count > 0
10
- singleton_class.__state_wrapper.class_state_wrapper
11
- .define_state_methods(self, *args, &block)
12
- # Otherwise we are just accessing it
13
- else
14
- @state ||= singleton_class.__state_wrapper.class_state_wrapper.new(self)
15
- end
16
- end
17
-
18
- def mutate
19
- @mutate ||= singleton_class.__state_wrapper.class_mutator_wrapper.new(self)
20
- end
21
-
22
- def __shared_states
23
- @__shared_states ||= []
24
- end
25
-
26
- def __class_states
27
- @__class_states ||= []
28
- end
29
-
30
- def __instance_states
31
- @__instance_states ||= []
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,41 +0,0 @@
1
- module Hyperstack
2
- module Internal
3
- module Store
4
- module DispatchReceiver
5
-
6
- attr_accessor :params
7
-
8
- def receives(*args, &block)
9
- # Format the callback to be Proc or Nil
10
- callback = format_callback(args)
11
-
12
- if args.empty?
13
- message = 'At least one operation must be passed in to the \'receives\' macro'
14
- raise Legacy::Store::InvalidOperationError, message
15
- end
16
-
17
- # Loop through receivers and call callback and block on dispatch
18
- args.each do |operation|
19
- operation.on_dispatch do |params|
20
- @params = params
21
-
22
- callback.call if callback
23
- yield params if block
24
- end
25
- end
26
- end
27
-
28
- private
29
-
30
- def format_callback(args)
31
- if args.last.is_a?(Symbol)
32
- method_name = args.pop
33
- -> { send(:"#{method_name}") }
34
- elsif args.last.is_a?(Proc)
35
- args.pop
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,45 +0,0 @@
1
- module Hyperstack
2
- module Internal
3
- module Store
4
- module InstanceMethods
5
- def init_store
6
- return if @__hyperstack_store_initialized
7
- @__hyperstack_store_initialized = true
8
- self.class.__instance_states.each do |instance_state|
9
- # If the scope is shared then we initialize at the class level
10
- next if instance_state[1][:scope] == :shared
11
-
12
- # TODO: Figure out exactly how we're going to handle passing in procs and blocks together
13
- # But for now...just do the proc first then the block
14
-
15
- # First initialize value from initializer Proc
16
- proc_value = initializer_value(instance_state[1][:initializer])
17
- mutate.__send__(:"#{instance_state[0]}", proc_value)
18
-
19
- # Then call the block if a block is passed
20
- next unless instance_state[1][:block]
21
-
22
- block_value = instance_eval(&instance_state[1][:block])
23
- mutate.__send__(:"#{instance_state[0]}", block_value)
24
- end
25
- end
26
-
27
- def state
28
- @state ||= self.class.singleton_class.__state_wrapper.instance_state_wrapper.new(self)
29
- end
30
-
31
- def mutate
32
- @mutate ||= self.class.singleton_class.__state_wrapper.instance_mutator_wrapper.new(self)
33
- end
34
-
35
- private
36
-
37
- def initializer_value(initializer)
38
- # We gotta check the arity because a Proc passed in directly from initializer has no args,
39
- # but if we created one then we might have wanted self
40
- initializer.arity > 0 ? initializer.call(self) : initializer.call
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,84 +0,0 @@
1
- module Hyperstack
2
- module Internal
3
- module Store
4
- class MutatorWrapper < BaseStoreClass # < BasicObject
5
-
6
- class << self
7
- def add_method(klass, method_name, opts = {})
8
- define_method(:"#{method_name}") do |*args|
9
- from = opts[:scope] == :shared ? klass.state.__from__ : __from__
10
- from.init_store if from.respond_to? :init_store
11
- current_value = State::Variable.get(from, method_name.to_s)
12
-
13
- if args.count > 0
14
- State::Variable.set(from, method_name.to_s, args[0])
15
- current_value
16
- else
17
- State::Variable.set(from, method_name.to_s, current_value)
18
- Observable.new(current_value) do |update|
19
- State::Variable.set(from, method_name.to_s, update)
20
- end
21
- end
22
- end
23
-
24
- initialize_values(klass, method_name, opts) if initialize_values?(opts)
25
- end
26
-
27
- def initialize_values?(opts)
28
- [:class, :shared].include?(opts[:scope]) && (opts[:initializer] || opts[:block])
29
- end
30
-
31
- def initialize_values(klass, name, opts)
32
- initializer = initializer_proc(opts[:initializer], klass, name) if opts[:initializer]
33
-
34
- if initializer && opts[:block]
35
- klass.receives(Hyperstack::Application::Boot, initializer) do
36
- klass.mutate.__send__(:"#{name}", opts[:block].call)
37
- end
38
- elsif initializer
39
- klass.receives(Hyperstack::Application::Boot, initializer)
40
- elsif opts[:block]
41
- klass.receives(Hyperstack::Application::Boot) do
42
- klass.mutate.__send__(:"#{name}", opts[:block].call)
43
- end
44
- end
45
- end
46
-
47
- private
48
-
49
- def initializer_proc(initializer, klass, name)
50
- # We gotta check the arity because a Proc passed in directly from initializer has no args,
51
- # but if we created one then we might have wanted the class
52
- if initializer.arity > 0
53
- -> { klass.mutate.__send__(:"#{name}", initializer.call(klass)) }
54
- else
55
- -> { klass.mutate.__send__(:"#{name}", initializer.call) }
56
- end
57
- end
58
- end
59
-
60
- attr_accessor :__from__
61
-
62
- def self.new(from)
63
- instance = allocate
64
- instance.__from__ = from
65
- instance
66
- end
67
-
68
- def []=(name, value)
69
- __send__(name, value)
70
- end
71
-
72
- def [](name)
73
- __send__(name)
74
- end
75
-
76
- # Any method_missing call will create a state and accessor with that name
77
- def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissing
78
- (class << self; self end).add_method(nil, name)
79
- __send__(name, *args, &block)
80
- end
81
- end
82
- end
83
- end
84
- end
@@ -1,33 +0,0 @@
1
- module Hyperstack
2
- module Internal
3
- module Store
4
- class Observable
5
- def initialize(value, on_change = nil, &block)
6
- @value = value
7
- @on_change = on_change || block
8
- end
9
-
10
- def method_missing(method_sym, *args, &block)
11
- @value.send(method_sym, *args, &block).tap { |result| @on_change.call @value }
12
- end
13
-
14
- def respond_to?(method, *args)
15
- if [:call, :to_proc].include? method
16
- true
17
- else
18
- @value.respond_to? method, *args
19
- end
20
- end
21
-
22
- def call(new_value)
23
- @on_change.call new_value
24
- @value = new_value
25
- end
26
-
27
- def to_proc
28
- lambda { |arg = @value| @on_change.call arg }
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,116 +0,0 @@
1
- module Hyperstack
2
- module Internal
3
- module Store
4
- class StateWrapper < BaseStoreClass
5
- extend ArgumentValidator
6
-
7
- class << self
8
- attr_reader :instance_state_wrapper, :class_state_wrapper,
9
- :instance_mutator_wrapper, :class_mutator_wrapper,
10
- :wrappers
11
-
12
- def inherited(subclass)
13
- subclass.add_class_instance_vars(subclass) if self == StateWrapper
14
- end
15
-
16
- def add_class_instance_vars(subclass)
17
- @shared_state_wrapper = subclass
18
- @instance_state_wrapper = Class.new(@shared_state_wrapper)
19
- @class_state_wrapper = Class.new(@shared_state_wrapper)
20
-
21
- @shared_mutator_wrapper = Class.new(MutatorWrapper)
22
- @instance_mutator_wrapper = Class.new(@shared_mutator_wrapper)
23
- @class_mutator_wrapper = Class.new(@shared_mutator_wrapper)
24
-
25
- @wrappers = [@instance_state_wrapper, @instance_mutator_wrapper,
26
- @class_state_wrapper, @class_mutator_wrapper]
27
- end
28
-
29
- def define_state_methods(klass, *args, &block)
30
- return self if args.empty?
31
-
32
- name, opts = validate_args!(klass, *args, &block)
33
-
34
- add_readers(klass, name, opts)
35
- klass.singleton_class.state.add_error_methods(name, opts)
36
- klass.singleton_class.state.add_methods(klass, name, opts)
37
- klass.singleton_class.state.remove_methods(name, opts)
38
- klass.send(:"__#{opts[:scope]}_states") << [name, opts]
39
- end
40
-
41
- def add_readers(klass, name, opts)
42
- return unless opts[:reader]
43
-
44
- if [:instance, :shared].include?(opts[:scope])
45
- klass.class_eval do
46
- define_method(:"#{opts[:reader]}") { state.__send__(:"#{name}") }
47
- end
48
- end
49
-
50
- if [:class, :shared].include?(opts[:scope])
51
- klass.define_singleton_method(:"#{opts[:reader]}") { state.__send__(:"#{name}") }
52
- end
53
- end
54
-
55
- def add_error_methods(name, opts)
56
- return if opts[:scope] == :shared
57
-
58
- [@shared_state_wrapper, @shared_mutator_wrapper].each do |klass|
59
- klass.define_singleton_method(:"#{name}") do
60
- 'nope!'
61
- end
62
- end
63
- end
64
-
65
- def add_methods(klass, name, opts)
66
- instance_variable_get("@#{opts[:scope]}_state_wrapper").add_method(klass, name, opts)
67
- instance_variable_get("@#{opts[:scope]}_mutator_wrapper").add_method(klass, name, opts)
68
- end
69
-
70
- def add_method(klass, method_name, opts = {})
71
- define_method(:"#{method_name}") do
72
- from = opts[:scope] == :shared ? klass.state.__from__ : @__from__
73
- from.init_store if from.respond_to? :init_store
74
- State::Variable.get(from, method_name.to_s)
75
- end
76
- end
77
-
78
- def remove_methods(name, opts)
79
- return unless opts[:scope] == :shared
80
-
81
- wrappers.each do |wrapper|
82
- wrapper.send(:remove_method, :"#{name}") if wrapper.respond_to?(:"#{name}")
83
- end
84
- end
85
-
86
- def default_scope(klass)
87
- if self == klass.singleton_class.__state_wrapper.class_state_wrapper
88
- :instance
89
- else
90
- :class
91
- end
92
- end
93
- end
94
-
95
- attr_accessor :__from__
96
-
97
- def self.new(from)
98
- instance = allocate
99
- instance.__from__ = from
100
- instance
101
- end
102
-
103
- def [](name)
104
- __send__(name)
105
- end
106
-
107
- # Any method_missing call will create a state and accessor with that name
108
- def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissing
109
- $method_missing = [name, *args]
110
- (class << self; self end).add_method(nil, name) #(class << self; self end).superclass.add_method(nil, name)
111
- __send__(name, *args, &block)
112
- end
113
- end
114
- end
115
- end
116
- end
@@ -1,93 +0,0 @@
1
- module Hyperstack
2
- module Internal
3
- module Store
4
- class StateWrapper < BaseStoreClass
5
- module ArgumentValidator
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 Legacy::Store::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
92
- end
93
- end