glimmer 2.2.2 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -30,9 +30,9 @@ module Glimmer
30
30
 
31
31
  attr_reader :binding_options, :property_name_expression
32
32
 
33
- def initialize(base_model, property_name_expression, binding_options = nil)
34
- @base_model = base_model
35
- @property_name_expression = property_name_expression
33
+ def initialize(*args)
34
+ binding_options = args.pop if args.size > 1 && args.last.is_a?(Hash)
35
+ @base_model, @property_name_expression = args
36
36
  @binding_options = binding_options || Concurrent::Hash.new
37
37
  if computed?
38
38
  @computed_model_bindings = Concurrent::Array.new(computed_by.map do |computed_by_property_expression|
@@ -91,7 +91,7 @@ module Glimmer
91
91
  end
92
92
 
93
93
  def nested_property?
94
- property_name_expression.match(/[.\[]/)
94
+ property_name_expression.to_s.match(/[.\[]/)
95
95
  end
96
96
 
97
97
  def computed?
@@ -101,6 +101,10 @@ module Glimmer
101
101
  def computed_by
102
102
  Concurrent::Array.new([@binding_options[:computed_by]].flatten.compact)
103
103
  end
104
+
105
+ def observation_options
106
+ @binding_options.slice(:recursive)
107
+ end
104
108
 
105
109
  def nested_property_observers_for(observer)
106
110
  @nested_property_observers_collection ||= Concurrent::Hash.new
@@ -121,7 +125,7 @@ module Glimmer
121
125
  @nested_property_observers_collection[observer]
122
126
  end
123
127
 
124
- def add_observer(observer)
128
+ def add_observer(observer, extra_options = {})
125
129
  if computed?
126
130
  add_computed_observers(observer)
127
131
  elsif nested_property?
@@ -133,19 +137,20 @@ module Glimmer
133
137
  apply_processor(@binding_options[:after_read], converted_value)
134
138
  end
135
139
  end
136
- observer_registration = model_binding_observer.observe(model, property_name)
140
+ observer_registration = model_binding_observer.observe(*[model, property_name, observation_options].compact)
137
141
  my_registration = observer.registration_for(self)
138
142
  observer.add_dependent(my_registration => observer_registration)
139
143
  end
140
144
  end
141
145
 
142
- def remove_observer(observer)
146
+ def remove_observer(observer, extra_options = {})
143
147
  if computed?
144
148
  @computed_model_bindings.each do |computed_model_binding|
145
149
  computed_observer_for(observer).unobserve(computed_model_binding)
146
150
  end
147
151
  @computed_observer_collection.delete(observer)
148
152
  elsif nested_property?
153
+ # No need to call remove_nested_observers(observer) (cleanup happens automatically indirectly when invoked through observer.unobserve(model_binding))
149
154
  nested_property_observers_for(observer).clear
150
155
  else
151
156
  observer.unobserve(model, property_name)
@@ -167,7 +172,7 @@ module Glimmer
167
172
 
168
173
  def add_computed_observers(observer)
169
174
  @computed_model_bindings.each do |computed_model_binding|
170
- observer_registration = computed_observer_for(observer).observe(computed_model_binding)
175
+ observer_registration = computed_observer_for(observer).observe(computed_model_binding, observation_options)
171
176
  my_registration = observer.registration_for(self)
172
177
  observer.add_dependent(my_registration => observer_registration)
173
178
  end
@@ -191,17 +196,17 @@ module Glimmer
191
196
  parent_property_name = nil if parent_property_name.to_s.start_with?('[')
192
197
  unless model.nil?
193
198
  # TODO figure out a way to deal with this more uniformly
194
- observer_registration = property_indexed?(property_name) ? nested_property_observer.observe(model) : nested_property_observer.observe(model, property_name)
195
- parent_registration = parent_observer.registration_for(parent_model, parent_property_name)
199
+ observer_registration = property_indexed?(property_name) ? nested_property_observer.observe(model, observation_options) : nested_property_observer.observe(model, property_name, observation_options)
200
+ parent_registration = parent_observer.registration_for(parent_model, *[parent_property_name].compact)
196
201
  parent_observer.add_dependent(parent_registration => observer_registration)
197
202
  end
198
203
  end
199
204
  end
200
-
205
+
201
206
  def call(value, *extra_args)
202
207
  return if model.nil?
203
208
  converted_value = value
204
- invoke_property_writer(model, "#{property_name}=", converted_value) unless converted_value == evaluate_property
209
+ invoke_property_writer(model, model.is_a?(Hash) ? property_name : "#{property_name}=", converted_value) unless converted_value == evaluate_property || property_name.nil?
205
210
  end
206
211
 
207
212
  def evaluate_property
@@ -258,11 +263,18 @@ module Glimmer
258
263
  property_argument = property_argument.to_i if property_argument.match(/\d+/)
259
264
  object.send(property_method, property_argument)
260
265
  else
261
- object.send(property_expression)
266
+ if property_expression.nil?
267
+ object
268
+ elsif object.is_a?(Hash)
269
+ object[property_expression]
270
+ else
271
+ object.send(property_expression)
272
+ end
262
273
  end
263
274
  end
264
275
 
265
276
  def invoke_property_writer(object, property_expression, value)
277
+ return if property_expression.nil?
266
278
  raise "Cannot invoke `#{property_expression}` because ModelBinding#binding_options[:read_only]=true" if @binding_options[:read_only]
267
279
  apply_processor(@binding_options[:before_write], value)
268
280
  converted_value = convert_on_write(value)
@@ -272,7 +284,11 @@ module Glimmer
272
284
  property_argument = property_argument.to_i if property_argument.match(/\d+/)
273
285
  object.send(property_method, property_argument, converted_value)
274
286
  else
275
- object.send(property_expression, converted_value)
287
+ if object.is_a?(Hash)
288
+ object[property_expression] = converted_value
289
+ else
290
+ object.send(property_expression, converted_value)
291
+ end
276
292
  end
277
293
  apply_processor(@binding_options[:after_write], converted_value)
278
294
  end
@@ -21,6 +21,7 @@
21
21
 
22
22
  require 'set'
23
23
  require 'glimmer/data_binding/observable'
24
+ require 'glimmer/data_binding/observer'
24
25
  require 'array_include_methods'
25
26
 
26
27
  using ArrayIncludeMethods
@@ -29,29 +30,70 @@ module Glimmer
29
30
  module DataBinding
30
31
  module ObservableArray
31
32
  include Observable
33
+
34
+ class Notifier
35
+ include Observer
36
+
37
+ attr_reader :observable_array
38
+
39
+ def initialize(observable_array)
40
+ @observable_array = observable_array
41
+ end
42
+
43
+ def call(new_value=nil, *extra_args)
44
+ @observable_array.notify_observers
45
+ end
46
+ end
32
47
 
33
- def add_observer(observer, *element_properties)
48
+ def add_observer(observer, *args)
49
+ options = args.last.is_a?(Hash) ? args.pop : {}
50
+ element_properties = args
34
51
  element_properties = element_properties.flatten.compact.uniq
35
52
  return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
36
- property_observer_list << observer
53
+ property_observer_list[observer] = options
37
54
  observer_element_properties[observer] = element_properties_for(observer) + Concurrent::Set.new(element_properties)
38
- each { |element| add_element_observer(element, observer) }
55
+ if !options.empty? && options[:recursive].is_a?(Integer)
56
+ options = options.clone
57
+ options[:recursive] = options[:recursive] - 1
58
+ end
59
+ each { |element| add_element_observer(element, observer, options) }
39
60
  observer
40
61
  end
41
62
 
42
- def add_element_observers(element)
43
- property_observer_list.each do |observer|
44
- add_element_observer(element, observer)
63
+ def add_element_observers(element, general_options = {})
64
+ property_observer_list.each do |observer, options|
65
+ add_element_observer(element, observer, options.merge(general_options))
45
66
  end
46
67
  end
47
68
 
48
- def add_element_observer(element, observer)
69
+ def add_element_observer(element, observer, options = {})
49
70
  element_properties_for(observer).each do |property|
50
- observer.observe(element, property)
71
+ observer.observe(element, property, options)
72
+ end
73
+ if element.is_a?(Array) && (options[:recursive] == true || (options[:recursive].is_a?(Integer) && options[:recursive] >= 0))
74
+ ensure_array_object_observer(element, options)
51
75
  end
52
76
  end
77
+
78
+ def ensure_array_object_observer(object, options)
79
+ return unless object&.is_a?(Array)
80
+ array_object_observer = array_object_observer_for(object)
81
+ array_observer_registration = array_object_observer.observe(object, options)
82
+ property_observer_list.each do |observer, options|
83
+ my_registration = observer.registration_for(self)
84
+ observer.add_dependent(my_registration => array_observer_registration)
85
+ end
86
+ end
87
+
88
+ def array_object_observer_for(object)
89
+ @array_object_observers ||= Concurrent::Hash.new
90
+ @array_object_observers[object] = Notifier.new(self) unless @array_object_observers.has_key?(object)
91
+ @array_object_observers[object]
92
+ end
53
93
 
54
- def remove_observer(observer, *element_properties)
94
+ def remove_observer(observer, *args)
95
+ options = args.last.is_a?(Hash) ? args.pop : {}
96
+ element_properties = args
55
97
  element_properties = element_properties.flatten.compact.uniq
56
98
  if !element_properties.empty?
57
99
  old_element_properties = element_properties_for(observer)
@@ -67,7 +109,7 @@ module Glimmer
67
109
  end
68
110
 
69
111
  def remove_element_observers(element)
70
- property_observer_list.each do |observer|
112
+ property_observer_list.each do |observer, options|
71
113
  remove_element_observer(element, observer)
72
114
  end
73
115
  end
@@ -76,10 +118,17 @@ module Glimmer
76
118
  element_properties_for(observer).each do |property|
77
119
  observer.unobserve(element, property)
78
120
  end
121
+ if element.is_a?(ObservableArray)
122
+ array_object_observer_for(element).unobserve(element)
123
+ element.property_observer_list.select {|obs, opt| obs.respond_to?(:observable_array) && obs.observable_array == self}.each do |o|
124
+ o.deregister_all_observables if o.respond_to?(:deregister_all_observables)
125
+ @array_object_observers.reject! {|k, v| v == o}
126
+ end
127
+ end
79
128
  end
80
129
 
81
130
  def has_observer?(observer)
82
- property_observer_list.include?(observer)
131
+ property_observer_list.keys.include?(observer)
83
132
  end
84
133
 
85
134
  def has_observer_element_properties?(observer, element_properties)
@@ -87,7 +136,7 @@ module Glimmer
87
136
  end
88
137
 
89
138
  def property_observer_list
90
- @property_observer_list ||= Concurrent::Set.new
139
+ @property_observer_list ||= Concurrent::Hash.new
91
140
  end
92
141
 
93
142
  def observer_element_properties
@@ -99,7 +148,7 @@ module Glimmer
99
148
  end
100
149
 
101
150
  def notify_observers
102
- property_observer_list.to_a.each { |o| o.call(self) }
151
+ property_observer_list.to_a.each { |obs, opt| obs.call(self) }
103
152
  end
104
153
 
105
154
  def <<(element)
@@ -204,6 +253,7 @@ module Glimmer
204
253
  alias map! collect!
205
254
 
206
255
  def compact!
256
+ # TODO consider checking which exact indices changed and only notifying if there is a change
207
257
  super.tap { notify_observers }
208
258
  end
209
259
 
@@ -322,7 +372,7 @@ module Glimmer
322
372
 
323
373
  def unregister_dependent_observers(old_value)
324
374
  return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
325
- property_observer_list.each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
375
+ property_observer_list.each { |observer, options| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
326
376
  end
327
377
  alias deregister_dependent_observers unregister_dependent_observers
328
378
  end
@@ -19,13 +19,13 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- require 'glimmer/data_binding/observable'
22
+ require 'glimmer/data_binding/observable_hashable'
23
23
  require 'glimmer/data_binding/observer'
24
24
 
25
25
  module Glimmer
26
26
  module DataBinding
27
27
  module ObservableHash
28
- include Observable
28
+ include ObservableHashable
29
29
 
30
30
  class Notifier
31
31
  include Observer
@@ -40,36 +40,19 @@ module Glimmer
40
40
  end
41
41
  end
42
42
 
43
- OBSERVED_STORE_METHOD = lambda do |key, value|
44
- if key_observer_list(key).empty?
45
- if all_key_observer_list.empty?
46
- self.send('__original__store', key, value)
47
- else
48
- old_value = self[key]
49
- unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
50
- self.send('__original__store', key, value)
51
- notify_observers(key)
52
- ensure_array_object_observer(nil, value, old_value)
53
- ensure_hash_object_observer(nil, value, old_value)
54
- end
55
- else
56
- old_value = self[key]
57
- unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
58
- self.send('__original__store', key, value)
59
- notify_observers(key)
60
- ensure_array_object_observer(key, value, old_value)
61
- ensure_hash_object_observer(key, value, old_value)
43
+ def add_observer(observer, key = nil, options = {})
44
+ if key.is_a?(Hash)
45
+ options = key
46
+ key = nil
62
47
  end
63
- end
64
-
65
- def add_observer(observer, key = nil)
66
48
  return observer if has_observer?(observer, key)
67
49
  key_observer_list(key) << observer
68
- add_key_writer_observer(key)
50
+ add_key_writer_observer(key, options)
69
51
  observer
70
52
  end
71
53
 
72
- def remove_observer(observer, key = nil)
54
+ def remove_observer(observer, key = nil, options = {})
55
+ old_value = self[key]
73
56
  if has_observer?(observer, key)
74
57
  key_observer_list(key).delete(observer)
75
58
  observer.unobserve(self, key)
@@ -118,24 +101,6 @@ module Glimmer
118
101
  (key_observer_list(key).to_a - all_key_observer_list.to_a).each { |observer| observer.call(self[key], key) }
119
102
  end
120
103
 
121
- def add_key_writer_observer(key = nil)
122
- ensure_array_object_observer(key, self[key])
123
- ensure_hash_object_observer(key, self[key])
124
- begin
125
- method('__original__store')
126
- rescue
127
- define_singleton_method('__original__store', store_method)
128
- define_singleton_method('[]=', &OBSERVED_STORE_METHOD)
129
- end
130
- rescue => e
131
- #ignore writing if no key writer exists
132
- Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.message}\n#{e.backtrace.join("\n")}"}
133
- end
134
-
135
- def store_method
136
- self.class.instance_method('[]=') rescue self.method('[]=')
137
- end
138
-
139
104
  def unregister_dependent_observers(key, old_value)
140
105
  # TODO look into optimizing this
141
106
  return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray) || old_value.is_a?(ObservableHash)
@@ -143,10 +108,11 @@ module Glimmer
143
108
  end
144
109
  alias deregister_dependent_observers unregister_dependent_observers
145
110
 
146
- def ensure_array_object_observer(key, object, old_object = nil)
111
+ def ensure_array_object_observer(key, object, old_object = nil, options = {})
112
+ options ||= {}
147
113
  return unless object&.is_a?(Array)
148
114
  array_object_observer = array_object_observer_for(key)
149
- array_observer_registration = array_object_observer.observe(object)
115
+ array_observer_registration = array_object_observer.observe(object, options)
150
116
  key_observer_list(key).each do |observer|
151
117
  my_registration = observer.registration_for(self, key) # TODO eliminate repetition
152
118
  observer.add_dependent(my_registration => array_observer_registration)
@@ -160,23 +126,6 @@ module Glimmer
160
126
  @array_object_observers[key]
161
127
  end
162
128
 
163
- def ensure_hash_object_observer(key, object, old_object = nil)
164
- return unless object&.is_a?(Hash)
165
- hash_object_observer = hash_object_observer_for(key)
166
- hash_observer_registration = hash_object_observer.observe(object)
167
- key_observer_list(key).each do |observer|
168
- my_registration = observer.registration_for(self, key) # TODO eliminate repetition
169
- observer.add_dependent(my_registration => hash_observer_registration)
170
- end
171
- hash_object_observer_for(key).unregister(old_object) if old_object.is_a?(ObservableHash)
172
- end
173
-
174
- def hash_object_observer_for(key)
175
- @hash_object_observers ||= Concurrent::Hash.new
176
- @hash_object_observers[key] = ObservableModel::Notifier.new(self, key) unless @hash_object_observers.has_key?(key)
177
- @hash_object_observers[key]
178
- end
179
-
180
129
  def delete(key, &block)
181
130
  old_value = self[key]
182
131
  unless old_value.nil?
@@ -0,0 +1,75 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/data_binding/observable'
23
+
24
+ module Glimmer
25
+ module DataBinding
26
+ # Represents a Hash-like object with attributes writable via :[]= store method like Hash, Struct, and OpenStruct
27
+ # Expects including class to have the following methods:
28
+ # - key_observer_list
29
+ # - all_key_observer_list
30
+ # - unregister_dependent_observer
31
+ # - ensure_array_object_observer
32
+ module ObservableHashable
33
+ include Observable
34
+
35
+ OBSERVED_STORE_METHOD = lambda do |options|
36
+ lambda do |key, value|
37
+ if key_observer_list(key).empty?
38
+ if all_key_observer_list.empty?
39
+ self.send('__original__store', key, value)
40
+ else
41
+ old_value = self[key]
42
+ unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer
43
+ self.send('__original__store', key, value)
44
+ notify_observers(key)
45
+ ensure_array_object_observer(nil, value, old_value, options)
46
+ end
47
+ else
48
+ old_value = self[key]
49
+ unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer
50
+ self.send('__original__store', key, value)
51
+ notify_observers(key)
52
+ ensure_array_object_observer(key, value, old_value, options)
53
+ end
54
+ end
55
+ end
56
+
57
+ def add_key_writer_observer(key = nil, options)
58
+ ensure_array_object_observer(key, self[key], nil, options)
59
+ begin
60
+ method('__original__store')
61
+ rescue
62
+ define_singleton_method('__original__store', store_method)
63
+ define_singleton_method('[]=', &OBSERVED_STORE_METHOD.call(options))
64
+ end
65
+ rescue => e
66
+ #ignore writing if no key writer exists
67
+ Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.message}\n#{e.backtrace.join("\n")}"}
68
+ end
69
+
70
+ def store_method
71
+ self.class.instance_method('[]=') rescue self.method('[]=')
72
+ end
73
+ end
74
+ end
75
+ end
@@ -19,13 +19,13 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- require 'glimmer/data_binding/observable'
22
+ require 'glimmer/data_binding/observable_hashable'
23
23
  require 'glimmer/data_binding/observer'
24
24
 
25
25
  module Glimmer
26
26
  module DataBinding
27
27
  module ObservableModel
28
- include Observable
28
+ include ObservableHashable
29
29
 
30
30
  class Notifier
31
31
  include Observer
@@ -40,26 +40,26 @@ module Glimmer
40
40
  end
41
41
  end
42
42
 
43
- PROPERTY_WRITER_FACTORY = lambda do |property_name|
43
+ PROPERTY_WRITER_FACTORY = lambda do |property_name, options|
44
44
  property_writer_name = "#{property_name}="
45
45
  lambda do |value|
46
46
  old_value = self.send(property_name)
47
- unregister_dependent_observers(property_name, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
47
+ unregister_dependent_observers(property_name, old_value) # remove dependent observers previously installed in ensure_array_object_observer
48
48
  self.send("__original__#{property_writer_name}", value)
49
49
  notify_observers(property_name)
50
- ensure_array_object_observer(property_name, value, old_value)
51
- ensure_hash_object_observer(property_name, value, old_value)
50
+ ensure_array_object_observer(property_name, value, old_value, options)
52
51
  end
53
52
  end
54
-
55
- def add_observer(observer, property_name)
53
+
54
+ def add_observer(observer, property_name, options = {})
56
55
  return observer if has_observer?(observer, property_name)
57
56
  property_observer_list(property_name) << observer
58
- add_property_writer_observers(property_name)
57
+ add_property_writer_observers(property_name, options)
58
+ add_key_writer_observer(property_name, options) if is_a?(Struct) || is_a?(OpenStruct)
59
59
  observer
60
60
  end
61
-
62
- def remove_observer(observer, property_name)
61
+
62
+ def remove_observer(observer, property_name, options = {})
63
63
  if has_observer?(observer, property_name)
64
64
  property_observer_list(property_name).delete(observer)
65
65
  observer.unobserve(self, property_name)
@@ -67,10 +67,11 @@ module Glimmer
67
67
  end
68
68
 
69
69
  def remove_observers(property_name)
70
- property_observer_hash[property_name.to_sym].each do |observer|
70
+ property_key = property_name&.to_sym
71
+ property_observer_hash[property_key].each do |observer|
71
72
  remove_observer(observer, property_name)
72
73
  end
73
- property_observer_hash.delete(property_name.to_sym)
74
+ property_observer_hash.delete(property_key)
74
75
  end
75
76
 
76
77
  def remove_all_observers
@@ -95,24 +96,32 @@ module Glimmer
95
96
  end
96
97
 
97
98
  def property_observer_list(property_name)
98
- property_observer_hash[property_name.to_sym] = Concurrent::Set.new unless property_observer_hash[property_name.to_sym]
99
- property_observer_hash[property_name.to_sym]
99
+ property_key = property_name&.to_sym
100
+ property_observer_hash[property_key] = Concurrent::Set.new unless property_observer_hash[property_key]
101
+ property_observer_hash[property_key]
100
102
  end
103
+ alias key_observer_list property_observer_list
104
+
105
+ def all_property_observer_list
106
+ property_observer_list(nil)
107
+ end
108
+ alias all_key_observer_list all_property_observer_list
101
109
 
102
110
  def notify_observers(property_name)
103
111
  property_observer_list(property_name).to_a.each { |observer| observer.call(send(property_name)) }
104
112
  end
105
-
106
- def add_property_writer_observers(property_name)
113
+
114
+ def add_property_writer_observers(property_name, options)
107
115
  property_writer_name = "#{property_name}="
108
116
  method(property_writer_name)
109
- ensure_array_object_observer(property_name, send(property_name))
110
- ensure_hash_object_observer(property_name, send(property_name))
117
+ ensure_array_object_observer(property_name, send(property_name), nil, options)
111
118
  begin
112
119
  method("__original__#{property_writer_name}")
113
120
  rescue
114
121
  define_singleton_method("__original__#{property_writer_name}", property_writer_method(property_writer_name))
115
- define_singleton_method(property_writer_name, &PROPERTY_WRITER_FACTORY.call(property_name))
122
+ # Note the limitation that the first observe call options apply to all subsequent observations meaning even if unobserve was called, options do not change from initial ones
123
+ # It is good enough for now. If there is a need to address this in the future, this is where to start the work
124
+ define_singleton_method(property_writer_name, &PROPERTY_WRITER_FACTORY.call(property_name, options))
116
125
  end
117
126
  rescue => e
118
127
  #ignore writing if no property writer exists
@@ -130,10 +139,11 @@ module Glimmer
130
139
  end
131
140
  alias deregister_dependent_observers unregister_dependent_observers
132
141
 
133
- def ensure_array_object_observer(property_name, object, old_object = nil)
142
+ def ensure_array_object_observer(property_name, object, old_object = nil, options = nil)
143
+ options ||= {}
134
144
  return unless object&.is_a?(Array)
135
145
  array_object_observer = array_object_observer_for(property_name)
136
- array_observer_registration = array_object_observer.observe(object)
146
+ array_observer_registration = array_object_observer.observe(object, options)
137
147
  property_observer_list(property_name).each do |observer|
138
148
  my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
139
149
  observer.add_dependent(my_registration => array_observer_registration)
@@ -143,26 +153,9 @@ module Glimmer
143
153
 
144
154
  def array_object_observer_for(property_name)
145
155
  @array_object_observers ||= Concurrent::Hash.new
146
- @array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
156
+ @array_object_observers[property_name] = Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
147
157
  @array_object_observers[property_name]
148
158
  end
149
-
150
- def ensure_hash_object_observer(property_name, object, old_object = nil)
151
- return unless object&.is_a?(Hash)
152
- hash_object_observer = hash_object_observer_for(property_name)
153
- hash_observer_registration = hash_object_observer.observe(object)
154
- property_observer_list(property_name).each do |observer|
155
- my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
156
- observer.add_dependent(my_registration => hash_observer_registration)
157
- end
158
- hash_object_observer_for(property_name).unregister(old_object) if old_object.is_a?(ObservableHash)
159
- end
160
-
161
- def hash_object_observer_for(property_name)
162
- @hash_object_observers ||= Concurrent::Hash.new
163
- @hash_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name) unless @hash_object_observers.has_key?(property_name)
164
- @hash_object_observers[property_name]
165
- end
166
159
  end
167
160
  end
168
161
  end