glimmer 0.10.1 → 1.0.1

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.1
1
+ 1.0.1
@@ -0,0 +1,81 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: glimmer 1.0.1 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "glimmer".freeze
9
+ s.version = "1.0.1"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["AndyMaleh".freeze]
14
+ s.date = "2020-10-04"
15
+ s.description = "Glimmer is a Ruby DSL engine with support for the Glimmer DSL for SWT (JRuby Desktop Development GUI Library), the Glimmer DSL for Tk (Ruby Desktop Development GUI Library), the Glimmer DSL for Opal (Web GUI Adapter for Desktop Apps), the Glimmer DSL for XML (& HTML), and the Glimmer DSL for CSS.".freeze
16
+ s.email = "andy.am@gmail.com".freeze
17
+ s.extra_rdoc_files = [
18
+ "CHANGELOG.md",
19
+ "LICENSE.txt",
20
+ "README.md"
21
+ ]
22
+ s.files = [
23
+ "CHANGELOG.md",
24
+ "CONTRIBUTING.md",
25
+ "LICENSE.txt",
26
+ "PROCESS.md",
27
+ "README.md",
28
+ "VERSION",
29
+ "glimmer.gemspec",
30
+ "lib/glimmer.rb",
31
+ "lib/glimmer/config.rb",
32
+ "lib/glimmer/data_binding/model_binding.rb",
33
+ "lib/glimmer/data_binding/observable.rb",
34
+ "lib/glimmer/data_binding/observable_array.rb",
35
+ "lib/glimmer/data_binding/observable_model.rb",
36
+ "lib/glimmer/data_binding/observer.rb",
37
+ "lib/glimmer/dsl/engine.rb",
38
+ "lib/glimmer/dsl/expression.rb",
39
+ "lib/glimmer/dsl/expression_handler.rb",
40
+ "lib/glimmer/dsl/parent_expression.rb",
41
+ "lib/glimmer/dsl/static_expression.rb",
42
+ "lib/glimmer/dsl/top_level_expression.rb",
43
+ "lib/glimmer/error.rb",
44
+ "lib/glimmer/invalid_keyword_error.rb"
45
+ ]
46
+ s.homepage = "http://github.com/AndyObtiva/glimmer".freeze
47
+ s.licenses = ["MIT".freeze]
48
+ s.rubygems_version = "3.1.4".freeze
49
+ s.summary = "Glimmer Ruby DSL Engine".freeze
50
+
51
+ if s.respond_to? :specification_version then
52
+ s.specification_version = 4
53
+ end
54
+
55
+ if s.respond_to? :add_runtime_dependency then
56
+ s.add_runtime_dependency(%q<array_include_methods>.freeze, [">= 1.0.3", "< 2.0.0"])
57
+ s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
58
+ s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
59
+ s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
60
+ s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
61
+ s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
62
+ s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
63
+ s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
64
+ s.add_development_dependency(%q<coveralls>.freeze, ["= 0.8.23"])
65
+ s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
66
+ s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
67
+ else
68
+ s.add_dependency(%q<array_include_methods>.freeze, [">= 1.0.3", "< 2.0.0"])
69
+ s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
70
+ s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
71
+ s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
72
+ s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
73
+ s.add_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
74
+ s.add_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
75
+ s.add_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
76
+ s.add_dependency(%q<coveralls>.freeze, ["= 0.8.23"])
77
+ s.add_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
78
+ s.add_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
79
+ end
80
+ end
81
+
@@ -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
 
@@ -37,22 +55,23 @@ module Glimmer
37
55
  end
38
56
 
39
57
  def method_missing(method_symbol, *args, &block)
40
- new_loop_data = [method_symbol, args, block]
41
- if new_loop_data == Glimmer.loop_last_data
42
- Glimmer.loop_increment!
43
- 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
44
- else
45
- Glimmer.loop_reset!
46
- end
47
- Glimmer.loop_last_data = new_loop_data
48
58
  # This if statement speeds up Glimmer in girb or whenever directly including on main object
49
59
  is_excluded = Config.excluded_keyword_checkers.reduce(false) {|result, checker| result || instance_exec(method_symbol, *args, &checker) }
50
- raise ExcludedKeywordError, "Glimmer excluded keyword: #{method_symbol}" if is_excluded
51
- Glimmer::Config.logger.info {"Interpreting keyword: #{method_symbol}"}
52
- Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
53
- rescue ExcludedKeywordError => e
54
- # TODO add a feature to show excluded keywords optionally for debugging purposes
55
- super(method_symbol, *args, &block)
60
+ if is_excluded
61
+ Glimmer::Config.logger.debug "Glimmer excluded keyword: #{method_symbol}" if Glimmer::Config.log_excluded_keywords?
62
+ super(method_symbol, *args, &block)
63
+ else
64
+ new_loop_data = [method_symbol, args, block]
65
+ if new_loop_data == Glimmer.loop_last_data
66
+ Glimmer.loop_increment!
67
+ 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
68
+ else
69
+ Glimmer.loop_reset!
70
+ end
71
+ Glimmer.loop_last_data = new_loop_data
72
+ Glimmer::Config.logger.info {"Interpreting keyword: #{method_symbol}"}
73
+ Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
74
+ end
56
75
  rescue InvalidKeywordError => e
57
76
  Glimmer::Config.logger.error {"Encountered an invalid keyword at this object: #{self}"}
58
77
  Glimmer::Config.logger.error {e.full_message}
@@ -61,6 +80,5 @@ module Glimmer
61
80
  end
62
81
 
63
82
  require 'glimmer/error'
64
- require 'glimmer/excluded_keyword_error'
65
83
  require 'glimmer/invalid_keyword_error'
66
84
  require 'glimmer/dsl/engine'
@@ -1,10 +1,33 @@
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
5
- REGEX_METHODS_EXCLUDED = /^(to_|\[)/
26
+ REGEX_METHODS_EXCLUDED = /^(to_|\[|load_iseq)/
6
27
 
7
28
  attr_writer :loop_max_count
29
+ attr_accessor :log_excluded_keywords
30
+ alias log_excluded_keywords? log_excluded_keywords
8
31
 
9
32
  def excluded_keyword_checkers
10
33
  @excluded_keyword_checkers ||= reset_excluded_keyword_checkers!
@@ -15,9 +38,7 @@ module Glimmer
15
38
  end
16
39
 
17
40
  def reset_excluded_keyword_checkers!
18
- @excluded_keyword_checkers = [
19
- lambda { |method_symbol, *args| method_symbol.to_s.match(REGEX_METHODS_EXCLUDED) }
20
- ]
41
+ @excluded_keyword_checkers = [ lambda { |method_symbol, *args| method_symbol.to_s.match(REGEX_METHODS_EXCLUDED) } ]
21
42
  end
22
43
 
23
44
  def loop_max_count
@@ -25,7 +46,7 @@ module Glimmer
25
46
  end
26
47
 
27
48
  # Returns Glimmer logger (standard Ruby logger)
28
- def logger
49
+ def logger
29
50
  reset_logger! unless defined? @@logger
30
51
  @@logger
31
52
  end
@@ -37,12 +58,13 @@ module Glimmer
37
58
  def reset_logger!
38
59
  self.logger = Logger.new(STDOUT).tap do |logger|
39
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
40
66
  end
41
67
  end
42
68
  end
43
69
  end
44
70
  end
45
-
46
- if ENV['GLIMMER_LOGGER_LEVEL']
47
- Glimmer::Config.logger.level = ENV['GLIMMER_LOGGER_LEVEL'].downcase
48
- 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
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