glimmer 2.4.0 → 2.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/README.md +229 -139
- data/VERSION +1 -1
- data/glimmer.gemspec +90 -89
- data/lib/glimmer/data_binding/model_binding.rb +19 -8
- data/lib/glimmer/data_binding/observable_array.rb +21 -15
- data/lib/glimmer/data_binding/observable_hash.rb +3 -61
- data/lib/glimmer/data_binding/observable_hashable.rb +75 -0
- data/lib/glimmer/data_binding/observable_model.rb +27 -35
- data/lib/glimmer/data_binding/observer.rb +16 -14
- metadata +10 -8
data/glimmer.gemspec
CHANGED
@@ -1,89 +1,90 @@
|
|
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 2.
|
6
|
-
|
7
|
-
Gem::Specification.new do |s|
|
8
|
-
s.name = "glimmer".freeze
|
9
|
-
s.version = "2.
|
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 = "2021-
|
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
|
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_hash.rb",
|
36
|
-
"lib/glimmer/data_binding/
|
37
|
-
"lib/glimmer/data_binding/
|
38
|
-
"lib/glimmer/data_binding/
|
39
|
-
"lib/glimmer/
|
40
|
-
"lib/glimmer/dsl/
|
41
|
-
"lib/glimmer/dsl/
|
42
|
-
"lib/glimmer/dsl/
|
43
|
-
"lib/glimmer/dsl/
|
44
|
-
"lib/glimmer/dsl/
|
45
|
-
"lib/glimmer/dsl/
|
46
|
-
"lib/glimmer/dsl/
|
47
|
-
"lib/glimmer/
|
48
|
-
"lib/glimmer/
|
49
|
-
"lib/glimmer/
|
50
|
-
"lib/glimmer/
|
51
|
-
|
52
|
-
|
53
|
-
s.
|
54
|
-
s.
|
55
|
-
s.
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
s.add_runtime_dependency(%q<
|
64
|
-
s.
|
65
|
-
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
66
|
-
s.add_development_dependency(%q<
|
67
|
-
s.add_development_dependency(%q<
|
68
|
-
s.add_development_dependency(%q<
|
69
|
-
s.add_development_dependency(%q<
|
70
|
-
s.add_development_dependency(%q<
|
71
|
-
s.add_development_dependency(%q<
|
72
|
-
s.add_development_dependency(%q<simplecov
|
73
|
-
s.add_development_dependency(%q<
|
74
|
-
|
75
|
-
|
76
|
-
s.add_dependency(%q<
|
77
|
-
s.add_dependency(%q<
|
78
|
-
s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
79
|
-
s.add_dependency(%q<
|
80
|
-
s.add_dependency(%q<
|
81
|
-
s.add_dependency(%q<
|
82
|
-
s.add_dependency(%q<
|
83
|
-
s.add_dependency(%q<
|
84
|
-
s.add_dependency(%q<
|
85
|
-
s.add_dependency(%q<simplecov
|
86
|
-
s.add_dependency(%q<
|
87
|
-
|
88
|
-
end
|
89
|
-
|
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 2.5.3 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "glimmer".freeze
|
9
|
+
s.version = "2.5.3"
|
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 = "2021-12-07"
|
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 Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), Glimmer DSL for Tk (Ruby Desktop Development GUI Library), Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library), Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library), Glimmer DSL for XML (& HTML), and 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_hash.rb",
|
36
|
+
"lib/glimmer/data_binding/observable_hashable.rb",
|
37
|
+
"lib/glimmer/data_binding/observable_model.rb",
|
38
|
+
"lib/glimmer/data_binding/observer.rb",
|
39
|
+
"lib/glimmer/data_binding/shine.rb",
|
40
|
+
"lib/glimmer/dsl/bind_expression.rb",
|
41
|
+
"lib/glimmer/dsl/engine.rb",
|
42
|
+
"lib/glimmer/dsl/expression.rb",
|
43
|
+
"lib/glimmer/dsl/expression_handler.rb",
|
44
|
+
"lib/glimmer/dsl/observe_expression.rb",
|
45
|
+
"lib/glimmer/dsl/parent_expression.rb",
|
46
|
+
"lib/glimmer/dsl/static_expression.rb",
|
47
|
+
"lib/glimmer/dsl/top_level_expression.rb",
|
48
|
+
"lib/glimmer/error.rb",
|
49
|
+
"lib/glimmer/ext/module.rb",
|
50
|
+
"lib/glimmer/invalid_keyword_error.rb",
|
51
|
+
"lib/glimmer/shim/concurrent.rb"
|
52
|
+
]
|
53
|
+
s.homepage = "http://github.com/AndyObtiva/glimmer".freeze
|
54
|
+
s.licenses = ["MIT".freeze]
|
55
|
+
s.rubygems_version = "3.2.22".freeze
|
56
|
+
s.summary = "Glimmer - DSL Engine for Ruby GUI and More".freeze
|
57
|
+
|
58
|
+
if s.respond_to? :specification_version then
|
59
|
+
s.specification_version = 4
|
60
|
+
end
|
61
|
+
|
62
|
+
if s.respond_to? :add_runtime_dependency then
|
63
|
+
s.add_runtime_dependency(%q<array_include_methods>.freeze, ["~> 1.4.0"])
|
64
|
+
s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
|
65
|
+
s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
|
66
|
+
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
67
|
+
s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.13"])
|
68
|
+
s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
|
69
|
+
s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
|
70
|
+
s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
|
71
|
+
s.add_development_dependency(%q<coveralls>.freeze, [">= 0"])
|
72
|
+
s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
|
73
|
+
s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
|
74
|
+
s.add_development_dependency(%q<rake-tui>.freeze, ["> 0"])
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<array_include_methods>.freeze, ["~> 1.4.0"])
|
77
|
+
s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
|
78
|
+
s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
|
79
|
+
s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
80
|
+
s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.13"])
|
81
|
+
s.add_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
|
82
|
+
s.add_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
|
83
|
+
s.add_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
|
84
|
+
s.add_dependency(%q<coveralls>.freeze, [">= 0"])
|
85
|
+
s.add_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
|
86
|
+
s.add_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
|
87
|
+
s.add_dependency(%q<rake-tui>.freeze, ["> 0"])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -30,9 +30,9 @@ module Glimmer
|
|
30
30
|
|
31
31
|
attr_reader :binding_options, :property_name_expression
|
32
32
|
|
33
|
-
def initialize(
|
34
|
-
|
35
|
-
@property_name_expression =
|
33
|
+
def initialize(*args)
|
34
|
+
binding_options = args.pop if args.size > 1 && args.last.is_a?(Hash)
|
35
|
+
@base_model, @property_name_expression = args
|
36
36
|
@binding_options = binding_options || Concurrent::Hash.new
|
37
37
|
if computed?
|
38
38
|
@computed_model_bindings = Concurrent::Array.new(computed_by.map do |computed_by_property_expression|
|
@@ -91,7 +91,7 @@ module Glimmer
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def nested_property?
|
94
|
-
property_name_expression.match(/[.\[]/)
|
94
|
+
property_name_expression.to_s.match(/[.\[]/)
|
95
95
|
end
|
96
96
|
|
97
97
|
def computed?
|
@@ -137,7 +137,7 @@ module Glimmer
|
|
137
137
|
apply_processor(@binding_options[:after_read], converted_value)
|
138
138
|
end
|
139
139
|
end
|
140
|
-
observer_registration = model_binding_observer.observe(model, property_name, observation_options)
|
140
|
+
observer_registration = model_binding_observer.observe(*[model, property_name, observation_options].compact)
|
141
141
|
my_registration = observer.registration_for(self)
|
142
142
|
observer.add_dependent(my_registration => observer_registration)
|
143
143
|
end
|
@@ -206,7 +206,7 @@ module Glimmer
|
|
206
206
|
def call(value, *extra_args)
|
207
207
|
return if model.nil?
|
208
208
|
converted_value = value
|
209
|
-
invoke_property_writer(model, "#{property_name}=", converted_value) unless converted_value == evaluate_property
|
209
|
+
invoke_property_writer(model, model.is_a?(Hash) ? property_name : "#{property_name}=", converted_value) unless converted_value == evaluate_property || property_name.nil?
|
210
210
|
end
|
211
211
|
|
212
212
|
def evaluate_property
|
@@ -263,11 +263,18 @@ module Glimmer
|
|
263
263
|
property_argument = property_argument.to_i if property_argument.match(/\d+/)
|
264
264
|
object.send(property_method, property_argument)
|
265
265
|
else
|
266
|
-
|
266
|
+
if property_expression.nil?
|
267
|
+
object
|
268
|
+
elsif object.is_a?(Hash)
|
269
|
+
object[property_expression]
|
270
|
+
else
|
271
|
+
object.send(property_expression)
|
272
|
+
end
|
267
273
|
end
|
268
274
|
end
|
269
275
|
|
270
276
|
def invoke_property_writer(object, property_expression, value)
|
277
|
+
return if property_expression.nil?
|
271
278
|
raise "Cannot invoke `#{property_expression}` because ModelBinding#binding_options[:read_only]=true" if @binding_options[:read_only]
|
272
279
|
apply_processor(@binding_options[:before_write], value)
|
273
280
|
converted_value = convert_on_write(value)
|
@@ -277,7 +284,11 @@ module Glimmer
|
|
277
284
|
property_argument = property_argument.to_i if property_argument.match(/\d+/)
|
278
285
|
object.send(property_method, property_argument, converted_value)
|
279
286
|
else
|
280
|
-
object.
|
287
|
+
if object.is_a?(Hash)
|
288
|
+
object[property_expression] = converted_value
|
289
|
+
else
|
290
|
+
object.send(property_expression, converted_value)
|
291
|
+
end
|
281
292
|
end
|
282
293
|
apply_processor(@binding_options[:after_write], converted_value)
|
283
294
|
end
|
@@ -50,15 +50,19 @@ module Glimmer
|
|
50
50
|
element_properties = args
|
51
51
|
element_properties = element_properties.flatten.compact.uniq
|
52
52
|
return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
|
53
|
-
property_observer_list
|
54
|
-
observer_element_properties[observer] = element_properties_for(observer) + Concurrent::
|
53
|
+
property_observer_list[observer] = options
|
54
|
+
observer_element_properties[observer] = Concurrent::Set.new(Concurrent::Array.new(element_properties_for(observer).to_a) + Concurrent::Array.new(element_properties)) # converting to Array as a workaround to jruby-9.3.2.0 issue TODO remove this workaround when no longer needed
|
55
|
+
if !options.empty? && options[:recursive].is_a?(Integer)
|
56
|
+
options = options.clone
|
57
|
+
options[:recursive] = options[:recursive] - 1
|
58
|
+
end
|
55
59
|
each { |element| add_element_observer(element, observer, options) }
|
56
60
|
observer
|
57
61
|
end
|
58
62
|
|
59
|
-
def add_element_observers(element,
|
60
|
-
property_observer_list.each do |observer|
|
61
|
-
add_element_observer(element, observer, options)
|
63
|
+
def add_element_observers(element, general_options = {})
|
64
|
+
property_observer_list.each do |observer, options|
|
65
|
+
add_element_observer(element, observer, options.merge(general_options))
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
@@ -66,14 +70,16 @@ module Glimmer
|
|
66
70
|
element_properties_for(observer).each do |property|
|
67
71
|
observer.observe(element, property, options)
|
68
72
|
end
|
69
|
-
|
73
|
+
if element.is_a?(Array) && (options[:recursive] == true || (options[:recursive].is_a?(Integer) && options[:recursive] >= 0))
|
74
|
+
ensure_array_object_observer(element, options)
|
75
|
+
end
|
70
76
|
end
|
71
77
|
|
72
78
|
def ensure_array_object_observer(object, options)
|
73
79
|
return unless object&.is_a?(Array)
|
74
80
|
array_object_observer = array_object_observer_for(object)
|
75
81
|
array_observer_registration = array_object_observer.observe(object, options)
|
76
|
-
property_observer_list.each do |observer|
|
82
|
+
property_observer_list.each do |observer, options|
|
77
83
|
my_registration = observer.registration_for(self)
|
78
84
|
observer.add_dependent(my_registration => array_observer_registration)
|
79
85
|
end
|
@@ -91,7 +97,7 @@ module Glimmer
|
|
91
97
|
element_properties = element_properties.flatten.compact.uniq
|
92
98
|
if !element_properties.empty?
|
93
99
|
old_element_properties = element_properties_for(observer)
|
94
|
-
observer_element_properties[observer] = element_properties_for(observer) - Concurrent::
|
100
|
+
observer_element_properties[observer] = Concurrent::Set.new(Concurrent::Array.new(element_properties_for(observer).to_a) - Concurrent::Array.new(element_properties)) # TODO remove this workaround when no longer needed (it is for jruby-9.3.2.0 issue)
|
95
101
|
each { |element| element_properties.each { |property| observer.unobserve(element, property) } }
|
96
102
|
end
|
97
103
|
if element_properties_for(observer).empty?
|
@@ -103,7 +109,7 @@ module Glimmer
|
|
103
109
|
end
|
104
110
|
|
105
111
|
def remove_element_observers(element)
|
106
|
-
property_observer_list.each do |observer|
|
112
|
+
property_observer_list.each do |observer, options|
|
107
113
|
remove_element_observer(element, observer)
|
108
114
|
end
|
109
115
|
end
|
@@ -114,15 +120,15 @@ module Glimmer
|
|
114
120
|
end
|
115
121
|
if element.is_a?(ObservableArray)
|
116
122
|
array_object_observer_for(element).unobserve(element)
|
117
|
-
element.property_observer_list.select {|
|
118
|
-
o.deregister_all_observables
|
123
|
+
element.property_observer_list.select {|obs, opt| obs.respond_to?(:observable_array) && obs.observable_array == self}.each do |o|
|
124
|
+
o.deregister_all_observables if o.respond_to?(:deregister_all_observables)
|
119
125
|
@array_object_observers.reject! {|k, v| v == o}
|
120
126
|
end
|
121
127
|
end
|
122
128
|
end
|
123
129
|
|
124
130
|
def has_observer?(observer)
|
125
|
-
property_observer_list.include?(observer)
|
131
|
+
property_observer_list.keys.include?(observer)
|
126
132
|
end
|
127
133
|
|
128
134
|
def has_observer_element_properties?(observer, element_properties)
|
@@ -130,7 +136,7 @@ module Glimmer
|
|
130
136
|
end
|
131
137
|
|
132
138
|
def property_observer_list
|
133
|
-
@property_observer_list ||= Concurrent::
|
139
|
+
@property_observer_list ||= Concurrent::Hash.new
|
134
140
|
end
|
135
141
|
|
136
142
|
def observer_element_properties
|
@@ -142,7 +148,7 @@ module Glimmer
|
|
142
148
|
end
|
143
149
|
|
144
150
|
def notify_observers
|
145
|
-
property_observer_list.to_a.each { |
|
151
|
+
property_observer_list.to_a.each { |obs, opt| obs.call(self) }
|
146
152
|
end
|
147
153
|
|
148
154
|
def <<(element)
|
@@ -366,7 +372,7 @@ module Glimmer
|
|
366
372
|
|
367
373
|
def unregister_dependent_observers(old_value)
|
368
374
|
return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
|
369
|
-
property_observer_list.each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
|
375
|
+
property_observer_list.each { |observer, options| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
|
370
376
|
end
|
371
377
|
alias deregister_dependent_observers unregister_dependent_observers
|
372
378
|
end
|
@@ -19,13 +19,13 @@
|
|
19
19
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
21
|
|
22
|
-
require 'glimmer/data_binding/
|
22
|
+
require 'glimmer/data_binding/observable_hashable'
|
23
23
|
require 'glimmer/data_binding/observer'
|
24
24
|
|
25
25
|
module Glimmer
|
26
26
|
module DataBinding
|
27
27
|
module ObservableHash
|
28
|
-
include
|
28
|
+
include ObservableHashable
|
29
29
|
|
30
30
|
class Notifier
|
31
31
|
include Observer
|
@@ -40,28 +40,6 @@ module Glimmer
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
OBSERVED_STORE_METHOD = lambda do |key, value|
|
44
|
-
if key_observer_list(key).empty?
|
45
|
-
if all_key_observer_list.empty?
|
46
|
-
self.send('__original__store', key, value)
|
47
|
-
else
|
48
|
-
old_value = self[key]
|
49
|
-
unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
|
50
|
-
self.send('__original__store', key, value)
|
51
|
-
notify_observers(key)
|
52
|
-
ensure_array_object_observer(nil, value, old_value)
|
53
|
-
ensure_hash_object_observer(nil, value, old_value)
|
54
|
-
end
|
55
|
-
else
|
56
|
-
old_value = self[key]
|
57
|
-
unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer and ensure_hash_object_observer
|
58
|
-
self.send('__original__store', key, value)
|
59
|
-
notify_observers(key)
|
60
|
-
ensure_array_object_observer(key, value, old_value)
|
61
|
-
ensure_hash_object_observer(key, value, old_value)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
43
|
def add_observer(observer, key = nil, options = {})
|
66
44
|
if key.is_a?(Hash)
|
67
45
|
options = key
|
@@ -106,7 +84,7 @@ module Glimmer
|
|
106
84
|
end
|
107
85
|
|
108
86
|
def key_observer_hash
|
109
|
-
@key_observers ||= Hash.new
|
87
|
+
@key_observers ||= Concurrent::Hash.new
|
110
88
|
end
|
111
89
|
|
112
90
|
def key_observer_list(key)
|
@@ -123,24 +101,6 @@ module Glimmer
|
|
123
101
|
(key_observer_list(key).to_a - all_key_observer_list.to_a).each { |observer| observer.call(self[key], key) }
|
124
102
|
end
|
125
103
|
|
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)
|
129
|
-
begin
|
130
|
-
method('__original__store')
|
131
|
-
rescue
|
132
|
-
define_singleton_method('__original__store', store_method)
|
133
|
-
define_singleton_method('[]=', &OBSERVED_STORE_METHOD)
|
134
|
-
end
|
135
|
-
rescue => e
|
136
|
-
#ignore writing if no key writer exists
|
137
|
-
Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.message}\n#{e.backtrace.join("\n")}"}
|
138
|
-
end
|
139
|
-
|
140
|
-
def store_method
|
141
|
-
self.class.instance_method('[]=') rescue self.method('[]=')
|
142
|
-
end
|
143
|
-
|
144
104
|
def unregister_dependent_observers(key, old_value)
|
145
105
|
# TODO look into optimizing this
|
146
106
|
return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray) || old_value.is_a?(ObservableHash)
|
@@ -166,24 +126,6 @@ module Glimmer
|
|
166
126
|
@array_object_observers[key]
|
167
127
|
end
|
168
128
|
|
169
|
-
def ensure_hash_object_observer(key, object, old_object = nil, options = {})
|
170
|
-
options ||= {}
|
171
|
-
return unless object&.is_a?(Hash)
|
172
|
-
hash_object_observer = hash_object_observer_for(key)
|
173
|
-
hash_observer_registration = hash_object_observer.observe(object, options)
|
174
|
-
key_observer_list(key).each do |observer|
|
175
|
-
my_registration = observer.registration_for(self, key) # TODO eliminate repetition
|
176
|
-
observer.add_dependent(my_registration => hash_observer_registration)
|
177
|
-
end
|
178
|
-
hash_object_observer_for(key).unregister(old_object) if old_object.is_a?(ObservableHash)
|
179
|
-
end
|
180
|
-
|
181
|
-
def hash_object_observer_for(key)
|
182
|
-
@hash_object_observers ||= Concurrent::Hash.new
|
183
|
-
@hash_object_observers[key] = ObservableModel::Notifier.new(self, key) unless @hash_object_observers.has_key?(key)
|
184
|
-
@hash_object_observers[key]
|
185
|
-
end
|
186
|
-
|
187
129
|
def delete(key, &block)
|
188
130
|
old_value = self[key]
|
189
131
|
unless old_value.nil?
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'glimmer/data_binding/observable'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module DataBinding
|
26
|
+
# Represents a Hash-like object with attributes writable via :[]= store method like Hash, Struct, and OpenStruct
|
27
|
+
# Expects including class to have the following methods:
|
28
|
+
# - key_observer_list
|
29
|
+
# - all_key_observer_list
|
30
|
+
# - unregister_dependent_observer
|
31
|
+
# - ensure_array_object_observer
|
32
|
+
module ObservableHashable
|
33
|
+
include Observable
|
34
|
+
|
35
|
+
OBSERVED_STORE_METHOD = lambda do |options|
|
36
|
+
lambda do |key, value|
|
37
|
+
if key_observer_list(key).empty?
|
38
|
+
if all_key_observer_list.empty?
|
39
|
+
self.send('__original__store', key, value)
|
40
|
+
else
|
41
|
+
old_value = self[key]
|
42
|
+
unregister_dependent_observers(nil, old_value) # remove dependent observers previously installed in ensure_array_object_observer
|
43
|
+
self.send('__original__store', key, value)
|
44
|
+
notify_observers(key)
|
45
|
+
ensure_array_object_observer(nil, value, old_value, options)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
old_value = self[key]
|
49
|
+
unregister_dependent_observers(key, old_value) # remove dependent observers previously installed in ensure_array_object_observer
|
50
|
+
self.send('__original__store', key, value)
|
51
|
+
notify_observers(key)
|
52
|
+
ensure_array_object_observer(key, value, old_value, options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_key_writer_observer(key = nil, options)
|
58
|
+
ensure_array_object_observer(key, self[key], nil, options)
|
59
|
+
begin
|
60
|
+
method('__original__store')
|
61
|
+
rescue
|
62
|
+
define_singleton_method('__original__store', store_method)
|
63
|
+
define_singleton_method('[]=', &OBSERVED_STORE_METHOD.call(options))
|
64
|
+
end
|
65
|
+
rescue => e
|
66
|
+
#ignore writing if no key writer exists
|
67
|
+
Glimmer::Config.logger.debug {"No need to observe store method: '[]='\n#{e.message}\n#{e.backtrace.join("\n")}"}
|
68
|
+
end
|
69
|
+
|
70
|
+
def store_method
|
71
|
+
self.class.instance_method('[]=') rescue self.method('[]=')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|