glimmer 1.2.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +15 -6
- data/VERSION +1 -1
- data/glimmer.gemspec +9 -8
- data/lib/glimmer.rb +1 -9
- data/lib/glimmer/data_binding/model_binding.rb +13 -8
- data/lib/glimmer/data_binding/observable_array.rb +9 -0
- data/lib/glimmer/data_binding/observable_model.rb +2 -0
- data/lib/glimmer/data_binding/shine.rb +56 -0
- data/lib/glimmer/dsl/bind_expression.rb +54 -0
- data/lib/glimmer/dsl/engine.rb +10 -6
- data/lib/glimmer/dsl/expression.rb +13 -3
- data/lib/glimmer/dsl/parent_expression.rb +5 -2
- data/lib/glimmer/dsl/static_expression.rb +2 -1
- data/lib/glimmer/ext/module.rb +10 -8
- data/lib/glimmer/shim/concurrent.rb +10 -0
- metadata +7 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a2d51ad333d0d08344d21c90f6bec78ec0cd09b61cd2d86b5d79ecf8374b7f6
|
4
|
+
data.tar.gz: c85f1d8f57ec0556ca3042d49050714908c763dbea9e911f10cde85dc5405b75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26211cca1888df8245ea8c1c76b74effac9370038e42474cbf1e7fb4b905c54a0f5b972dfdb4413293898fb75fea155779bfd49e15f118e7560cba5ffb13b3da
|
7
|
+
data.tar.gz: d56fe91c1eaac6730ef3b706a3e4adf467251cdc48f1ead6f2ea9070e85145ac3e2b774813d2222dd86dbfac0a416dfab54232f0e840cf0e1a28dc2acf7cc2fc
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,19 @@
|
|
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.0.0
|
7
|
+
|
8
|
+
- Extract Glimmer::DSL::BindExpression from Glimmer DSL for SWT
|
9
|
+
- Make concurrent-ruby an optional dependency (automatically using its data-structure classes if present)
|
10
|
+
|
11
|
+
### 1.3.1
|
12
|
+
|
13
|
+
- Use `Concurrent::Array` instead of `Array` in `Glimmer::DataBinding::ModelBinding`
|
14
|
+
|
15
|
+
### 1.3.0
|
16
|
+
|
17
|
+
- Support the `Expression#around` hook, which executes code around both `interpret` and `add_content`
|
18
|
+
|
6
19
|
## 1.2.0
|
7
20
|
|
8
21
|
- Alter `Engine`/`Expression`/`ParentExpression` API to pass `keyword` and `args` to `#add_content` method. This enables consumers to vary behavior based on `keyword` and `args`, not just `parent` and presence of `block`.
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ Featured in JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do) an
|
|
16
16
|
|
17
17
|
[**Glimmer**](https://rubygems.org/gems/glimmer) is a DSL (Domain-Specific Language) Framework that consists of two things:
|
18
18
|
- [DSL Engine](#dsl-engine): enables building internal DSLs embedded in Ruby (e.g. for GUI, XML, or CSS).
|
19
|
-
- [Data-Binding Library](#data-binding-library): enables synchronizing GUI with Model Attributes bidirectionally
|
19
|
+
- [Data-Binding Library](#data-binding-library): enables synchronizing GUI with Model Attributes bidirectionally **(now with Shine syntax support in v2)**.
|
20
20
|
|
21
21
|
[**Glimmer**](https://rubygems.org/gems/glimmer) is ***the cream of the crop*** when it comes to building DSLs in Ruby:
|
22
22
|
- Supports building the tersest most concise domain specific language syntax in Ruby.
|
@@ -27,6 +27,8 @@ Featured in JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do) an
|
|
27
27
|
- Multiple DSLs may be [mixed](#multi-dsl-support) together safely to achieve maximum expressability, composability, and productivity.
|
28
28
|
- DSLs are fully configurable, so you may activate and deactivate DSLs as per your current needs only.
|
29
29
|
|
30
|
+
Start by checking out Glimmer's original GUI DSL, which got extracted into its own gem: [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt)
|
31
|
+
|
30
32
|
[**Glimmer**](https://rubygems.org/gems/glimmer) supports the following DSLs:
|
31
33
|
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
|
32
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)
|
@@ -34,8 +36,6 @@ Featured in JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do) an
|
|
34
36
|
- [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS
|
35
37
|
- [glimmer-dsl-tk](https://github.com/AndyObtiva/glimmer-dsl-tk): Glimmer DSL for Tk (MRI Ruby Desktop Development GUI Library)
|
36
38
|
|
37
|
-
[Glimmer and/or Glimmer DSLs receive two updates per month](https://rubygems.org/gems/glimmer-dsl-swt/versions). You can trust [Glimmer](https://rubygems.org/gems/glimmer) with your Ruby development needs.
|
38
|
-
|
39
39
|
## Table of Contents
|
40
40
|
|
41
41
|
- [Glimmer](#-glimmer---dsl-framework-for-ruby-gui-and-more)
|
@@ -102,6 +102,9 @@ Every `Expression` sublcass must specify two methods at least:
|
|
102
102
|
|
103
103
|
For example, some parent widgets use their block for other reasons or process their children at very specific times, so they may override that method and disable it, or otherwise call `super` and do additional work.
|
104
104
|
|
105
|
+
Otherwise, all expressions support the `around` hook method:
|
106
|
+
- `around(parent, keyword, args, block, &interpret_and_add_content)`: a hook for executing code around both `interpret` and `add_content`. Clients may invoke `interpret_and_add_content.call` or `yield` when ready for interpretation. `parent`, `keyword`, `args`, and `block` are supplied in case they are needed in the `around` logic.
|
107
|
+
|
105
108
|
Example of a dynamic expression:
|
106
109
|
|
107
110
|
```ruby
|
@@ -152,6 +155,9 @@ module Glimmer
|
|
152
155
|
end
|
153
156
|
```
|
154
157
|
|
158
|
+
An extra convenience expression module is included called `BindExpression`. It builds a `Glimmer::DataBinding::ModelBinding` object for [data-binding](#data-binding) purposes.
|
159
|
+
You may learn more about it by looking at how [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) uses it.
|
160
|
+
|
155
161
|
DSL expressions go into the `glimmer/dsl/{dsl_name}` namespace directory.
|
156
162
|
|
157
163
|
Also, every DSL requires a `glimmer/dsl/{dsl_name}/dsl.rb` file, which configures the DSL into Glimmer via a call to:
|
@@ -201,7 +207,7 @@ end
|
|
201
207
|
### Setup
|
202
208
|
|
203
209
|
Follow these steps to author a [Glimmer](https://rubygems.org/gems/glimmer) DSL:
|
204
|
-
- Add `gem 'glimmer', '~>
|
210
|
+
- Add `gem 'glimmer', '~> 2.0.1'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.0.1` and add `require 'glimmer'`
|
205
211
|
- 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)
|
206
212
|
- Create `glimmer/dsl/[dsl_name]/[expresion_name]_expresion.rb` for every [expresion_name] expression needed, whether dynamic or static
|
207
213
|
|
@@ -921,9 +927,9 @@ Glimmer app:
|
|
921
927
|
|
922
928
|
## Data-Binding Library
|
923
929
|
|
924
|
-
Data-Binding enables mapping GUI properties (like text and color) to Model attributes (like name and age).
|
930
|
+
Data-Binding enables mapping GUI properties (like text and color) to Model attributes (like name and age) for bidirectional or unidirectional synchronization and conversion as needed.
|
925
931
|
|
926
|
-
Glimmer enhances observed models automatically (including array operations like
|
932
|
+
Glimmer enhances observed models automatically (including array operations like `<<`, `delete`, and `reject!`) on first observation. As such, you get automatic observable support, including nested and computed observations. No need to change your model code to data-bind it to the view or add repetitive boilerplate modules. View data-binding is truly decoupled from model logic by being able to observe any model attribute (Ruby attribute reader/writer combo or Ruby attribute reader alone for read-only data-binding when needed)
|
927
933
|
|
928
934
|
This relies mainly on the Observer Design Pattern and the MVP (Model-View-Presenter) Architectural Pattern (a variation on MVC)
|
929
935
|
|
@@ -933,6 +939,9 @@ These are the main classes concerning data-binding:
|
|
933
939
|
- `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.
|
934
940
|
- `ObservableArray`: Mixin module for any observable array collection that automatically handles notifying observers upon performing array mutation operations (e.g. `push` or `delete`)
|
935
941
|
- `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
|
942
|
+
- `Shine`: enables highly intuitive and visually expressive syntax to perform bidirectional (two-way) data-binding with `<=>` and unidirectional (one-way) data-binding with `<=`
|
943
|
+
|
944
|
+
You may learn more from [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)
|
936
945
|
|
937
946
|
## Glimmer Process
|
938
947
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.1
|
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
|
5
|
+
# stub: glimmer 2.0.1 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "glimmer".freeze
|
9
|
-
s.version = "
|
9
|
+
s.version = "2.0.1"
|
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-
|
14
|
+
s.date = "2021-07-24"
|
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. Used in the Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), the Glimmer DSL for Tk (Ruby Desktop Development GUI Library), the Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), the Glimmer DSL for XML (& HTML), and the Glimmer DSL for CSS.".freeze
|
16
16
|
s.email = "andy.am@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
@@ -34,6 +34,8 @@ Gem::Specification.new do |s|
|
|
34
34
|
"lib/glimmer/data_binding/observable_array.rb",
|
35
35
|
"lib/glimmer/data_binding/observable_model.rb",
|
36
36
|
"lib/glimmer/data_binding/observer.rb",
|
37
|
+
"lib/glimmer/data_binding/shine.rb",
|
38
|
+
"lib/glimmer/dsl/bind_expression.rb",
|
37
39
|
"lib/glimmer/dsl/engine.rb",
|
38
40
|
"lib/glimmer/dsl/expression.rb",
|
39
41
|
"lib/glimmer/dsl/expression_handler.rb",
|
@@ -42,7 +44,8 @@ Gem::Specification.new do |s|
|
|
42
44
|
"lib/glimmer/dsl/top_level_expression.rb",
|
43
45
|
"lib/glimmer/error.rb",
|
44
46
|
"lib/glimmer/ext/module.rb",
|
45
|
-
"lib/glimmer/invalid_keyword_error.rb"
|
47
|
+
"lib/glimmer/invalid_keyword_error.rb",
|
48
|
+
"lib/glimmer/shim/concurrent.rb"
|
46
49
|
]
|
47
50
|
s.homepage = "http://github.com/AndyObtiva/glimmer".freeze
|
48
51
|
s.licenses = ["MIT".freeze]
|
@@ -56,10 +59,9 @@ Gem::Specification.new do |s|
|
|
56
59
|
if s.respond_to? :add_runtime_dependency then
|
57
60
|
s.add_runtime_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
|
58
61
|
s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
|
59
|
-
s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
|
60
62
|
s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
|
61
63
|
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
62
|
-
s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.
|
64
|
+
s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.13"])
|
63
65
|
s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
|
64
66
|
s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
|
65
67
|
s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
|
@@ -70,10 +72,9 @@ Gem::Specification.new do |s|
|
|
70
72
|
else
|
71
73
|
s.add_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
|
72
74
|
s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
|
73
|
-
s.add_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
|
74
75
|
s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
|
75
76
|
s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
76
|
-
s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.
|
77
|
+
s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.13"])
|
77
78
|
s.add_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
|
78
79
|
s.add_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
|
79
80
|
s.add_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
|
data/lib/glimmer.rb
CHANGED
@@ -22,18 +22,10 @@
|
|
22
22
|
require 'logger'
|
23
23
|
require 'set'
|
24
24
|
require 'array_include_methods'
|
25
|
-
if RUBY_ENGINE == 'opal'
|
26
|
-
module Concurrent
|
27
|
-
Array = ::Array
|
28
|
-
Hash = ::Hash
|
29
|
-
Set = ::Set
|
30
|
-
end
|
31
|
-
else
|
32
|
-
require 'concurrent-ruby'
|
33
|
-
end
|
34
25
|
|
35
26
|
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
36
27
|
|
28
|
+
require 'glimmer/shim/concurrent'
|
37
29
|
require 'glimmer/config'
|
38
30
|
require 'glimmer/ext/module'
|
39
31
|
|
@@ -35,9 +35,9 @@ module Glimmer
|
|
35
35
|
@property_name_expression = property_name_expression
|
36
36
|
@binding_options = binding_options || Concurrent::Hash.new
|
37
37
|
if computed?
|
38
|
-
@computed_model_bindings = computed_by.map do |computed_by_property_expression|
|
38
|
+
@computed_model_bindings = Concurrent::Array.new(computed_by.map do |computed_by_property_expression|
|
39
39
|
self.class.new(base_model, computed_by_property_expression)
|
40
|
-
end
|
40
|
+
end)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -47,7 +47,7 @@ module Glimmer
|
|
47
47
|
|
48
48
|
# e.g. person.address.state returns [person, person.address]
|
49
49
|
def nested_models
|
50
|
-
@nested_models = [base_model]
|
50
|
+
@nested_models = Concurrent::Array.new([base_model])
|
51
51
|
model_property_names.reduce(base_model) do |reduced_model, nested_model_property_name|
|
52
52
|
if !reduced_model.nil?
|
53
53
|
invoke_property_reader(reduced_model, nested_model_property_name).tap do |new_reduced_model|
|
@@ -75,7 +75,7 @@ module Glimmer
|
|
75
75
|
# If there are any indexed property names, this returns indexes as properties.
|
76
76
|
# e.g. property name expression "addresses[1].state" gives ['addresses', '[1]', 'state']
|
77
77
|
def nested_property_names
|
78
|
-
@nested_property_names ||= property_name_expression.split(".").map {|pne| pne.match(/([^\[]+)(\[[^\]]+\])?/).to_a.drop(1)}.flatten.compact
|
78
|
+
@nested_property_names ||= Concurrent::Array.new(property_name_expression.split(".").map {|pne| pne.match(/([^\[]+)(\[[^\]]+\])?/).to_a.drop(1)}.flatten.compact)
|
79
79
|
end
|
80
80
|
|
81
81
|
# Final nested property name
|
@@ -87,7 +87,7 @@ module Glimmer
|
|
87
87
|
# Model representing nested property names
|
88
88
|
# e.g. property name expression "address.state" gives [:address]
|
89
89
|
def model_property_names
|
90
|
-
nested_property_names[0...-1]
|
90
|
+
Concurrent::Array.new(nested_property_names[0...-1])
|
91
91
|
end
|
92
92
|
|
93
93
|
def nested_property?
|
@@ -99,7 +99,7 @@ module Glimmer
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def computed_by
|
102
|
-
[@binding_options[:computed_by]].flatten.compact
|
102
|
+
Concurrent::Array.new([@binding_options[:computed_by]].flatten.compact)
|
103
103
|
end
|
104
104
|
|
105
105
|
def nested_property_observers_for(observer)
|
@@ -175,7 +175,7 @@ module Glimmer
|
|
175
175
|
|
176
176
|
def add_nested_observers(observer)
|
177
177
|
nested_property_observers = nested_property_observers_for(observer)
|
178
|
-
nested_models.zip(nested_property_names).each_with_index do |zip, i|
|
178
|
+
Concurrent::Array.new(nested_models.zip(nested_property_names)).each_with_index do |zip, i|
|
179
179
|
model, property_name = zip
|
180
180
|
nested_property_observer = nested_property_observers[property_name]
|
181
181
|
previous_index = i - 1
|
@@ -242,7 +242,12 @@ module Glimmer
|
|
242
242
|
|
243
243
|
def invoke_proc_with_exact_parameters(proc_object, *args)
|
244
244
|
return if proc_object.nil?
|
245
|
-
|
245
|
+
if RUBY_ENGINE == 'opal'
|
246
|
+
# opal doesn't support proc_object.parameters.size properly it seems
|
247
|
+
args = Concurrent::Array.new(args[0...1])
|
248
|
+
else
|
249
|
+
args = Concurrent::Array.new(args[0...proc_object.parameters.size])
|
250
|
+
end
|
246
251
|
proc_object.call(*args)
|
247
252
|
end
|
248
253
|
|
@@ -130,6 +130,15 @@ module Glimmer
|
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
133
|
+
def shift
|
134
|
+
shifted_element = first
|
135
|
+
unregister_dependent_observers(shifted_element)
|
136
|
+
remove_element_observers(shifted_element)
|
137
|
+
super.tap do
|
138
|
+
notify_observers
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
133
142
|
def delete(element)
|
134
143
|
unregister_dependent_observers(element)
|
135
144
|
remove_element_observers(element)
|
@@ -29,10 +29,12 @@ module Glimmer
|
|
29
29
|
|
30
30
|
class Notifier
|
31
31
|
include Observer
|
32
|
+
|
32
33
|
def initialize(observable_model, property_name)
|
33
34
|
@observable_model = observable_model
|
34
35
|
@property_name = property_name
|
35
36
|
end
|
37
|
+
|
36
38
|
def call(new_value=nil)
|
37
39
|
@observable_model.notify_observers(@property_name)
|
38
40
|
end
|
@@ -0,0 +1,56 @@
|
|
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
|
+
module Glimmer
|
23
|
+
module DataBinding
|
24
|
+
class Shine
|
25
|
+
include Glimmer
|
26
|
+
|
27
|
+
def initialize(parent, parent_attribute)
|
28
|
+
@parent = parent
|
29
|
+
@parent_attribute = parent_attribute
|
30
|
+
end
|
31
|
+
|
32
|
+
def <=>(other)
|
33
|
+
if other.is_a?(Array)
|
34
|
+
args_clone = other.clone
|
35
|
+
@parent.content {
|
36
|
+
send(@parent_attribute, bind(*args_clone))
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def <=(other)
|
42
|
+
if other.is_a?(Array)
|
43
|
+
args_clone = other.clone
|
44
|
+
if args_clone.last.is_a?(Hash)
|
45
|
+
args_clone.last[:read_only] = true
|
46
|
+
else
|
47
|
+
args_clone << {read_only: true}
|
48
|
+
end
|
49
|
+
@parent.content {
|
50
|
+
send(@parent_attribute, bind(*args_clone))
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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/dsl/static_expression'
|
23
|
+
require 'glimmer/data_binding/model_binding'
|
24
|
+
|
25
|
+
module Glimmer
|
26
|
+
module DSL
|
27
|
+
# Responsible for setting up the return value of the bind keyword (command symbol)
|
28
|
+
# as a ModelBinding. It is to be used as the argument of another data-binding expression.
|
29
|
+
module BindExpression
|
30
|
+
def can_interpret?(parent, keyword, *args, &block)
|
31
|
+
(
|
32
|
+
keyword == 'bind' and
|
33
|
+
(
|
34
|
+
(
|
35
|
+
(args.size == 2) and
|
36
|
+
textual?(args[1])
|
37
|
+
) ||
|
38
|
+
(
|
39
|
+
(args.size == 3) and
|
40
|
+
textual?(args[1]) and
|
41
|
+
(args[2].is_a?(Hash))
|
42
|
+
)
|
43
|
+
)
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def interpret(parent, keyword, *args, &block)
|
48
|
+
binding_options = args[2] || {}
|
49
|
+
binding_options[:on_read] = binding_options.delete(:on_read) || binding_options.delete('on_read') || block
|
50
|
+
DataBinding::ModelBinding.new(args[0], args[1].to_s, binding_options)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/glimmer/dsl/engine.rb
CHANGED
@@ -176,10 +176,14 @@ module Glimmer
|
|
176
176
|
end
|
177
177
|
|
178
178
|
def interpret_expression(expression, keyword, *args, &block)
|
179
|
-
|
180
|
-
|
181
|
-
|
179
|
+
new_parent = nil
|
180
|
+
expression.around(parent, keyword, args, block) do
|
181
|
+
new_parent = expression.interpret(parent, keyword, *args, &block).tap do |new_parent|
|
182
|
+
add_content(new_parent, expression, keyword, *args, &block)
|
183
|
+
dsl_stack.pop
|
184
|
+
end
|
182
185
|
end
|
186
|
+
new_parent
|
183
187
|
end
|
184
188
|
|
185
189
|
# Adds content block to parent UI object
|
@@ -187,12 +191,12 @@ module Glimmer
|
|
187
191
|
# This allows evaluating parent UI object properties and children
|
188
192
|
#
|
189
193
|
# For example, a shell widget would get properties set and children added
|
190
|
-
def add_content(
|
194
|
+
def add_content(new_parent, expression, keyword, *args, &block)
|
191
195
|
if block_given? && expression.is_a?(ParentExpression)
|
192
196
|
dsl_stack.push(expression.class.dsl)
|
193
|
-
parent_stack.push(
|
197
|
+
parent_stack.push(new_parent)
|
194
198
|
begin
|
195
|
-
expression.add_content(
|
199
|
+
expression.add_content(new_parent, keyword, *args, &block)
|
196
200
|
ensure
|
197
201
|
parent_stack.pop
|
198
202
|
dsl_stack.pop
|
@@ -47,13 +47,23 @@ module Glimmer
|
|
47
47
|
raise Error, "#interpret must be implemented by an Expression subclass"
|
48
48
|
end
|
49
49
|
|
50
|
-
# Adds block content to
|
50
|
+
# Adds block content to newly interpreted parent object (Optional)
|
51
51
|
#
|
52
52
|
# Only expressions that receive a content block should implement
|
53
|
-
def add_content(
|
53
|
+
def add_content(new_parent, keyword, *args, &block)
|
54
54
|
# No Op by default
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
|
+
# Executes code around the `interpret_and_add_content` block,
|
58
|
+
# which invokes `interpret` and `add_content` when called without args
|
59
|
+
# (parent, keyword, args, block are supplied automatically).
|
60
|
+
# Clients may invoke yield as an alternative to calling `interpret_and_add_content` directly.
|
61
|
+
# This method takes parent, keyword, args, block in case they are needed
|
62
|
+
# in its around logic.
|
63
|
+
def around(parent, keyword, args, block, &interpret_and_add_content)
|
64
|
+
interpret_and_add_content.call
|
65
|
+
end
|
66
|
+
|
57
67
|
# Checks if object is a Symbol or a String
|
58
68
|
def textual?(object)
|
59
69
|
object.is_a?(Symbol) or object.is_a?(String)
|
@@ -25,8 +25,11 @@ module Glimmer
|
|
25
25
|
module DSL
|
26
26
|
# Mixin that represents expressions that always have a content block
|
27
27
|
module ParentExpression
|
28
|
-
|
29
|
-
|
28
|
+
# Default implementation that simply invokes block content with newly interpreted parent object as an argument
|
29
|
+
#
|
30
|
+
# Only expressions that receive a content block should implement
|
31
|
+
def add_content(new_parent, keyword, *args, &block)
|
32
|
+
block.call(new_parent)
|
30
33
|
end
|
31
34
|
end
|
32
35
|
end
|
@@ -50,7 +50,8 @@ module Glimmer
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
# Subclasses may optionally implement
|
53
|
+
# Subclasses may optionally implement, but by default it only ensures that
|
54
|
+
# the keyword matches lower case static expression class name minus `Expression`
|
54
55
|
def can_interpret?(parent, keyword, *args, &block)
|
55
56
|
true
|
56
57
|
end
|
data/lib/glimmer/ext/module.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
unless RUBY_ENGINE == 'opal'
|
2
|
+
class Module
|
3
|
+
alias append_features_without_glimmer append_features
|
4
|
+
def append_features(mod)
|
5
|
+
if self == Glimmer && mod == Object
|
6
|
+
Glimmer::Config.logger.debug { 'Appending Glimmer to Singleton Class of main object (not appending to Object everywhere to avoid method pollution)' }
|
7
|
+
TOPLEVEL_BINDING.receiver.singleton_class.include(self)
|
8
|
+
else
|
9
|
+
append_features_without_glimmer(mod)
|
10
|
+
end
|
9
11
|
end
|
10
12
|
end
|
11
13
|
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:
|
4
|
+
version: 2.0.1
|
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-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: array_include_methods
|
@@ -50,26 +50,6 @@ dependencies:
|
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: 4.0.0
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: concurrent-ruby
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - ">="
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: 1.1.7
|
60
|
-
- - "<"
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: 2.0.0
|
63
|
-
type: :runtime
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: 1.1.7
|
70
|
-
- - "<"
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version: 2.0.0
|
73
53
|
- !ruby/object:Gem::Dependency
|
74
54
|
name: rspec-mocks
|
75
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,14 +84,14 @@ dependencies:
|
|
104
84
|
requirements:
|
105
85
|
- - "~>"
|
106
86
|
- !ruby/object:Gem::Version
|
107
|
-
version: 0.
|
87
|
+
version: '0.13'
|
108
88
|
type: :development
|
109
89
|
prerelease: false
|
110
90
|
version_requirements: !ruby/object:Gem::Requirement
|
111
91
|
requirements:
|
112
92
|
- - "~>"
|
113
93
|
- !ruby/object:Gem::Version
|
114
|
-
version: 0.
|
94
|
+
version: '0.13'
|
115
95
|
- !ruby/object:Gem::Dependency
|
116
96
|
name: rake
|
117
97
|
requirement: !ruby/object:Gem::Requirement
|
@@ -256,6 +236,8 @@ files:
|
|
256
236
|
- lib/glimmer/data_binding/observable_array.rb
|
257
237
|
- lib/glimmer/data_binding/observable_model.rb
|
258
238
|
- lib/glimmer/data_binding/observer.rb
|
239
|
+
- lib/glimmer/data_binding/shine.rb
|
240
|
+
- lib/glimmer/dsl/bind_expression.rb
|
259
241
|
- lib/glimmer/dsl/engine.rb
|
260
242
|
- lib/glimmer/dsl/expression.rb
|
261
243
|
- lib/glimmer/dsl/expression_handler.rb
|
@@ -265,6 +247,7 @@ files:
|
|
265
247
|
- lib/glimmer/error.rb
|
266
248
|
- lib/glimmer/ext/module.rb
|
267
249
|
- lib/glimmer/invalid_keyword_error.rb
|
250
|
+
- lib/glimmer/shim/concurrent.rb
|
268
251
|
homepage: http://github.com/AndyObtiva/glimmer
|
269
252
|
licenses:
|
270
253
|
- MIT
|