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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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