glimmer 2.3.0 → 2.5.1

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.
@@ -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
@@ -45,33 +45,41 @@ module Glimmer
45
45
  end
46
46
  end
47
47
 
48
- 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
49
51
  element_properties = element_properties.flatten.compact.uniq
50
52
  return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
51
- property_observer_list << observer
53
+ property_observer_list[observer] = options
52
54
  observer_element_properties[observer] = element_properties_for(observer) + Concurrent::Set.new(element_properties)
53
- 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) }
54
60
  observer
55
61
  end
56
62
 
57
- def add_element_observers(element)
58
- property_observer_list.each do |observer|
59
- 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))
60
66
  end
61
67
  end
62
68
 
63
- def add_element_observer(element, observer)
69
+ def add_element_observer(element, observer, options = {})
64
70
  element_properties_for(observer).each do |property|
65
- 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)
66
75
  end
67
- ensure_array_object_observer(element) if element.is_a?(Array)
68
76
  end
69
77
 
70
- def ensure_array_object_observer(object)
78
+ def ensure_array_object_observer(object, options)
71
79
  return unless object&.is_a?(Array)
72
80
  array_object_observer = array_object_observer_for(object)
73
- array_observer_registration = array_object_observer.observe(object)
74
- property_observer_list.each do |observer|
81
+ array_observer_registration = array_object_observer.observe(object, options)
82
+ property_observer_list.each do |observer, options|
75
83
  my_registration = observer.registration_for(self)
76
84
  observer.add_dependent(my_registration => array_observer_registration)
77
85
  end
@@ -83,7 +91,9 @@ module Glimmer
83
91
  @array_object_observers[object]
84
92
  end
85
93
 
86
- 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
87
97
  element_properties = element_properties.flatten.compact.uniq
88
98
  if !element_properties.empty?
89
99
  old_element_properties = element_properties_for(observer)
@@ -99,7 +109,7 @@ module Glimmer
99
109
  end
100
110
 
101
111
  def remove_element_observers(element)
102
- property_observer_list.each do |observer|
112
+ property_observer_list.each do |observer, options|
103
113
  remove_element_observer(element, observer)
104
114
  end
105
115
  end
@@ -110,17 +120,15 @@ module Glimmer
110
120
  end
111
121
  if element.is_a?(ObservableArray)
112
122
  array_object_observer_for(element).unobserve(element)
113
- element.property_observer_list.select {|o| o.observable_array == self}.each do |o|
114
- o.registrations.each do |registration|
115
- registration.deregister
116
- end
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)
117
125
  @array_object_observers.reject! {|k, v| v == o}
118
126
  end
119
127
  end
120
128
  end
121
129
 
122
130
  def has_observer?(observer)
123
- property_observer_list.include?(observer)
131
+ property_observer_list.keys.include?(observer)
124
132
  end
125
133
 
126
134
  def has_observer_element_properties?(observer, element_properties)
@@ -128,7 +136,7 @@ module Glimmer
128
136
  end
129
137
 
130
138
  def property_observer_list
131
- @property_observer_list ||= Concurrent::Set.new
139
+ @property_observer_list ||= Concurrent::Hash.new
132
140
  end
133
141
 
134
142
  def observer_element_properties
@@ -140,7 +148,7 @@ module Glimmer
140
148
  end
141
149
 
142
150
  def notify_observers
143
- property_observer_list.to_a.each { |o| o.call(self) }
151
+ property_observer_list.to_a.each { |obs, opt| obs.call(self) }
144
152
  end
145
153
 
146
154
  def <<(element)
@@ -245,6 +253,7 @@ module Glimmer
245
253
  alias map! collect!
246
254
 
247
255
  def compact!
256
+ # TODO consider checking which exact indices changed and only notifying if there is a change
248
257
  super.tap { notify_observers }
249
258
  end
250
259
 
@@ -363,7 +372,7 @@ module Glimmer
363
372
 
