glimmer 2.4.1 → 2.5.4
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 +6 -5
- 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 +14 -14
- 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 +45 -44
- data/lib/glimmer/data_binding/observer.rb +16 -14
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8767081e5092e2238c10506725c9b552975128f7b463ec8d6d522a7b763cfcf9
|
4
|
+
data.tar.gz: df300e488e8094dc16293e3ab45a06b58a51e6620d3d744040dec2da4bdf09e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b9aea718ba6d0e39860bbcf3f24f428dff3e0138ec26244676c9fab419a08a28fc39d4cd9db912b4a224a97016133d79efbf3e8321c4828f5fd66a36ad4b436
|
7
|
+
data.tar.gz: 8aa24fa09f117a33b276174c6631d7aecc940ff63346204c65711e2a5e4a064550bd7417d8c9aee4a539b26707c046b4afe7b9f989dea7bf372bb199328539bc
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,29 @@
|
|
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.5.4
|
7
|
+
|
8
|
+
- `Glimmer::DataBinding::ObservableModel` support for observing model attributes with specified `:attribute_writer_type` option (default: `:attribute=`), which can be a single symbol or an array (e.g. `attribute_writer_type: [:attribute=, :set_attribute]`). Glimmer automatches attribute name and automatically generates observer notification attribute writer methods.
|
9
|
+
|
10
|
+
### 2.5.3
|
11
|
+
|
12
|
+
- Provide `Observer#observe` option to tolerate not being able to extend an object for observation by silently not observing such object
|
13
|
+
- Use `Concurrent::Hash` for `ObservableModel#property_observer_hash`
|
14
|
+
- Use `Concurrent::Hash` for `ObservableHash#key_observer_hash`
|
15
|
+
|
16
|
+
### 2.5.1
|
17
|
+
|
18
|
+
- Fix issue with referencing `OpenStruct` without 'ostruct' library being required (it now checks if `OpenStruct` is loaded first and avoids referencing otherwise).
|
19
|
+
|
20
|
+
### 2.5.0
|
21
|
+
|
22
|
+
- Support observing `Struct`/`OpenStruct` changes via `:[]=` method in addition to attribute writers.
|
23
|
+
- Support read-only direct observation of `Hash` object without key via `ModelBinding` (e.g. `ModelBinding.new(some_hash)`)
|
24
|
+
- Support read-only direct observation of `Array` object without index via `ModelBinding` (e.g. `ModelBinding.new(some_array)`)
|
25
|
+
- Support observing `Hash` attribute with `ModelBinding` (all keys or a single key)
|
26
|
+
- Disable `#ensure_hash_object_observer` in ObservableModel/ObservableHash/ObservableArray since it has performance implications and is not necessary
|
27
|
+
- Fix issue with `#ensure_array_object_observer` not receiving `recursive: true` option when updating value of an attribute in `ObservableArray`, `ObservableModel`, and `ObservableHash`
|
28
|
+
|
6
29
|
### 2.4.1
|
7
30
|
|
8
31
|
- Support `recursive: [integer]` option for ObservableArray#add_observer for finite recursion
|
data/README.md
CHANGED
@@ -34,6 +34,7 @@ Start by checking out Glimmer's original GUI DSL, which got extracted into its o
|
|
34
34
|
- [glimmer-dsl-opal](https://github.com/AndyObtiva/glimmer-dsl-opal): Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps)
|
35
35
|
- [glimmer-dsl-tk](https://github.com/AndyObtiva/glimmer-dsl-tk): Glimmer DSL for Tk (MRI Ruby Desktop Development GUI Library)
|
36
36
|
- [glimmer-dsl-libui](https://github.com/AndyObtiva/glimmer-dsl-libui): Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library)
|
37
|
+
- [glimmer-dsl-gtk](https://github.com/AndyObtiva/glimmer-dsl-gtk): Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library)
|
37
38
|
- [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
|
38
39
|
- [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS
|
39
40
|
|
@@ -229,7 +230,7 @@ end
|
|
229
230
|
### Setup
|
230
231
|
|
231
232
|
Follow these steps to author a [Glimmer](https://rubygems.org/gems/glimmer) DSL:
|
232
|
-
- Add `gem 'glimmer', '~> 2.4
|
233
|
+
- Add `gem 'glimmer', '~> 2.5.4'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.5.4` and add `require 'glimmer'`
|
233
234
|
- 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)
|
234
235
|
- Create `glimmer/dsl/[dsl_name]/[expresion_name]_expresion.rb` for every [expresion_name] expression needed, whether dynamic or static
|
235
236
|
|
@@ -1184,11 +1185,11 @@ Glimmer enhances observed models automatically (including array operations like
|
|
1184
1185
|
This relies mainly on the Observer Design Pattern and the MVP (Model-View-Presenter) Architectural Pattern (a variation on MVC)
|
1185
1186
|
|
1186
1187
|
These are the main classes concerning data-binding:
|
1187
|
-
- `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`)
|
1188
|
+
- `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`). Passing the option `ignore_frozen: true` at the end of the args of `register` (alias: `observe`) method results in silently ignoring any passed frozen observable without raising an error (it raises an error otherwise for frozen/immutable objects).
|
1188
1189
|
- `Glimmer::DataBinding::Observable`: General super-module for all observables. Main methods concerned are: `add_observer` and `remove_observer`
|
1189
|
-
- `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.
|
1190
|
+
- `Glimmer::DataBinding::ObservableModel`: Mixin module for any observable model (`Object`, `Struct` or `OpenStruct`) with observable attributes (observes attribute writers and `Struct`/`OpenStruct` `:[]=` method). 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. `:attribute_writer_type` option can be specified (default: `:attribute=`) to observe different attribute styles (e.g. `attribute_writer_type: [:attribute=, :set_attribute]`).
|
1190
1191
|
- `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. Alternatively, pass `recursive: [integer]` to limit recursion in `Array` observation to a specific number of levels beyond the first level (which is always included).
|
1191
|
-
- `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!`)
|
1192
|
+
- `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!`). Also, it automatically handles observing array values using `ObservableArray` appropriately so they would notify observers upon array mutation changes.
|
1192
1193
|
- `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
|
1193
1194
|
- `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 `<=`
|
1194
1195
|
|
@@ -1254,7 +1255,7 @@ end
|
|
1254
1255
|
|
1255
1256
|
Note that if an observed model attribute or hash key is an array, it is automatically observed for array changes, not just attribute/key-value changes.
|
1256
1257
|
|
1257
|
-
All of the features above make Glimmer's data-binding library one of the most sophisticated and advanced in the industry since
|
1258
|
+
All of the features above make Glimmer's data-binding library one of the most sophisticated and advanced in the industry since it automates everything instead of requiring endless manual configuration, thus resulting in some of the tersest most declarative syntax for using observers and data-binding.
|
1258
1259
|
|
1259
1260
|
You may learn more by looking into [data-binding specs](/Users/andy/code/glimmer/spec/lib/glimmer/data_binding) as well as [Data-Binding](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#data-binding) and [Observer](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#observer) usage in [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)
|
1260
1261
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.4
|
1
|
+
2.5.4
|
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.4
|
6
|
-
|
7
|
-
Gem::Specification.new do |s|
|
8
|
-
s.name = "glimmer".freeze
|
9
|
-
s.version = "2.4
|
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.4 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "glimmer".freeze
|
9
|
+
s.version = "2.5.4"
|
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-08"
|
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,8 +50,8 @@ 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
55
|
if !options.empty? && options[:recursive].is_a?(Integer)
|
56
56
|
options = options.clone
|
57
57
|
options[:recursive] = options[:recursive] - 1
|
@@ -60,9 +60,9 @@ module Glimmer
|
|
60
60
|
observer
|
61
61
|
end
|
62
62
|
|
63
|
-
def add_element_observers(element,
|
64
|
-
property_observer_list.each do |observer|
|
65
|
-
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))
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -79,7 +79,7 @@ module Glimmer
|
|
79
79
|
return unless object&.is_a?(Array)
|
80
80
|
array_object_observer = array_object_observer_for(object)
|
81
81
|
array_observer_registration = array_object_observer.observe(object, options)
|
82
|
-
property_observer_list.each do |observer|
|
82
|
+
property_observer_list.each do |observer, options|
|
83
83
|
my_registration = observer.registration_for(self)
|
84
84
|
observer.add_dependent(my_registration => array_observer_registration)
|
85
85
|
end
|
@@ -97,7 +97,7 @@ module Glimmer
|
|
97
97
|
element_properties = element_properties.flatten.compact.uniq
|
98
98
|
if !element_properties.empty?
|
99
99
|
old_element_properties = element_properties_for(observer)
|
100
|
-
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)
|
101
101
|
each { |element| element_properties.each { |property| observer.unobserve(element, property) } }
|
102
102
|
end
|
103
103
|
if element_properties_for(observer).empty?
|
@@ -109,7 +109,7 @@ module Glimmer
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def remove_element_observers(element)
|
112
|
-
property_observer_list.each do |observer|
|
112
|
+
property_observer_list.each do |observer, options|
|
113
113
|
remove_element_observer(element, observer)
|
114
114
|
end
|
115
115
|
end
|
@@ -120,15 +120,15 @@ module Glimmer
|
|
120
120
|
end
|
121
121
|
if element.is_a?(ObservableArray)
|
122
122
|
array_object_observer_for(element).unobserve(element)
|
123
|
-
element.property_observer_list.select {|
|
124
|
-
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)
|
125
125
|
@array_object_observers.reject! {|k, v| v == o}
|
126
126
|
end
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
130
|
def has_observer?(observer)
|
131
|
-
property_observer_list.include?(observer)
|
131
|
+
property_observer_list.keys.include?(observer)
|
132
132
|
end
|
133
133
|
|
134
134
|
def has_observer_element_properties?(observer, element_properties)
|
@@ -136,7 +136,7 @@ module Glimmer
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def property_observer_list
|
139
|
-
@property_observer_list ||= Concurrent::
|
139
|
+
@property_observer_list ||= Concurrent::Hash.new
|
140
140
|
end
|
141
141
|
|
142
142
|
def observer_element_properties
|
@@ -148,7 +148,7 @@ module Glimmer
|
|
148
148
|
end
|
149
149
|
|
150
150
|
def notify_observers
|
151
|
-
property_observer_list.to_a.each { |
|
151
|
+
property_observer_list.to_a.each { |obs, opt| obs.call(self) }
|
152
152
|
end
|
153
153
|
|
154
154
|
def <<(element)
|
@@ -372,7 +372,7 @@ module Glimmer
|
|
372
372
|
|
373
373
|
def unregister_dependent_observers(old_value)
|
374
374
|
return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
|
375
|
-
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) }
|
376
376
|
end
|
377
377
|
alias deregister_dependent_observers unregister_dependent_observers
|
378
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
|
@@ -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 ObservableModel
|
28
|
-
include
|
28
|
+
include ObservableHashable
|
29
29
|
|
30
30
|
class Notifier
|
31
31
|
include Observer
|
@@ -40,25 +40,26 @@ module Glimmer
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
PROPERTY_WRITER_FACTORY = lambda do |property_name|
|
44
|
-
property_writer_name = "#{property_name}="
|
43
|
+
PROPERTY_WRITER_FACTORY = lambda do |property_name, property_writer_name, options|
|
45
44
|
lambda do |value|
|
46
45
|
old_value = self.send(property_name)
|
47
|
-
unregister_dependent_observers(property_name, old_value) # remove dependent observers previously installed in ensure_array_object_observer
|
46
|
+
unregister_dependent_observers(property_name, old_value) # remove dependent observers previously installed in ensure_array_object_observer
|
48
47
|
self.send("__original__#{property_writer_name}", value)
|
49
48
|
notify_observers(property_name)
|
50
|
-
ensure_array_object_observer(property_name, value, old_value)
|
51
|
-
ensure_hash_object_observer(property_name, value, old_value)
|
49
|
+
ensure_array_object_observer(property_name, value, old_value, options)
|
52
50
|
end
|
53
51
|
end
|
54
|
-
|
52
|
+
|
55
53
|
def add_observer(observer, property_name, options = {})
|
54
|
+
initialize_observer_options(options)
|
56
55
|
return observer if has_observer?(observer, property_name)
|
57
56
|
property_observer_list(property_name) << observer
|
58
57
|
add_property_writer_observers(property_name, options)
|
58
|
+
open_struct_loaded = !!::OpenStruct rescue false
|
59
|
+
add_key_writer_observer(property_name, options) if is_a?(Struct) || (open_struct_loaded && is_a?(OpenStruct))
|
59
60
|
observer
|
60
61
|
end
|
61
|
-
|
62
|
+
|
62
63
|
def remove_observer(observer, property_name, options = {})
|
63
64
|
if has_observer?(observer, property_name)
|
64
65
|
property_observer_list(property_name).delete(observer)
|
@@ -67,10 +68,11 @@ module Glimmer
|
|
67
68
|
end
|
68
69
|
|
69
70
|
def remove_observers(property_name)
|
70
|
-
|
71
|
+
property_key = property_name&.to_sym
|
72
|
+
property_observer_hash[property_key].each do |observer|
|
71
73
|
remove_observer(observer, property_name)
|
72
74
|
end
|
73
|
-
property_observer_hash.delete(
|
75
|
+
property_observer_hash.delete(property_key)
|
74
76
|
end
|
75
77
|
|
76
78
|
def remove_all_observers
|
@@ -91,32 +93,44 @@ module Glimmer
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def property_observer_hash
|
94
|
-
@property_observers ||= Hash.new
|
96
|
+
@property_observers ||= Concurrent::Hash.new
|
95
97
|
end
|
96
98
|
|
97
99
|
def property_observer_list(property_name)
|
98
|
-
|
99
|
-
property_observer_hash[
|
100
|
+
property_key = property_name&.to_sym
|
101
|
+
property_observer_hash[property_key] = Concurrent::Set.new unless property_observer_hash[property_key]
|
102
|
+
property_observer_hash[property_key]
|
100
103
|
end
|
104
|
+
alias key_observer_list property_observer_list
|
105
|
+
|
106
|
+
def all_property_observer_list
|
107
|
+
property_observer_list(nil)
|
108
|
+
end
|
109
|
+
alias all_key_observer_list all_property_observer_list
|
101
110
|
|
102
111
|
def notify_observers(property_name)
|
103
112
|
property_observer_list(property_name).to_a.each { |observer| observer.call(send(property_name)) }
|
104
113
|
end
|
105
|
-
|
114
|
+
|
106
115
|
def add_property_writer_observers(property_name, options)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
+
options[:attribute_writer_type].each do |attribute_writer_type|
|
117
|
+
begin
|
118
|
+
property_writer_name = attribute_writer_type.to_s.gsub('attribute', property_name.to_s)
|
119
|
+
method(property_writer_name)
|
120
|
+
ensure_array_object_observer(property_name, send(property_name), nil, options)
|
121
|
+
begin
|
122
|
+
method("__original__#{property_writer_name}")
|
123
|
+
rescue
|
124
|
+
define_singleton_method("__original__#{property_writer_name}", property_writer_method(property_writer_name))
|
125
|
+
# Note the limitation that the first observe call options apply to all subsequent observations meaning even if unobserve was called, options do not change from initial ones
|
126
|
+
# It is good enough for now. If there is a need to address this in the future, this is where to start the work
|
127
|
+
define_singleton_method(property_writer_name, &PROPERTY_WRITER_FACTORY.call(property_name, property_writer_name, options))
|
128
|
+
end
|
129
|
+
rescue => e
|
130
|
+
#ignore writing if no property writer exists
|
131
|
+
Glimmer::Config.logger.debug {"No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"}
|
132
|
+
end
|
116
133
|
end
|
117
|
-
rescue => e
|
118
|
-
#ignore writing if no property writer exists
|
119
|
-
Glimmer::Config.logger.debug {"No need to observe property writer: #{property_writer_name}\n#{e.message}\n#{e.backtrace.join("\n")}"}
|
120
134
|
end
|
121
135
|
|
122
136
|
def property_writer_method(property_writer_name)
|
@@ -130,7 +144,7 @@ module Glimmer
|
|
130
144
|
end
|
131
145
|
alias deregister_dependent_observers unregister_dependent_observers
|
132
146
|
|
133
|
-
def ensure_array_object_observer(property_name, object, old_object = nil, options =
|
147
|
+
def ensure_array_object_observer(property_name, object, old_object = nil, options = nil)
|
134
148
|
options ||= {}
|
135
149
|
return unless object&.is_a?(Array)
|
136
150
|
array_object_observer = array_object_observer_for(property_name)
|
@@ -147,23 +161,10 @@ module Glimmer
|
|
147
161
|
@array_object_observers[property_name] = Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
|
148
162
|
@array_object_observers[property_name]
|
149
163
|
end
|
150
|
-
|
151
|
-
def ensure_hash_object_observer(property_name, object, old_object = nil, options)
|
152
|
-
options ||= {}
|
153
|
-
return unless object&.is_a?(Hash)
|
154
|
-
hash_object_observer = hash_object_observer_for(property_name)
|
155
|
-
hash_observer_registration = hash_object_observer.observe(object, options)
|
156
|
-
property_observer_list(property_name).each do |observer|
|
157
|
-
my_registration = observer.registration_for(self, property_name) # TODO eliminate repetition
|
158
|
-
observer.add_dependent(my_registration => hash_observer_registration)
|
159
|
-
end
|
160
|
-
hash_object_observer_for(property_name).unregister(old_object) if old_object.is_a?(ObservableHash)
|
161
|
-
end
|
162
164
|
|
163
|
-
def
|
164
|
-
|
165
|
-
|
166
|
-
@hash_object_observers[property_name]
|
165
|
+
def initialize_observer_options(options)
|
166
|
+
options[:attribute_writer_type] ||= [:attribute=]
|
167
|
+
options[:attribute_writer_type] = [options[:attribute_writer_type]] if !options[:attribute_writer_type].is_a?(Array)
|
167
168
|
end
|
168
169
|
end
|
169
170
|
end
|
@@ -47,11 +47,11 @@ module Glimmer
|
|
47
47
|
end
|
48
48
|
|
49
49
|
class Registration < Struct.new(:observer, :observable, :args, keyword_init: true)
|
50
|
-
def
|
50
|
+
def deregister
|
51
51
|
observer.unobserve(observable, *args)
|
52
52
|
end
|
53
|
-
alias
|
54
|
-
alias deregister
|
53
|
+
alias unregister deregister
|
54
|
+
alias unobserve deregister
|
55
55
|
end
|
56
56
|
|
57
57
|
class << self
|
@@ -82,8 +82,10 @@ module Glimmer
|
|
82
82
|
|
83
83
|
# registers observer in an observable on args usually containing a property and options (optional)
|
84
84
|
# observer maintains registration list to unregister later
|
85
|
-
def
|
85
|
+
def observe(observable, *args)
|
86
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
86
87
|
return if observable.nil?
|
88
|
+
return if options[:ignore_frozen] && observable.frozen?
|
87
89
|
unless observable.is_a?(Observable)
|
88
90
|
# TODO refactor code to be more smart/polymorphic/automated and honor open/closed principle (e.g. for SomeClass, search if there is ObservableSomeClass)
|
89
91
|
if observable.is_a?(Array)
|
@@ -98,9 +100,9 @@ module Glimmer
|
|
98
100
|
observable.add_observer(self, *args)
|
99
101
|
ensure_registration_for!(observable, *args)
|
100
102
|
end
|
101
|
-
alias observe
|
103
|
+
alias register observe
|
102
104
|
|
103
|
-
def
|
105
|
+
def unobserve(observable, *args)
|
104
106
|
return unless observable.is_a?(Observable)
|
105
107
|
args = compact_args(args)
|
106
108
|
registration = registration_for(observable, *args)
|
@@ -113,27 +115,27 @@ module Glimmer
|
|
113
115
|
observable.remove_observer(self, *args)
|
114
116
|
end
|
115
117
|
end
|
116
|
-
alias unobserve
|
117
|
-
alias deregister
|
118
|
+
alias unregister unobserve
|
119
|
+
alias deregister unobserve
|
118
120
|
|
119
|
-
def
|
121
|
+
def unobserve_dependents_with_observable(registration, dependent_observable)
|
120
122
|
thedependents = dependents_for(registration).select do |thedependent|
|
121
123
|
thedependent.observable == dependent_observable
|
122
124
|
end
|
123
125
|
thedependents.each(&:deregister)
|
124
126
|
end
|
125
|
-
alias unobserve_dependents_with_observable
|
126
|
-
alias deregister_dependents_with_observable
|
127
|
+
alias unregister_dependents_with_observable unobserve_dependents_with_observable
|
128
|
+
alias deregister_dependents_with_observable unobserve_dependents_with_observable
|
127
129
|
|
128
130
|
# cleans up all registrations in observables
|
129
|
-
def
|
131
|
+
def unobserve_all_observables
|
130
132
|
registrations.values.dup.each do |registration|
|
131
133
|
registration.deregister
|
132
134
|
registrations.delete([registration.observable.object_id, registration.args])
|
133
135
|
end
|
134
136
|
end
|
135
|
-
alias unobserve_all_observables
|
136
|
-
alias deregister_all_observables
|
137
|
+
alias unregister_all_observables unobserve_all_observables
|
138
|
+
alias deregister_all_observables unobserve_all_observables
|
137
139
|
|
138
140
|
# add dependent observer to unregister when unregistering observer
|
139
141
|
def add_dependent(parent_to_dependent_hash)
|
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
|
4
|
+
version: 2.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: array_include_methods
|
@@ -192,23 +192,24 @@ dependencies:
|
|
192
192
|
name: rake-tui
|
193
193
|
requirement: !ruby/object:Gem::Requirement
|
194
194
|
requirements:
|
195
|
-
- - "
|
195
|
+
- - ">"
|
196
196
|
- !ruby/object:Gem::Version
|
197
197
|
version: '0'
|
198
198
|
type: :development
|
199
199
|
prerelease: false
|
200
200
|
version_requirements: !ruby/object:Gem::Requirement
|
201
201
|
requirements:
|
202
|
-
- - "
|
202
|
+
- - ">"
|
203
203
|
- !ruby/object:Gem::Version
|
204
204
|
version: '0'
|
205
205
|
description: Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of
|
206
206
|
a DSL Engine and an Observable / Observer / Data-Binding Library (including Observable
|
207
207
|
Model, Observable Array, and Observable Hash). Used in Glimmer DSL for SWT (JRuby
|
208
|
-
Desktop Development GUI Framework), Glimmer DSL for
|
209
|
-
|
210
|
-
|
211
|
-
|
208
|
+
Desktop Development GUI Framework), Glimmer DSL for Opal (Pure Ruby Web GUI and
|
209
|
+
Auto-Webifier of Desktop Apps), Glimmer DSL for Tk (Ruby Desktop Development GUI
|
210
|
+
Library), Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI
|
211
|
+
Library), Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library), Glimmer
|
212
|
+
DSL for XML (& HTML), and Glimmer DSL for CSS.
|
212
213
|
email: andy.am@gmail.com
|
213
214
|
executables: []
|
214
215
|
extensions: []
|
@@ -230,6 +231,7 @@ files:
|
|
230
231
|
- lib/glimmer/data_binding/observable.rb
|
231
232
|
- lib/glimmer/data_binding/observable_array.rb
|
232
233
|
- lib/glimmer/data_binding/observable_hash.rb
|
234
|
+
- lib/glimmer/data_binding/observable_hashable.rb
|
233
235
|
- lib/glimmer/data_binding/observable_model.rb
|
234
236
|
- lib/glimmer/data_binding/observer.rb
|
235
237
|
- lib/glimmer/data_binding/shine.rb
|