glimmer-dsl-swt 0.1.1 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b7dbe91f4446b09448aa58ad33e7192060feb314ad3cb6e146c95f6aef034c4
4
- data.tar.gz: 030a51954d8ed32fc128a729c7469e3c313e18615aa47caa588920dd9706c49e
3
+ metadata.gz: 4b54809644b379821d606ce742901ec5ce91197bfccb33ee15893d9b809ef766
4
+ data.tar.gz: f322c7d1c9f2a7aa9b97709739978317c727a0988dec41c397db205c544c3c7b
5
5
  SHA512:
6
- metadata.gz: 3240f754fb9948de06ed1d84af8f037ca8a520aaf4d0b2d6958bf856a650ee53c13f49391e1be23566ff6f51b8792bb21e99f7bbc781c5c6c3b16b378f52193f
7
- data.tar.gz: 6e7f3a1fb5614ece07eb98dd0f44cdefe011e69b1bb686bd8ff5c8b9968a96b692a5bace1b648c16d4aa7d66ac5e716127097fe6f08c6e744adfa307f42dfc33
6
+ metadata.gz: 54539c2fa3414d637fa6e29578e88c592f09d292c7027308ced2a8ddd84f11ed6d36ec769ec9e8c06113c3fed16c08cba4774f92b5d167e8f16867788fd7106d
7
+ data.tar.gz: 8f3f36715b553078f72f0fd66f635437344ba0151a1ba2665852cee9fb81658afb265d66493d0b61d42083f1ebb3c963368fc43c6f74133e4b9bf73d79fb8395
data/README.md CHANGED
@@ -1,11 +1,16 @@
1
- # Glimmer DSL for SWT 0.1.1 (Desktop GUI)
1
+ # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=105 /> Glimmer DSL for SWT 0.1.2 (Desktop GUI)
2
2
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-swt.svg)](http://badge.fury.io/rb/glimmer-dsl-swt)
3
3
  [![Travis CI](https://travis-ci.com/AndyObtiva/glimmer-dsl-swt.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer-dsl-swt)
4
+ [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
5
 
5
6
  [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for SWT enables desktop development with Glimmer.
6
7
 
7
- You may find full setup/usage instructions at the main Glimmer project page:
8
- [https://github.com/AndyObtiva/glimmer](https://github.com/AndyObtiva/glimmer)
8
+ You may find full setup/usage instructions at the main [Glimmer project page](https://github.com/AndyObtiva/glimmer).
9
+
10
+ Other Glimmer DSL gems:
11
+ - [glimmer-dsl-opal](https://github.com/AndyObtiva/glimmer-dsl-opal): Glimmer DSL for Opal (Web GUI Adapter for Desktop Apps)
12
+ - [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
13
+ - [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS (Cascading Style Sheets)
9
14
 
10
15
  ## Help
11
16
 
@@ -15,11 +20,9 @@ You may submit [issues](https://github.com/AndyObtiva/glimmer/issues) on [GitHub
15
20
 
16
21
  [Click here to submit an issue.](https://github.com/AndyObtiva/glimmer/issues)
17
22
 
18
- ### IRC Channel
19
-
20
- If you need live help, try the [#glimmer](http://widget.mibbit.com/?settings=7514b8a196f8f1de939a351245db7aa8&server=irc.mibbit.net&channel=%23glimmer) IRC channel on [irc.mibbit.net](http://widget.mibbit.com/?settings=7514b8a196f8f1de939a351245db7aa8&server=irc.mibbit.net&channel=%23glimmer). If no one was available, you may [leave a GitHub issue](https://github.com/AndyObtiva/glimmer/issues) to schedule a meetup on IRC.
23
+ ### Chat
21
24
 
22
- [Click here to connect to #glimmer IRC channel immediately via a web interface.](http://widget.mibbit.com/?settings=7514b8a196f8f1de939a351245db7aa8&server=irc.mibbit.net&channel=%23glimmer)
25
+ If you need live help, try to [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
23
26
 
24
27
  ## Feature Suggestions
25
28
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -1,6 +1,5 @@
1
- require 'glimmer'
2
- require_relative 'observable'
3
- require_relative 'observer'
1
+ require 'glimmer/data_binding/observable'
2
+ require 'glimmer/data_binding/observer'
4
3
 
5
4
  module Glimmer
6
5
  module DataBinding
@@ -10,10 +9,10 @@ module Glimmer
10
9
  include Observer
11
10
 
12
11
  attr_reader :widget, :property
13
- def initialize(model, property, translator = nil)
14
- @widget = model
12
+ def initialize(widget, property, translator = nil)
13
+ @widget = widget
15
14
  @property = property
16
- @translator = translator || proc {|value| value}
15
+ @translator = translator || proc {|value| value} #TODO check on this it doesn't seem used
17
16
 
18
17
  if @widget.respond_to?(:dispose)
19
18
  @widget.on_widget_disposed do |dispose_event|
@@ -21,10 +20,12 @@ module Glimmer
21
20
  end
22
21
  end
23
22
  end
23
+
24
24
  def call(value)
25
25
  converted_value = translated_value = @translator.call(value)
26
26
  @widget.set_attribute(@property, converted_value) unless evaluate_property == converted_value
27
27
  end
28
+
28
29
  def evaluate_property
29
30
  @widget.get_attribute(@property)
30
31
  end
@@ -1,4 +1,3 @@
1
- require 'glimmer'
2
1
  require 'glimmer/swt/widget_listener_proxy'
3
2
  require 'glimmer/swt/color_proxy'
4
3
  require 'glimmer/swt/font_proxy'
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-swt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-15 00:00:00.000000000 Z
11
+ date: 2020-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.9.0
18
+ version: 0.9.2
19
19
  name: glimmer
20
20
  type: :runtime
21
21
  prerelease: false
@@ -23,7 +23,7 @@ dependencies:
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.9.0
26
+ version: 0.9.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
@@ -216,12 +216,7 @@ files:
216
216
  - lib/ext/glimmer/config.rb
217
217
  - lib/glimmer-dsl-swt.rb
218
218
  - lib/glimmer/data_binding/list_selection_binding.rb
219
- - lib/glimmer/data_binding/model_binding.rb
220
- - lib/glimmer/data_binding/observable.rb
221
- - lib/glimmer/data_binding/observable_array.rb
222
- - lib/glimmer/data_binding/observable_model.rb
223
219
  - lib/glimmer/data_binding/observable_widget.rb
224
- - lib/glimmer/data_binding/observer.rb
225
220
  - lib/glimmer/data_binding/shine.rb
226
221
  - lib/glimmer/data_binding/table_items_binding.rb
227
222
  - lib/glimmer/data_binding/tree_items_binding.rb
@@ -1,248 +0,0 @@
1
- require 'glimmer/data_binding/observable'
2
- require 'glimmer/data_binding/observer'
3
-
4
- module Glimmer
5
- module DataBinding
6
- class ModelBinding
7
- include Observable
8
- include Observer
9
-
10
- attr_reader :binding_options
11
-
12
- def initialize(base_model, property_name_expression, binding_options = nil)
13
- @base_model = base_model
14
- @property_name_expression = property_name_expression
15
- @binding_options = binding_options || {}
16
- if computed?
17
- @computed_model_bindings = computed_by.map do |computed_by_property_expression|
18
- self.class.new(base_model, computed_by_property_expression)
19
- end
20
- end
21
- end
22
-
23
- def model
24
- nested_property? ? nested_model : base_model
25
- end
26
-
27
- # e.g. person.address.state returns [person, person.address]
28
- def nested_models
29
- @nested_models = [base_model]
30
- model_property_names.reduce(base_model) do |reduced_model, nested_model_property_name|
31
- if reduced_model.nil?
32
- nil
33
- else
34
- invoke_property_reader(reduced_model, nested_model_property_name).tap do |new_reduced_model|
35
- @nested_models << new_reduced_model
36
- end
37
- end
38
- end
39
- @nested_models
40
- end
41
-
42
- def nested_model
43
- nested_models.last
44
- end
45
-
46
- def base_model
47
- @base_model
48
- end
49
-
50
- def property_name
51
- nested_property? ? nested_property_name : property_name_expression
52
- end
53
-
54
- def convert_on_read(value)
55
- apply_converter(@binding_options[:on_read], value)
56
- end
57
-
58
- def convert_on_write(value)
59
- apply_converter(@binding_options[:on_write], value)
60
- end
61
-
62
- 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
76
- end
77
-
78
- # All nested property names
79
- # e.g. property name expression "address.state" gives ['address', 'state']
80
- # If there are any indexed property names, this returns indexes as properties.
81
- # e.g. property name expression "addresses[1].state" gives ['addresses', '[1]', 'state']
82
- def nested_property_names
83
- @nested_property_names ||= property_name_expression.split(".").map {|pne| pne.match(/([^\[]+)(\[[^\]]+\])?/).to_a.drop(1)}.flatten.compact
84
- end
85
-
86
- # Final nested property name
87
- # e.g. property name expression "address.state" gives :state
88
- def nested_property_name
89
- nested_property_names.last
90
- end
91
-
92
- # Model representing nested property names
93
- # e.g. property name expression "address.state" gives [:address]
94
- def model_property_names
95
- nested_property_names[0...-1]
96
- end
97
-
98
- def nested_property?
99
- property_name_expression.match(/[.\[]/)
100
- end
101
-
102
- def property_name_expression
103
- @property_name_expression
104
- end
105
-
106
- def computed?
107
- !computed_by.empty?
108
- end
109
-
110
- def computed_by
111
- [@binding_options[:computed_by]].flatten.compact
112
- end
113
-
114
- def nested_property_observers_for(observer)
115
- @nested_property_observers_collection ||= {}
116
- unless @nested_property_observers_collection.has_key?(observer)
117
- @nested_property_observers_collection[observer] = nested_property_names.reduce({}) do |output, property_name|
118
- output.merge(
119
- property_name => Observer.proc do |new_value|
120
- # Ensure reattaching observers when a higher level nested property is updated (e.g. person.address changes reattaches person.address.street observer)
121
- add_observer(observer)
122
- observer.call(evaluate_property)
123
- end
124
- )
125
- end
126
- end
127
- @nested_property_observers_collection[observer]
128
- end
129
-
130
- def add_observer(observer)
131
- if computed?
132
- add_computed_observers(observer)
133
- elsif nested_property?
134
- add_nested_observers(observer)
135
- else
136
- model_binding_observer = Observer.proc do |new_value|
137
- observer.call(evaluate_property)
138
- end
139
- observer_registration = model_binding_observer.observe(model, property_name)
140
- my_registration = observer.registration_for(self)
141
- observer.add_dependent(my_registration => observer_registration)
142
- end
143
- end
144
-
145
- def remove_observer(observer)
146
- if computed?
147
- @computed_model_bindings.each do |computed_model_binding|
148
- computed_observer_for(observer).unobserve(computed_model_binding)
149
- end
150
- @computed_observer_collection.delete(observer)
151
- elsif nested_property?
152
- nested_property_observers_for(observer).clear
153
- else
154
- observer.unobserve(model, property_name)
155
- end
156
- end
157
-
158
- def computed_observer_for(observer)
159
- @computed_observer_collection ||= {}
160
- unless @computed_observer_collection.has_key?(observer)
161
- @computed_observer_collection[observer] = Observer.proc do |new_value|
162
- observer.call(evaluate_property)
163
- end
164
- end
165
- @computed_observer_collection[observer]
166
- end
167
-
168
- def add_computed_observers(observer)
169
- @computed_model_bindings.each do |computed_model_binding|
170
- observer_registration = computed_observer_for(observer).observe(computed_model_binding)
171
- my_registration = observer.registration_for(self)
172
- observer.add_dependent(my_registration => observer_registration)
173
- end
174
- end
175
-
176
- def add_nested_observers(observer)
177
- nested_property_observers = nested_property_observers_for(observer)
178
- nested_models.zip(nested_property_names).each_with_index do |zip, i|
179
- model, property_name = zip
180
- nested_property_observer = nested_property_observers[property_name]
181
- 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]
185
- parent_property_name = nil if parent_property_name.to_s.start_with?('[')
186
- 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
193
- parent_registration = parent_observer.registration_for(parent_model, parent_property_name)
194
- parent_observer.add_dependent(parent_registration => observer_registration)
195
- end
196
- end
197
- end
198
-
199
- def call(value)
200
- return if model.nil?
201
- converted_value = value
202
- invoke_property_writer(model, "#{property_name}=", converted_value) unless evaluate_property == converted_value
203
- end
204
-
205
- def evaluate_property
206
- value = nil
207
- value = invoke_property_reader(model, property_name) unless model.nil?
208
- convert_on_read(value)
209
- end
210
-
211
- def evaluate_options_property
212
- model.send(options_property_name) unless model.nil?
213
- end
214
-
215
- def options_property_name
216
- self.property_name + "_options"
217
- end
218
-
219
- def property_indexed?(property_expression)
220
- property_expression.to_s.start_with?('[')
221
- end
222
-
223
- def invoke_property_reader(object, property_expression)
224
- if property_indexed?(property_expression)
225
- property_method = '[]'
226
- property_argument = property_expression[1...-1]
227
- property_argument = property_argument.to_i if property_argument.match(/\d+/)
228
- object.send(property_method, property_argument)
229
- else
230
- object.send(property_expression)
231
- end
232
- end
233
-
234
- def invoke_property_writer(object, property_expression, value)
235
- return if @binding_options[:read_only]
236
- value = convert_on_write(value)
237
- if property_indexed?(property_expression)
238
- property_method = '[]='
239
- property_argument = property_expression[1...-2]
240
- property_argument = property_argument.to_i if property_argument.match(/\d+/)
241
- object.send(property_method, property_argument, value)
242
- else
243
- object.send(property_expression, value)
244
- end
245
- end
246
- end
247
- end
248
- end
@@ -1,21 +0,0 @@
1
- require 'glimmer/error'
2
-
3
- module Glimmer
4
- module DataBinding
5
- module Observable
6
- # TODO rename methods to observe/unobserve
7
- def add_observer(observer, property_or_properties=nil)
8
- raise Error, 'Not implemented!'
9
- end
10
-
11
- def remove_observer(observer, property_or_properties=nil)
12
- raise Error, 'Not implemented!'
13
- end
14
-
15
- # Overriding inspect to avoid printing very long observer hierarchies
16
- def inspect
17
- "#<#{self.class.name}:0x#{self.hash.to_s(16)}>"
18
- end
19
- end
20
- end
21
- end
@@ -1,107 +0,0 @@
1
- require 'set'
2
-
3
- require_relative 'observable'
4
-
5
- module Glimmer
6
- module DataBinding
7
- # TODO prefix utility methods with double-underscore
8
- module ObservableArray
9
- include Observable
10
-
11
- def add_observer(observer, element_properties=nil)
12
- return observer if has_observer?(observer) && element_properties.nil?
13
- 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
19
- observer
20
- end
21
-
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
28
- end
29
- observer
30
- end
31
-
32
- def has_observer?(observer)
33
- property_observer_list.include?(observer)
34
- end
35
-
36
- def property_observer_list
37
- @property_observer_list ||= Set.new
38
- end
39
-
40
- def notify_observers
41
- property_observer_list.each {|observer| observer.call}
42
- end
43
-
44
- def self.extend_object(array)
45
- # TODO consider alias_method, and define_method instead
46
-
47
- array.instance_eval("alias __original_add <<")
48
- array.instance_eval <<-end_eval, __FILE__, __LINE__
49
- def <<(value)
50
- self.__original_add(value)
51
- notify_observers
52
- end
53
- end_eval
54
-
55
- array.instance_eval("alias __original_set_value []=")
56
- array.instance_eval <<-end_eval, __FILE__, __LINE__
57
- def []=(index, value)
58
- old_value = self[index]
59
- unregister_dependent_observers(old_value)
60
- self.__original_set_value(index, value)
61
- notify_observers
62
- end
63
- end_eval
64
-
65
- array.instance_eval("alias __original_delete delete")
66
- array.instance_eval <<-end_eval, __FILE__, __LINE__
67
- def delete(value)
68
- unregister_dependent_observers(value)
69
- self.__original_delete(value)
70
- notify_observers
71
- end
72
- end_eval
73
-
74
- array.instance_eval("alias __original_delete_at delete_at")
75
- array.instance_eval <<-end_eval, __FILE__, __LINE__
76
- def delete_at(index)
77
- old_value = self[index]
78
- unregister_dependent_observers(old_value)
79
- self.__original_delete_at(index)
80
- notify_observers
81
- end
82
- end_eval
83
-
84
- array.instance_eval("alias __original_clear clear")
85
- array.instance_eval <<-end_eval, __FILE__, __LINE__
86
- def clear
87
- each do |old_value|
88
- unregister_dependent_observers(old_value)
89
- end
90
- self.__original_clear
91
- notify_observers
92
- end
93
- end_eval
94
-
95
- super
96
- end
97
-
98
- def unregister_dependent_observers(old_value)
99
- # TODO look into optimizing this
100
- return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
101
- property_observer_list.each do |observer|
102
- observer.unregister_dependents_with_observable(observer.registration_for(self), old_value)
103
- end
104
- end
105
- end
106
- end
107
- end
@@ -1,108 +0,0 @@
1
- require 'glimmer'
2
-
3
- require_relative 'observable'
4
- require_relative 'observer'
5
-
6
- module Glimmer
7
- module DataBinding
8
- # TODO prefix utility methods with double-underscore
9
- module ObservableModel
10
- include Observable
11
-
12
- class Notifier
13
- include Observer
14
- def initialize(observable_model, property_name)
15
- @observable_model = observable_model
16
- @property_name = property_name
17
- end
18
- def call(new_value=nil)
19
- @observable_model.notify_observers(@property_name)
20
- end
21
- end
22
-
23
- def add_observer(observer, property_name)
24
- return observer if has_observer?(observer, property_name)
25
- property_observer_list(property_name) << observer
26
- add_property_writer_observers(property_name)
27
- observer
28
- end
29
-
30
- def remove_observer(observer, property_name)
31
- property_observer_list(property_name).delete(observer)
32
- end
33
-
34
- def has_observer?(observer, property_name)
35
- property_observer_list(property_name).include?(observer)
36
- end
37
-
38
- def has_observer_for_any_property?(observer)
39
- property_observer_hash.values.map(&:to_a).sum.include?(observer)
40
- end
41
-
42
- def property_observer_hash
43
- @property_observers ||= Hash.new
44
- end
45
-
46
- def property_observer_list(property_name)
47
- property_observer_hash[property_name.to_sym] = Set.new unless property_observer_hash[property_name.to_sym]
48
- property_observer_hash[property_name.to_sym]
49
- end
50
-
51
- def notify_observers(property_name)
52
- property_observer_list(property_name).each {|observer| observer.call(send(property_name))}
53
- end
54
- #TODO upon updating values, make sure dependent observers are cleared (not added as dependents here)
55
-
56
- def add_property_writer_observers(property_name)
57
- property_writer_name = "#{property_name}="
58
- method(property_writer_name)
59
- ensure_array_object_observer(property_name, send(property_name))
60
- begin
61
- method("__original_#{property_writer_name}")
62
- rescue
63
- # TODO consider alias_method or define_method instead
64
- instance_eval "alias __original_#{property_writer_name} #{property_writer_name}"
65
- instance_eval <<-end_eval, __FILE__, __LINE__
66
- def #{property_writer_name}(value)
67
- old_value = self.#{property_name}
68
- unregister_dependent_observers('#{property_name}', old_value)
69
- self.__original_#{property_writer_name}(value)
70
- notify_observers('#{property_name}')
71
- ensure_array_object_observer('#{property_name}', value, old_value)
72
- end
73
- end_eval
74
- end
75
- rescue => e
76
- # ignore writing if no property writer exists
77
- Glimmer::Config.logger&.debug "No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"
78
- end
79
-
80
- def unregister_dependent_observers(property_name, old_value)
81
- # TODO look into optimizing this
82
- return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
83
- property_observer_list(property_name).each do |observer|
84
- observer.unregister_dependents_with_observable(observer.registration_for(self, property_name), old_value)
85
- end
86
- end
87
-
88
- def ensure_array_object_observer(property_name, object, old_object = nil)
89
- return unless object.is_a?(Array)
90
- array_object_observer = array_object_observer_for(property_name)
91
- array_observer_registration = array_object_observer.observe(object)
92
- property_observer_list(property_name).each do |observer|
93
- my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
94
- observer.add_dependent(my_registration => array_observer_registration)
95
- end
96
- array_object_observer_for(property_name).unregister(old_object) if old_object.is_a?(ObservableArray)
97
- end
98
-
99
- def array_object_observer_for(property_name)
100
- @array_object_observers ||= {}
101
- unless @array_object_observers.has_key?(property_name)
102
- @array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name)
103
- end
104
- @array_object_observers[property_name]
105
- end
106
- end
107
- end
108
- end
@@ -1,124 +0,0 @@
1
- require 'glimmer/error'
2
-
3
- module Glimmer
4
- module DataBinding
5
- # Mixin representing Observer trait from Observer Design Pattern
6
- # Allows classes to include without interfering with their
7
- # inheritance hierarchy.
8
- #
9
- # Includes a default implementation that can receive an observer block
10
- # Example: Observer.proc {|new_value| puts new_value}
11
- # Subclasses may override
12
- module Observer
13
- # Observer Proc default implementation that takes an observer block to process updates
14
- # via call method
15
- class Proc
16
- include Observer
17
-
18
- def initialize(&observer_block)
19
- @observer_block = observer_block
20
- end
21
-
22
- # Called by observables once updates occur sending in the new_value if any
23
- def call(new_value=nil)
24
- @observer_block.call(new_value)
25
- end
26
- end
27
-
28
- class Registration < Struct.new(:observer, :observable, :property, keyword_init: true)
29
- def unregister
30
- observer.unobserve(observable, property)
31
- end
32
- alias unobserve unregister
33
- end
34
-
35
- class << self
36
- def proc(&observer_block)
37
- Proc.new(&observer_block)
38
- end
39
- end
40
-
41
- def registrations
42
- @registrations ||= Set.new
43
- end
44
-
45
- def registration_for(observable, property = nil)
46
- Registration.new(observer: self, observable: observable, property: property)
47
- end
48
-
49
- # mapping of registrations to dependents
50
- # {[observable, property] => [[dependent, dependent_observable, dependent_property], ...]}
51
- def dependents
52
- @dependents ||= Hash.new
53
- end
54
-
55
- def dependents_for(registration)
56
- dependents[registration] ||= Set.new
57
- end
58
-
59
- # registers observer in an observable on a property (optional)
60
- # observer maintains registration list to unregister later
61
- def register(observable, property = nil)
62
- unless observable.is_a?(Observable)
63
- # TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle
64
- if observable.is_a?(Array)
65
- observable.extend(ObservableArray)
66
- else
67
- observable.extend(ObservableModel)
68
- end
69
- end
70
- observable.add_observer(*[self, property].compact)
71
- registration_for(observable, property).tap do |registration|
72
- self.registrations << registration
73
- end
74
- end
75
- alias observe register
76
-
77
- def unregister(observable, property = nil)
78
- # TODO optimize performance in the future via indexing and/or making a registration official object/class
79
- observable.remove_observer(*[self, property].compact)
80
- registration = registration_for(observable, property)
81
- dependents_for(registration).each do |dependent|
82
- dependent.unregister
83
- remove_dependent(registration => dependent)
84
- end
85
- registrations.delete(registration)
86
- end
87
- alias unobserve unregister
88
-
89
- def unregister_dependents_with_observable(registration, dependent_observable)
90
- thedependents = dependents_for(registration).select do |thedependent|
91
- thedependent.observable == dependent_observable
92
- end
93
- thedependents.each do |thedependent|
94
- thedependent.unregister
95
- end
96
- end
97
-
98
- # cleans up all registrations in observables
99
- def unregister_all_observables
100
- registrations.each do |registration|
101
- registration.unregister
102
- end
103
- end
104
- alias unobserve_all_observables unregister_all_observables
105
-
106
- # add dependent observer to unregister when unregistering observer
107
- def add_dependent(parent_to_dependent_hash)
108
- registration = parent_to_dependent_hash.keys.first
109
- dependent = parent_to_dependent_hash.values.first
110
- dependents_for(registration) << dependent
111
- end
112
-
113
- def remove_dependent(parent_to_dependent_hash)
114
- registration = parent_to_dependent_hash.keys.first
115
- dependent = parent_to_dependent_hash.values.first
116
- dependents_for(registration).delete(dependent)
117
- end
118
-
119
- def call(new_value)
120
- raise Error, 'Not implemented!'
121
- end
122
- end
123
- end
124
- end