glimmer 0.10.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 1.0.0
@@ -1,9 +1,27 @@
1
- # Glimmer - a JRuby DSL that enables easy and efficient authoring of user
2
- # interfaces using the robust platform-independent Eclipse SWT library. Glimmer
3
- # comes with built-in data-binding support to greatly facilitate synchronizing
4
- # UI with domain models.
1
+ # Copyright (c) 2007-2020 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
+
5
22
  require 'logger'
6
23
  require 'set'
24
+ require 'array_include_methods'
7
25
 
8
26
  $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
9
27
 
@@ -17,7 +35,6 @@ require 'glimmer/config'
17
35
  # Glimmer DSL dynamic keywords (e.g. label, combo, etc...) are available via method_missing
18
36
  module Glimmer
19
37
  #TODO make it configurable to include or not include perhaps reverting to using included
20
- REGEX_METHODS_EXCLUDED = /^(to_|\[)/
21
38
 
22
39
  # TODO add loop detection support to avoid infinite loops (perhaps breaks after 3 repetitions and provides an option to allow it if intentional)
23
40
  class << self
@@ -41,32 +58,26 @@ module Glimmer
41
58
  new_loop_data = [method_symbol, args, block]
42
59
  if new_loop_data == Glimmer.loop_last_data
43
60
  Glimmer.loop_increment!
44
- if Glimmer.loop == Config.loop_max_count
45
- raise "Glimmer looped #{Config.loop_max_count} times with keyword '#{new_loop_data[0]}'! Check code for errors."
46
- end
61
+ raise "Glimmer looped #{Config.loop_max_count} times with keyword '#{new_loop_data[0]}'! Check code for errors." if Glimmer.loop == Config.loop_max_count
47
62
  else
48
63
  Glimmer.loop_reset!
49
64
  end
50
65
  Glimmer.loop_last_data = new_loop_data
51
66
  # This if statement speeds up Glimmer in girb or whenever directly including on main object
52
- if method_symbol.to_s.match(REGEX_METHODS_EXCLUDED)
53
- raise ExcludedKeywordError, "Glimmer excluded keyword: #{method_symbol}"
67
+ is_excluded = Config.excluded_keyword_checkers.reduce(false) {|result, checker| result || instance_exec(method_symbol, *args, &checker) }
68
+ if is_excluded
69
+ Glimmer::Config.logger.debug "Glimmer excluded keyword: #{method_symbol}" if Glimmer::Config.log_excluded_keywords?
70
+ super(method_symbol, *args, &block)
54
71
  end
55
- Glimmer::Config.logger.debug {"Interpreting keyword: #{method_symbol}"}
72
+ Glimmer::Config.logger.info {"Interpreting keyword: #{method_symbol}"}
56
73
  Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
57
- rescue ExcludedKeywordError => e
58
- # TODO add a feature to show excluded keywords optionally for debugging purposes
59
- super(method_symbol, *args, &block)
60
74
  rescue InvalidKeywordError => e
61
- if !method_symbol.to_s.match(REGEX_METHODS_EXCLUDED)
62
- Glimmer::Config.logger.error {e.message}
63
- end
64
- Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
75
+ Glimmer::Config.logger.error {"Encountered an invalid keyword at this object: #{self}"}
76
+ Glimmer::Config.logger.error {e.full_message}
65
77
  super(method_symbol, *args, &block)
66
78
  end
67
79
  end
68
80
 
69
81
  require 'glimmer/error'
70
- require 'glimmer/excluded_keyword_error'
71
82
  require 'glimmer/invalid_keyword_error'
72
83
  require 'glimmer/dsl/engine'
@@ -1,16 +1,52 @@
1
+ # Copyright (c) 2007-2020 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
+
1
22
  module Glimmer
2
23
  module Config
3
24
  class << self
4
25
  LOOP_MAX_COUNT_DEFAULT = 100
26
+ REGEX_METHODS_EXCLUDED = /^(to_|\[)/
5
27
 
6
28
  attr_writer :loop_max_count
29
+ attr_accessor :log_excluded_keywords
30
+ alias log_excluded_keywords? log_excluded_keywords
31
+
32
+ def excluded_keyword_checkers
33
+ @excluded_keyword_checkers ||= reset_excluded_keyword_checkers!
34
+ end
35
+
36
+ def excluded_keyword_checkers=(checkers)
37
+ @excluded_keyword_checkers = checkers
38
+ end
39
+
40
+ def reset_excluded_keyword_checkers!
41
+ @excluded_keyword_checkers = [ lambda { |method_symbol, *args| method_symbol.to_s.match(REGEX_METHODS_EXCLUDED) } ]
42
+ end
7
43
 
8
44
  def loop_max_count
9
45
  @loop_max_count ||= LOOP_MAX_COUNT_DEFAULT
10
46
  end
11
47
 
12
48
  # Returns Glimmer logger (standard Ruby logger)
13
- def logger
49
+ def logger
14
50
  reset_logger! unless defined? @@logger
15
51
  @@logger
16
52
  end
@@ -22,12 +58,13 @@ module Glimmer
22
58
  def reset_logger!
23
59
  self.logger = Logger.new(STDOUT).tap do |logger|
24
60
  logger.level = Logger::ERROR
61
+ begin
62
+ logger.level = ENV['GLIMMER_LOGGER_LEVEL'].strip.downcase if ENV['GLIMMER_LOGGER_LEVEL']
63
+ rescue => e
64
+ puts e.message
65
+ end
25
66
  end
26
67
  end
27
68
  end
28
69
  end
29
70
  end
30
-
31
- if ENV['GLIMMER_LOGGER_LEVEL']
32
- Glimmer::Config.logger.level = ENV['GLIMMER_LOGGER_LEVEL'].downcase
33
- end
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2007-2020 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
+
1
22
  require 'glimmer/data_binding/observable'
2
23
  require 'glimmer/data_binding/observer'
3
24
 
@@ -7,7 +28,7 @@ module Glimmer
7
28
  include Observable
8
29
  include Observer
9
30
 
10
- attr_reader :binding_options
31
+ attr_reader :binding_options, :property_name_expression
11
32
 
12
33
  def initialize(base_model, property_name_expression, binding_options = nil)
13
34
  @base_model = base_model
@@ -60,19 +81,10 @@ module Glimmer
60
81
  end
61
82
 
62
83
  def apply_converter(converter, value)
63
- if converter.nil?
64
- value
65
- elsif converter.is_a?(String) || converter.is_a?(Symbol)
66
- if value.respond_to?(converter)
67
- value.send(converter)
68
- else
69
- raise Glimmer::Error, "Unsupported bind converter: #{converter.inspect}"
70
- end
71
- elsif converter.respond_to?(:call, value)
72
- converter.call(value)
73
- else
74
- raise Glimmer::Error, "Unsupported bind converter: #{converter.inspect}"
75
- end
84
+ return value if converter.nil?
85
+ return value.send(converter) if (converter.is_a?(String) || converter.is_a?(Symbol)) && value.respond_to?(converter)
86
+ return converter.call(value) if converter.respond_to?(:call, value)
87
+ raise Glimmer::Error, "Unsupported bind converter: #{converter.inspect}"
76
88
  end
77
89
 
78
90
  # All nested property names
@@ -99,10 +111,6 @@ module Glimmer
99
111
  property_name_expression.match(/[.\[]/)
100
112
  end
101
113
 
102
- def property_name_expression
103
- @property_name_expression
104
- end
105
-
106
114
  def computed?
107
115
  !computed_by.empty?
108
116
  end
@@ -179,17 +187,19 @@ module Glimmer
179
187
  model, property_name = zip
180
188
  nested_property_observer = nested_property_observers[property_name]
181
189
  previous_index = i - 1
182
- parent_model = previous_index.negative? ? self : nested_models[previous_index]
183
- parent_property_name = previous_index.negative? ? nil : nested_property_names[previous_index]
184
- parent_observer = previous_index.negative? ? observer : nested_property_observers[parent_property_name]
190
+ if previous_index.negative?
191
+ parent_model = self
192
+ parent_property_name = nil
193
+ parent_observer = observer
194
+ else
195
+ parent_model = nested_models[previous_index]
196
+ parent_property_name = nested_property_names[previous_index]
197
+ parent_observer = nested_property_observers[parent_property_name]
198
+ end
185
199
  parent_property_name = nil if parent_property_name.to_s.start_with?('[')
186
200
  unless model.nil?
187
- if property_indexed?(property_name)
188
- # TODO figure out a way to deal with this more uniformly
189
- observer_registration = nested_property_observer.observe(model)
190
- else
191
- observer_registration = nested_property_observer.observe(model, property_name)
192
- end
201
+ # TODO figure out a way to deal with this more uniformly
202
+ observer_registration = property_indexed?(property_name) ? nested_property_observer.observe(model) : nested_property_observer.observe(model, property_name)
193
203
  parent_registration = parent_observer.registration_for(parent_model, parent_property_name)
194
204
  parent_observer.add_dependent(parent_registration => observer_registration)
195
205
  end
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2007-2020 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
+
1
22
  require 'glimmer/error'
2
23
 
3
24
  module Glimmer
@@ -1,85 +1,284 @@
1
- require 'set'
1
+ # Copyright (c) 2007-2020 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.
2
21
 
22
+ require 'set'
3
23
  require 'glimmer/data_binding/observable'
24
+ require 'array_include_methods'
25
+
26
+ using ArrayIncludeMethods
4
27
 
5
28
  module Glimmer
6
29
  module DataBinding
7
- # TODO prefix utility methods with double-underscore
8
30
  module ObservableArray
9
31
  include Observable
10
32
 
11
- def add_observer(observer, element_properties=nil)
12
- return observer if has_observer?(observer) && element_properties.nil?
33
+ def add_observer(observer, *element_properties)
34
+ element_properties = element_properties.flatten.compact.uniq
35
+ return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
13
36
  property_observer_list << observer
14
- [element_properties].flatten.compact.each do |property|
15
- each do |element|
16
- observer.observe(element, property)
17
- end
18
- end
37
+ observer_element_properties[observer] = element_properties_for(observer) + Set.new(element_properties)
38
+ each { |element| add_element_observer(element, observer) }
19
39
  observer
20
40
  end
41
+
42
+ def add_element_observers(element)
43
+ property_observer_list.each do |observer|
44
+ add_element_observer(element, observer)
45
+ end
46
+ end
21
47
 
22
- def remove_observer(observer, element_properties=nil)
23
- property_observer_list.delete(observer)
24
- [element_properties].flatten.compact.each do |property|
25
- each do |element|
26
- observer.unobserve(element, property)
27
- end
48
+ def add_element_observer(element, observer)
49
+ element_properties_for(observer).each do |property|
50
+ observer.observe(element, property)
51
+ end
52
+ end
53
+
54
+ def remove_observer(observer, *element_properties)
55
+ element_properties = element_properties.flatten.compact.uniq
56
+ if !element_properties.empty?
57
+ old_element_properties = element_properties_for(observer)
58
+ observer_element_properties[observer] = element_properties_for(observer) - Set.new(element_properties)
59
+ each { |element| element_properties.each { |property| observer.unobserve(element, property) } }
28
60
  end
61
+ if element_properties_for(observer).empty?
62
+ property_observer_list.delete(observer)
63
+ observer_element_properties.delete(observer)
64
+ each { |element| remove_element_observer(element, observer) }
65
+ end
29
66
  observer
30
67
  end
31
68
 
69
+ def remove_element_observers(element)
70
+ property_observer_list.each do |observer|
71
+ remove_element_observer(element, observer)
72
+ end
73
+ end
74
+
75
+ def remove_element_observer(element, observer)
76
+ element_properties_for(observer).each do |property|
77
+ observer.unobserve(element, property)
78
+ end
79
+ end
80
+
32
81
  def has_observer?(observer)
33
82
  property_observer_list.include?(observer)
34
83
  end
84
+
85
+ def has_observer_element_properties?(observer, element_properties)
86
+ element_properties_for(observer).to_a.include_all?(element_properties)
87
+ end
35
88
 
36
89
  def property_observer_list
37
90
  @property_observer_list ||= Set.new
38
91
  end
39
92
 
93
+ def observer_element_properties
94
+ @observer_element_properties ||= {}
95
+ end
96
+
97
+ def element_properties_for(observer)
98
+ observer_element_properties[observer] ||= Set.new
99
+ end
100
+
40
101
  def notify_observers
41
- property_observer_list.each {|observer| observer.call}
102
+ property_observer_list.to_a.each(&:call)
42
103
  end
43
104
 
44
105
  def <<(element)
45
- super(element)
46
- notify_observers
106
+ super(element).tap do
107
+ add_element_observers(element)
108
+ notify_observers
109
+ end
47
110
  end
111
+ alias push <<
48
112
 
49
113
  def []=(index, value)
50
114
  old_value = self[index]
51
115
  unregister_dependent_observers(old_value)
52
- super(index, value)
53
- notify_observers
116
+ remove_element_observers(old_value)
117
+ add_element_observers(value)
118
+ super(index, value).tap do
119
+ notify_observers
120
+ end
121
+ end
122
+
123
+ def pop
124
+ popped_element = last
125
+ unregister_dependent_observers(popped_element)
126
+ remove_element_observers(popped_element)
127
+ super.tap do
128
+ notify_observers
129
+ end
54
130
  end
55
131
 
56
132
  def delete(element)
57
133
  unregister_dependent_observers(element)
58
- super(element)
59
- notify_observers
134
+ remove_element_observers(element)
135
+ super(element).tap do
136
+ notify_observers
137
+ end
60
138
  end
61
139
 
62
140
  def delete_at(index)
63
141
  old_value = self[index]
64
142
  unregister_dependent_observers(old_value)
65
- super(index)
66
- notify_observers
143
+ remove_element_observers(old_value)
144
+ super(index).tap do
145
+ notify_observers
146
+ end
147
+ end
148
+
149
+ def delete_if(&block)
150
+ if block_given?
151
+ old_array = Array.new(self)
152
+ super(&block).tap do |new_array|
153
+ (old_array - new_array).each do |element|
154
+ unregister_dependent_observers(element)
155
+ remove_element_observers(element)
156
+ end
157
+ notify_observers
158
+ end
159
+ else
160
+ super
161
+ end
67
162
  end
68
163
 
69
164
  def clear
70
165
  each do |old_value|
71
166
  unregister_dependent_observers(old_value)
167
+ remove_element_observers(old_value)
168
+ end
169
+ super.tap do
170
+ notify_observers
171
+ end
172
+ end
173
+
174
+ def reverse!
175
+ super.tap do
176
+ notify_observers
177
+ end
178
+ end
179
+
180
+ def collect!(&block)
181
+ if block_given?
182
+ each do |old_value|
183
+ unregister_dependent_observers(old_value)
184
+ remove_element_observers(old_value)
185
+ end
186
+ super(&block).tap do
187
+ each { |element| add_element_observers(element) }
188
+ notify_observers
189
+ end
190
+ else
191
+ super
192
+ end
193
+ end
194
+ alias map! collect!
195
+
196
+ def compact!
197
+ super.tap { notify_observers }
198
+ end
199
+
200
+ def flatten!(level=nil)
201
+ each do |old_value|
202
+ unregister_dependent_observers(old_value)
203
+ remove_element_observers(old_value)
204
+ end
205
+ (level.nil? ? super() : super(level)).tap do
206
+ each { |element| add_element_observers(element) }
207
+ notify_observers
208
+ end
209
+ end
210
+
211
+ def rotate!(count=1)
212
+ super(count).tap { notify_observers }
213
+ end
214
+
215
+ def select!(&block)
216
+ if block_given?
217
+ old_array = Array.new(self)
218
+ super(&block).tap do
219
+ (old_array - self).each do |old_value|
220
+ unregister_dependent_observers(old_value)
221
+ remove_element_observers(old_value)
222
+ end
223
+ notify_observers
224
+ end
225
+ else
226
+ super
227
+ end
228
+ end
229
+
230
+ def shuffle!(hash = nil)
231
+ (hash.nil? ? super() : super(random: hash[:random])).tap { notify_observers }
232
+ end
233
+
234
+ def slice!(arg1, arg2=nil)
235
+ old_array = Array.new(self)
236
+ (arg2.nil? ? super(arg1) : super(arg1, arg2)).tap do
237
+ (old_array - self).each do |old_value|
238
+ unregister_dependent_observers(old_value)
239
+ remove_element_observers(old_value)
240
+ end
241
+ notify_observers
242
+ end
243
+ end
244
+
245
+ def sort!(&block)
246
+ (block.nil? ? super() : super(&block)).tap { notify_observers }
247
+ end
248
+
249
+ def sort_by!(&block)
250
+ (block.nil? ? super() : super(&block)).tap { notify_observers }
251
+ end
252
+
253
+ def uniq!(&block)
254
+ each do |old_value|
255
+ unregister_dependent_observers(old_value)
256
+ remove_element_observers(old_value)
257
+ end
258
+ (block.nil? ? super() : super(&block)).tap do
259
+ each { |element| add_element_observers(element) }
260
+ notify_observers
261
+ end
262
+ end
263
+
264
+ def reject!(&block)
265
+ if block.nil?
266
+ super
267
+ else
268
+ old_array = Array.new(self)
269
+ super(&block).tap do
270
+ (old_array - self).each do |old_value|
271
+ unregister_dependent_observers(old_value)
272
+ remove_element_observers(old_value)
273
+ end
274
+ notify_observers
275
+ end
72
276
  end
73
- super()
74
- notify_observers
75
277
  end
76
278
 
77
279
  def unregister_dependent_observers(old_value)
78
- # TODO look into optimizing this
79
280
  return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
80
- property_observer_list.each do |observer|
81
- observer.unregister_dependents_with_observable(observer.registration_for(self), old_value)
82
- end
281
+ property_observer_list.each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
83
282
  end
84
283
  end
85
284
  end