364
373
  def unregister_dependent_observers(old_value)
365
374
  return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
366
- 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) }
367
376
  end
368
377
  alias deregister_dependent_observers unregister_dependent_observers
369
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,27 @@ 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
+ open_struct_loaded = !!::OpenStruct rescue false
59
+ add_key_writer_observer(property_name, options) if is_a?(Struct) || (open_struct_loaded && is_a?(OpenStruct))
59
60
  observer
60
61
  end
61
-
62
- def remove_observer(observer, property_name)
62
+
63
+ def remove_observer(observer, property_name, options = {})
63
64
  if has_observer?(observer, property_name)
64
65
  property_observer_list(property_name).delete(observer)
65
66
  observer.unobserve(self, property_name)
@@ -67,10 +68,11 @@ module Glimmer
67
68
  end
68
69
 
69
70
  def remove_observers(property_name)
70
- property_observer_hash[property_name.to_sym].each do |observer|
71
+ property_key = property_name&.to_sym
72
+ property_observer_hash[property_key].each do |observer|
71
73
  remove_observer(observer, property_name)
72
74
  end
73
- property_observer_hash.delete(property_name.to_sym)
75
+ property_observer_hash.delete(property_key)
74
76
  end
75
77
 
76
78
  def remove_all_observers
@@ -95,24 +97,32 @@ module Glimmer
95
97
  end
96
98
 
97
99
  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]
100
+ property_key = property_name&.to_sym
101
+ property_observer_hash[property_key] = Concurrent::Set.new unless property_observer_hash[property_key]
102
+ property_observer_hash[property_key]
100
103
  end
104
+ alias key_observer_list property_observer_list
105
+
106
+ def all_property_observer_list
107
+ property_observer_list(nil)
108
+ end
109
+ alias all_key_observer_list all_property_observer_list
101
110
 
102
111
  def notify_observers(property_name)
103
112
  property_observer_list(property_name).to_a.each { |observer| observer.call(send(property_name)) }
104
113
  end
105
-
106
- def add_property_writer_observers(property_name)
114
+
115
+ def add_property_writer_observers(property_name, options)
107
116
  property_writer_name = "#{property_name}="
108
117
  method(property_writer_name)
109
- ensure_array_object_observer(property_name, send(property_name))
110
- ensure_hash_object_observer(property_name, send(property_name))
118
+ ensure_array_object_observer(property_name, send(property_name), nil, options)
111
119
  begin
112
120
  method("__original__#{property_writer_name}")
113
121
  rescue
114
122
  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))
123
+ # 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
124
+ # It is good enough for now. If there is a need to address this in the future, this is where to start the work
125
+ define_singleton_method(property_writer_name, &PROPERTY_WRITER_FACTORY.call(property_name, options))
116
126
  end
117
127
  rescue => e
118
128
  #ignore writing if no property writer exists
@@ -130,10 +140,11 @@ module Glimmer
130
140
  end
131
141
  alias deregister_dependent_observers unregister_dependent_observers
132
142
 
133
- def ensure_array_object_observer(property_name, object, old_object = nil)
143
+ def ensure_array_object_observer(property_name, object, old_object = nil, options = nil)
144
+ options ||= {}
134
145
  return unless object&.is_a?(Array)
135
146
  array_object_observer = array_object_observer_for(property_name)
136
- array_observer_registration = array_object_observer.observe(object)
147
+ array_observer_registration = array_object_observer.observe(object, options)
137
148
  property_observer_list(property_name).each do |observer|
138
149
  my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
139
150
  observer.add_dependent(my_registration => array_observer_registration)
@@ -146,23 +157,6 @@ module Glimmer
146
157
  @array_object_observers[property_name] = Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
147
158
  @array_object_observers[property_name]
148
159
  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] = Notifier.new(self, property_name) unless @hash_object_observers.has_key?(property_name)
164
- @hash_object_observers[property_name]
165
- end
166
160
  end
167
161
  end
168
162
  end