glimmer 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +11 -11
- data/VERSION +1 -1
- data/glimmer.gemspec +4 -4
- data/lib/glimmer/data_binding/model_binding.rb +12 -7
- data/lib/glimmer/data_binding/observable_array.rb +17 -14
- data/lib/glimmer/data_binding/observable_hash.rb +17 -10
- data/lib/glimmer/data_binding/observable_model.rb +12 -10
- data/lib/glimmer/data_binding/observer.rb +39 -26
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6a8921b091e770dd1acb0528bdf8dad0a63e79290ffb457325abf261b4ac8ca
|
4
|
+
data.tar.gz: 4d530d648577640a25943fb55f61918d352f30e2007f7426b739b877cd6a44a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68f5e3c05e2381a6f4855cec0832cc983fc74d0dcf27649efaf9e92dd8cf7aa69f9e171494ee1ab17a6a8d68ce0d71cb9ef61521290d999eaa70ad3915b989f2
|
7
|
+
data.tar.gz: 6b3af9b3d411bed16cc9c9f2f227394675fd255098d64729424e31dfdbf1b7e75d8e3aac102016f31c8b729978e33b44fbca1b0dbecec1d1acffea3651dbc468
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,13 @@
|
|
3
3
|
Related Change Logs:
|
4
4
|
- [glimmer-dsl-swt/CHANGELOG.md](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/CHANGELOG.md)
|
5
5
|
|
6
|
+
### 2.4.0
|
7
|
+
|
8
|
+
- Support passing arbitrary options to `Observer` `#observe` (`#register`) method (not just properties, like `recursive: true` for example)
|
9
|
+
- Make observing nested arrays within an array optional with `recursive: true` option
|
10
|
+
- Make `Observer` `dependents` collection rely on Concurrent::Hash when available
|
11
|
+
- Fix `Observer` cleanup of registrations and dependents on `#deregister` (was not cleaning up everything because observables were changing `#hash` value on content change and slipping through the cracks as a result)
|
12
|
+
|
6
13
|
### 2.3.0
|
7
14
|
|
8
15
|
- Have observing `ObservableArray` automatically notice if any values are nested arrays and observe them for micro-changes (recursively all the way down)
|
data/README.md
CHANGED
@@ -210,7 +210,7 @@ end
|
|
210
210
|
### Setup
|
211
211
|
|
212
212
|
Follow these steps to author a [Glimmer](https://rubygems.org/gems/glimmer) DSL:
|
213
|
-
- Add `gem 'glimmer', '~> 2.
|
213
|
+
- Add `gem 'glimmer', '~> 2.4.0'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.4.0` and add `require 'glimmer'`
|
214
214
|
- Create `glimmer/dsl/[dsl_name]/dsl.rb`, which requires and adds all dynamic expressions for the [dsl_name] Glimmer DSL module as per the code shown in the previous section (or [Official DSLs](#official-dsls) as examples)
|
215
215
|
- Create `glimmer/dsl/[dsl_name]/[expresion_name]_expresion.rb` for every [expresion_name] expression needed, whether dynamic or static
|
216
216
|
|
@@ -856,7 +856,7 @@ Glimmer app:
|
|
856
856
|
|
857
857
|
![glimmer dsl tk screenshot sample hello world](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-tk/master/images/glimmer-dsl-tk-screenshot-sample-hello-world.png)
|
858
858
|
|
859
|
-
###### Hello,
|
859
|
+
###### Hello, Notebook!
|
860
860
|
|
861
861
|
Glimmer code (from [samples/hello/hello_tab.rb](https://github.com/AndyObtiva/glimmer-dsl-tk/blob/master/samples/hello/hello_tab.rb)):
|
862
862
|
|
@@ -864,7 +864,7 @@ Glimmer code (from [samples/hello/hello_tab.rb](https://github.com/AndyObtiva/gl
|
|
864
864
|
include Glimmer
|
865
865
|
|
866
866
|
root {
|
867
|
-
title 'Hello,
|
867
|
+
title 'Hello, Notebook!'
|
868
868
|
|
869
869
|
notebook {
|
870
870
|
frame(text: 'English') {
|
@@ -885,13 +885,13 @@ root {
|
|
885
885
|
Run (with the [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed):
|
886
886
|
|
887
887
|
```
|
888
|
-
ruby -r glimmer-dsl-tk -e "require '../samples/hello/
|
888
|
+
ruby -r glimmer-dsl-tk -e "require '../samples/hello/hello_notebook.rb'"
|
889
889
|
```
|
890
890
|
|
891
891
|
Glimmer app:
|
892
892
|
|
893
|
-
![glimmer dsl tk screenshot sample hello
|
894
|
-
![glimmer dsl tk screenshot sample hello
|
893
|
+
![glimmer dsl tk screenshot sample hello notebook English](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-tk/master/images/glimmer-dsl-tk-screenshot-sample-hello-notebook-english.png)
|
894
|
+
![glimmer dsl tk screenshot sample hello notebook French](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-tk/master/images/glimmer-dsl-tk-screenshot-sample-hello-notebook-french.png)
|
895
895
|
|
896
896
|
###### Hello, Combo!
|
897
897
|
|
@@ -900,7 +900,7 @@ Glimmer code (from [samples/hello/hello_combo.rb](https://github.com/AndyObtiva/
|
|
900
900
|
```ruby
|
901
901
|
# ... more code precedes
|
902
902
|
root {
|
903
|
-
title 'Hello,
|
903
|
+
title 'Hello, Combobox!'
|
904
904
|
|
905
905
|
combobox { |proxy|
|
906
906
|
state 'readonly'
|
@@ -920,13 +920,13 @@ root {
|
|
920
920
|
Run (with the [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed):
|
921
921
|
|
922
922
|
```
|
923
|
-
ruby -r glimmer-dsl-tk -e "require '../samples/hello/
|
923
|
+
ruby -r glimmer-dsl-tk -e "require '../samples/hello/hello_combobox.rb'"
|
924
924
|
```
|
925
925
|
|
926
926
|
Glimmer app:
|
927
927
|
|
928
|
-
![glimmer dsl tk screenshot sample hello combo](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-tk/master/images/glimmer-dsl-tk-screenshot-sample-hello-
|
929
|
-
![glimmer dsl tk screenshot sample hello combo dropdown](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-tk/master/images/glimmer-dsl-tk-screenshot-sample-hello-
|
928
|
+
![glimmer dsl tk screenshot sample hello combo](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-tk/master/images/glimmer-dsl-tk-screenshot-sample-hello-combobox.png)
|
929
|
+
![glimmer dsl tk screenshot sample hello combo dropdown](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-tk/master/images/glimmer-dsl-tk-screenshot-sample-hello-combobox-dropdown.png)
|
930
930
|
|
931
931
|
#### Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library)
|
932
932
|
|
@@ -1163,7 +1163,7 @@ These are the main classes concerning data-binding:
|
|
1163
1163
|
- `Glimmer::DataBinding::Observer`: Provides general observer support including unique registration and deregistration for cleanup and prevention of memory leaks. Main methods concerned are: `call`, `register` (alias: `observe`), and `unregister` (alias: `unobserve` or `deregister`)
|
1164
1164
|
- `Glimmer::DataBinding::Observable`: General super-module for all observables. Main methods concerned are: `add_observer` and `remove_observer`
|
1165
1165
|
- `Glimmer::DataBinding::ObservableModel`: Mixin module for any observable model with observable attributes. In addition to `Observable` methods, it has a `notify_observers` method to be called when changes occur. It automatically enhances all attribute setters (ending with `=`) to notify observers on changes. Also, it automatically handles observing array attributes using `ObservableArray` appropriately so they would notify observers upon array mutation changes.
|
1166
|
-
- `Glimmer::DataBinding::ObservableArray`: Mixin module for any observable array collection that automatically handles notifying observers upon performing array mutation operations (e.g. `push`, `select!`, or `delete`) recursively (meaning if an array contained arrays and they changed, observers are notified)
|
1166
|
+
- `Glimmer::DataBinding::ObservableArray`: Mixin module for any observable array collection that automatically handles notifying observers upon performing array mutation operations (e.g. `push`, `select!`, or `delete`) recursively (meaning if an array contained arrays and they changed, observers are notified). Accepts `recursive: true` option in `add_observer` method to recursively observe nested arrays all the way down.
|
1167
1167
|
- `Glimmer::DataBinding::ObservableHash`: Mixin module for any observable hash that automatically handles notifying observers upon performing hash mutation operations (e.g. `hash[key]=value`, `select!`, `merge!`)
|
1168
1168
|
- `Glimmer::DataBinding::ModelBinding`: a higher-level abstraction that relies on all the other observer/observable classes to support basic data-binding, nested data-binding, and computed data-binding
|
1169
1169
|
- `Glimmer::DataBinding::Shine`: enables highly intuitive and visually expressive syntax to perform bidirectional (two-way) data-binding with `<=>` and unidirectional (one-way) data-binding with `<=`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.4.0
|
data/glimmer.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: glimmer 2.
|
5
|
+
# stub: glimmer 2.4.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "glimmer".freeze
|
9
|
-
s.version = "2.
|
9
|
+
s.version = "2.4.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["AndyMaleh".freeze]
|
14
|
-
s.date = "2021-10-
|
14
|
+
s.date = "2021-10-15"
|
15
15
|
s.description = "Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of a DSL Engine and an Observable / Observer / Data-Binding Library (including Observable Model, Observable Array, and Observable Hash). Used in Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), Glimmer DSL for Tk (Ruby Desktop Development GUI Library), Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library), Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), Glimmer DSL for XML (& HTML), and Glimmer DSL for CSS.".freeze
|
16
16
|
s.email = "andy.am@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
@@ -51,7 +51,7 @@ Gem::Specification.new do |s|
|
|
51
51
|
]
|
52
52
|
s.homepage = "http://github.com/AndyObtiva/glimmer".freeze
|
53
53
|
s.licenses = ["MIT".freeze]
|
54
|
-
s.rubygems_version = "3.2.
|
54
|
+
s.rubygems_version = "3.2.22".freeze
|
55
55
|
s.summary = "Glimmer - DSL Engine for Ruby GUI and More".freeze
|
56
56
|
|
57
57
|
if s.respond_to? :specification_version then
|
@@ -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)
|
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,13 +196,13 @@ 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
|
@@ -45,32 +45,34 @@ module Glimmer
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def add_observer(observer, *
|
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
53
|
property_observer_list << observer
|
52
54
|
observer_element_properties[observer] = element_properties_for(observer) + Concurrent::Set.new(element_properties)
|
53
|
-
each { |element| add_element_observer(element, observer) }
|
55
|
+
each { |element| add_element_observer(element, observer, options) }
|
54
56
|
observer
|
55
57
|
end
|
56
58
|
|
57
|
-
def add_element_observers(element)
|
59
|
+
def add_element_observers(element, options = {})
|
58
60
|
property_observer_list.each do |observer|
|
59
|
-
add_element_observer(element, observer)
|
61
|
+
add_element_observer(element, observer, options)
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
|
-
def add_element_observer(element, observer)
|
65
|
+
def add_element_observer(element, observer, options = {})
|
64
66
|
element_properties_for(observer).each do |property|
|
65
|
-
observer.observe(element, property)
|
67
|
+
observer.observe(element, property, options)
|
66
68
|
end
|
67
|
-
ensure_array_object_observer(element) if element.is_a?(Array)
|
69
|
+
ensure_array_object_observer(element, options) if options[:recursive] && element.is_a?(Array)
|
68
70
|
end
|
69
71
|
|
70
|
-
def ensure_array_object_observer(object)
|
72
|
+
def ensure_array_object_observer(object, options)
|
71
73
|
return unless object&.is_a?(Array)
|
72
74
|
array_object_observer = array_object_observer_for(object)
|
73
|
-
array_observer_registration = array_object_observer.observe(object)
|
75
|
+
array_observer_registration = array_object_observer.observe(object, options)
|
74
76
|
property_observer_list.each do |observer|
|
75
77
|
my_registration = observer.registration_for(self)
|
76
78
|
observer.add_dependent(my_registration => array_observer_registration)
|
@@ -83,7 +85,9 @@ module Glimmer
|
|
83
85
|
@array_object_observers[object]
|
84
86
|
end
|
85
87
|
|
86
|
-
def remove_observer(observer, *
|
88
|
+
def remove_observer(observer, *args)
|
89
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
90
|
+
element_properties = args
|
87
91
|
element_properties = element_properties.flatten.compact.uniq
|
88
92
|
if !element_properties.empty?
|
89
93
|
old_element_properties = element_properties_for(observer)
|
@@ -110,10 +114,8 @@ module Glimmer
|
|
110
114
|
end
|
111
115
|
if element.is_a?(ObservableArray)
|
112
116
|
array_object_observer_for(element).unobserve(element)
|
113
|
-
element.property_observer_list.select {|o| o.observable_array == self}.each do |o|
|
114
|
-
o.
|
115
|
-
registration.deregister
|
116
|
-
end
|
117
|
+
element.property_observer_list.select {|o| o.respond_to?(:observable_array) && o.observable_array == self}.each do |o|
|
118
|
+
o.deregister_all_observables
|
117
119
|
@array_object_observers.reject! {|k, v| v == o}
|
118
120
|
end
|
119
121
|
end
|
@@ -245,6 +247,7 @@ module Glimmer
|
|
245
247
|
alias map! collect!
|
246
248
|
|
247
249
|
def compact!
|
250
|
+
# TODO consider checking which exact indices changed and only notifying if there is a change
|
248
251
|
super.tap { notify_observers }
|
249
252
|
end
|
250
253
|
|
@@ -62,14 +62,19 @@ module Glimmer
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def add_observer(observer, key = nil)
|
65
|
+
def add_observer(observer, key = nil, options = {})
|
66
|
+
if key.is_a?(Hash)
|
67
|
+
options = key
|
68
|
+
key = nil
|
69
|
+
end
|
66
70
|
return observer if has_observer?(observer, key)
|
67
71
|
key_observer_list(key) << observer
|
68
|
-
add_key_writer_observer(key)
|
72
|
+
add_key_writer_observer(key, options)
|
69
73
|
observer
|
70
74
|
end
|
71
75
|
|
72
|
-
def remove_observer(observer, key = nil)
|
76
|
+
def remove_observer(observer, key = nil, options = {})
|
77
|
+
old_value = self[key]
|
73
78
|
if has_observer?(observer, key)
|
74
79
|
key_observer_list(key).delete(observer)
|
75
80
|
observer.unobserve(self, key)
|
@@ -118,9 +123,9 @@ module Glimmer
|
|
118
123
|
(key_observer_list(key).to_a - all_key_observer_list.to_a).each { |observer| observer.call(self[key], key) }
|
119
124
|
end
|
120
125
|
|
121
|
-
def add_key_writer_observer(key = nil)
|
122
|
-
ensure_array_object_observer(key, self[key])
|
123
|
-
ensure_hash_object_observer(key, self[key])
|
126
|
+
def add_key_writer_observer(key = nil, options)
|
127
|
+
ensure_array_object_observer(key, self[key], nil, options)
|
128
|
+
ensure_hash_object_observer(key, self[key], nil, options)
|
124
129
|
begin
|
125
130
|
method('__original__store')
|
126
131
|
rescue
|
@@ -143,10 +148,11 @@ module Glimmer
|
|
143
148
|
end
|
144
149
|
alias deregister_dependent_observers unregister_dependent_observers
|
145
150
|
|
146
|
-
def ensure_array_object_observer(key, object, old_object = nil)
|
151
|
+
def ensure_array_object_observer(key, object, old_object = nil, options = {})
|
152
|
+
options ||= {}
|
147
153
|
return unless object&.is_a?(Array)
|
148
154
|
array_object_observer = array_object_observer_for(key)
|
149
|
-
array_observer_registration = array_object_observer.observe(object)
|
155
|
+
array_observer_registration = array_object_observer.observe(object, options)
|
150
156
|
key_observer_list(key).each do |observer|
|
151
157
|
my_registration = observer.registration_for(self, key) # TODO eliminate repetition
|
152
158
|
observer.add_dependent(my_registration => array_observer_registration)
|
@@ -160,10 +166,11 @@ module Glimmer
|
|
160
166
|
@array_object_observers[key]
|
161
167
|
end
|
162
168
|
|
163
|
-
def ensure_hash_object_observer(key, object, old_object = nil)
|
169
|
+
def ensure_hash_object_observer(key, object, old_object = nil, options = {})
|
170
|
+
options ||= {}
|
164
171
|
return unless object&.is_a?(Hash)
|
165
172
|
hash_object_observer = hash_object_observer_for(key)
|
166
|
-
hash_observer_registration = hash_object_observer.observe(object)
|
173
|
+
hash_observer_registration = hash_object_observer.observe(object, options)
|
167
174
|
key_observer_list(key).each do |observer|
|
168
175
|
my_registration = observer.registration_for(self, key) # TODO eliminate repetition
|
169
176
|
observer.add_dependent(my_registration => hash_observer_registration)
|
@@ -52,14 +52,14 @@ module Glimmer
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def add_observer(observer, property_name)
|
55
|
+
def add_observer(observer, property_name, options = {})
|
56
56
|
return observer if has_observer?(observer, property_name)
|
57
57
|
property_observer_list(property_name) << observer
|
58
|
-
add_property_writer_observers(property_name)
|
58
|
+
add_property_writer_observers(property_name, options)
|
59
59
|
observer
|
60
60
|
end
|
61
61
|
|
62
|
-
def remove_observer(observer, property_name)
|
62
|
+
def remove_observer(observer, property_name, options = {})
|
63
63
|
if has_observer?(observer, property_name)
|
64
64
|
property_observer_list(property_name).delete(observer)
|
65
65
|
observer.unobserve(self, property_name)
|
@@ -103,11 +103,11 @@ module Glimmer
|
|
103
103
|
property_observer_list(property_name).to_a.each { |observer| observer.call(send(property_name)) }
|
104
104
|
end
|
105
105
|
|
106
|
-
def add_property_writer_observers(property_name)
|
106
|
+
def add_property_writer_observers(property_name, options)
|
107
107
|
property_writer_name = "#{property_name}="
|
108
108
|
method(property_writer_name)
|
109
|
-
ensure_array_object_observer(property_name, send(property_name))
|
110
|
-
ensure_hash_object_observer(property_name, send(property_name))
|
109
|
+
ensure_array_object_observer(property_name, send(property_name), nil, options)
|
110
|
+
ensure_hash_object_observer(property_name, send(property_name), nil, options)
|
111
111
|
begin
|
112
112
|
method("__original__#{property_writer_name}")
|
113
113
|
rescue
|
@@ -130,10 +130,11 @@ module Glimmer
|
|
130
130
|
end
|
131
131
|
alias deregister_dependent_observers unregister_dependent_observers
|
132
132
|
|
133
|
-
def ensure_array_object_observer(property_name, object, old_object = nil)
|
133
|
+
def ensure_array_object_observer(property_name, object, old_object = nil, options = {})
|
134
|
+
options ||= {}
|
134
135
|
return unless object&.is_a?(Array)
|
135
136
|
array_object_observer = array_object_observer_for(property_name)
|
136
|
-
array_observer_registration = array_object_observer.observe(object)
|
137
|
+
array_observer_registration = array_object_observer.observe(object, options)
|
137
138
|
property_observer_list(property_name).each do |observer|
|
138
139
|
my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
|
139
140
|
observer.add_dependent(my_registration => array_observer_registration)
|
@@ -147,10 +148,11 @@ module Glimmer
|
|
147
148
|
@array_object_observers[property_name]
|
148
149
|
end
|
149
150
|
|
150
|
-
def ensure_hash_object_observer(property_name, object, old_object = nil)
|
151
|
+
def ensure_hash_object_observer(property_name, object, old_object = nil, options)
|
152
|
+
options ||= {}
|
151
153
|
return unless object&.is_a?(Hash)
|
152
154
|
hash_object_observer = hash_object_observer_for(property_name)
|
153
|
-
hash_observer_registration = hash_object_observer.observe(object)
|
155
|
+
hash_observer_registration = hash_object_observer.observe(object, options)
|
154
156
|
property_observer_list(property_name).each do |observer|
|
155
157
|
my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
|
156
158
|
observer.add_dependent(my_registration => hash_observer_registration)
|
@@ -46,9 +46,9 @@ module Glimmer
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
class Registration < Struct.new(:observer, :observable, :
|
49
|
+
class Registration < Struct.new(:observer, :observable, :args, keyword_init: true)
|
50
50
|
def unregister
|
51
|
-
observer.unobserve(observable,
|
51
|
+
observer.unobserve(observable, *args)
|
52
52
|
end
|
53
53
|
alias unobserve unregister
|
54
54
|
alias deregister unregister
|
@@ -61,29 +61,31 @@ module Glimmer
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def registrations
|
64
|
-
@registrations ||= Concurrent::
|
64
|
+
@registrations ||= Concurrent::Hash.new
|
65
65
|
end
|
66
66
|
|
67
|
-
def registration_for(observable,
|
68
|
-
|
67
|
+
def registration_for(observable, *args)
|
68
|
+
args = compact_args(args)
|
69
|
+
registrations[[observable.object_id, args]] ||= Registration.new(observer: self, observable: observable, args: args)
|
69
70
|
end
|
71
|
+
alias ensure_registration_for! registration_for
|
70
72
|
|
71
73
|
# mapping of registrations to dependents
|
72
74
|
# {[observable, property] => [[dependent, dependent_observable, dependent_property], ...]}
|
73
75
|
def dependents
|
74
|
-
@dependents ||= Hash.new
|
76
|
+
@dependents ||= Concurrent::Hash.new
|
75
77
|
end
|
76
78
|
|
77
79
|
def dependents_for(registration)
|
78
|
-
dependents[registration] ||= Concurrent::Set.new
|
80
|
+
dependents[registration.object_id] ||= Concurrent::Set.new
|
79
81
|
end
|
80
82
|
|
81
|
-
# registers observer in an observable on a property (optional)
|
83
|
+
# registers observer in an observable on args usually containing a property and options (optional)
|
82
84
|
# observer maintains registration list to unregister later
|
83
|
-
def register(observable,
|
85
|
+
def register(observable, *args)
|
84
86
|
return if observable.nil?
|
85
87
|
unless observable.is_a?(Observable)
|
86
|
-
# TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle
|
88
|
+
# TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle (e.g. for SomeClass, search if there is ObservableSomeClass)
|
87
89
|
if observable.is_a?(Array)
|
88
90
|
observable.extend(ObservableArray)
|
89
91
|
elsif observable.is_a?(Hash)
|
@@ -92,23 +94,23 @@ module Glimmer
|
|
92
94
|
observable.extend(ObservableModel)
|
93
95
|
end
|
94
96
|
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
97
|
+
args = compact_args(args)
|
98
|
+
observable.add_observer(self, *args)
|
99
|
+
ensure_registration_for!(observable, *args)
|
99
100
|
end
|
100
101
|
alias observe register
|
101
102
|
|
102
|
-
def unregister(observable,
|
103
|
+
def unregister(observable, *args)
|
103
104
|
return unless observable.is_a?(Observable)
|
104
|
-
|
105
|
-
registration = registration_for(observable,
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
args = compact_args(args)
|
106
|
+
registration = registration_for(observable, *args)
|
107
|
+
registrations.delete([observable.object_id, args])
|
108
|
+
registration.tap do |registration|
|
109
|
+
dependents_for(registration).each do |dependent|
|
110
|
+
remove_dependent(registration => dependent)
|
111
|
+
dependent.deregister if dependent != registration
|
112
|
+
end
|
113
|
+
observable.remove_observer(self, *args)
|
112
114
|
end
|
113
115
|
end
|
114
116
|
alias unobserve unregister
|
@@ -118,14 +120,17 @@ module Glimmer
|
|
118
120
|
thedependents = dependents_for(registration).select do |thedependent|
|
119
121
|
thedependent.observable == dependent_observable
|
120
122
|
end
|
121
|
-
thedependents.each(&:
|
123
|
+
thedependents.each(&:deregister)
|
122
124
|
end
|
123
125
|
alias unobserve_dependents_with_observable unregister_dependents_with_observable
|
124
126
|
alias deregister_dependents_with_observable unregister_dependents_with_observable
|
125
127
|
|
126
128
|
# cleans up all registrations in observables
|
127
129
|
def unregister_all_observables
|
128
|
-
registrations.each
|
130
|
+
registrations.values.dup.each do |registration|
|
131
|
+
registration.deregister
|
132
|
+
registrations.delete([registration.observable.object_id, registration.args])
|
133
|
+
end
|
129
134
|
end
|
130
135
|
alias unobserve_all_observables unregister_all_observables
|
131
136
|
alias deregister_all_observables unregister_all_observables
|
@@ -140,12 +145,20 @@ module Glimmer
|
|
140
145
|
def remove_dependent(parent_to_dependent_hash)
|
141
146
|
registration = parent_to_dependent_hash.keys.first
|
142
147
|
dependent = parent_to_dependent_hash.values.first
|
143
|
-
dependents_for(registration).delete(dependent)
|
148
|
+
dependents_for(registration).delete(dependent).tap do
|
149
|
+
dependents.delete([registration.object_id]) if dependents_for(registration).empty?
|
150
|
+
end
|
144
151
|
end
|
145
152
|
|
146
153
|
def call(new_value = nil, *extra_args)
|
147
154
|
raise Error, 'Not implemented!'
|
148
155
|
end
|
156
|
+
|
157
|
+
def compact_args(args)
|
158
|
+
args = args[0...-1] if args.last == {}
|
159
|
+
args = args[0...-1] if args.last == []
|
160
|
+
args.compact
|
161
|
+
end
|
149
162
|
end
|
150
163
|
end
|
151
164
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: array_include_methods
|
@@ -264,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
264
264
|
- !ruby/object:Gem::Version
|
265
265
|
version: '0'
|
266
266
|
requirements: []
|
267
|
-
rubygems_version: 3.2.
|
267
|
+
rubygems_version: 3.2.22
|
268
268
|
signing_key:
|
269
269
|
specification_version: 4
|
270
270
|
summary: Glimmer - DSL Engine for Ruby GUI and More
|