glimmer 1.0.3 → 1.0.8
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/LICENSE.txt +1 -1
- data/PROCESS.md +2 -2
- data/README.md +387 -224
- data/VERSION +1 -1
- data/glimmer.gemspec +8 -7
- data/lib/glimmer.rb +6 -5
- data/lib/glimmer/config.rb +6 -6
- data/lib/glimmer/data_binding/model_binding.rb +7 -7
- data/lib/glimmer/data_binding/observable.rb +4 -4
- data/lib/glimmer/data_binding/observable_array.rb +6 -6
- data/lib/glimmer/data_binding/observable_model.rb +27 -8
- data/lib/glimmer/data_binding/observer.rb +10 -8
- data/lib/glimmer/dsl/engine.rb +23 -22
- data/lib/glimmer/dsl/expression.rb +5 -5
- data/lib/glimmer/dsl/expression_handler.rb +4 -4
- data/lib/glimmer/dsl/parent_expression.rb +4 -4
- data/lib/glimmer/dsl/static_expression.rb +6 -6
- data/lib/glimmer/dsl/top_level_expression.rb +4 -4
- data/lib/glimmer/error.rb +4 -4
- data/lib/glimmer/invalid_keyword_error.rb +4 -4
- metadata +30 -11
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.8
|
data/glimmer.gemspec
CHANGED
@@ -2,20 +2,19 @@
|
|
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 1.0.
|
5
|
+
# stub: glimmer 1.0.8 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "glimmer".freeze
|
9
|
-
s.version = "1.0.
|
9
|
+
s.version = "1.0.8"
|
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 = "
|
15
|
-
s.description = "Glimmer is a Ruby DSL Framework consisting of a DSL Engine and Observable/Observer/Data-Binding Library. Used in the Glimmer DSL for SWT (JRuby Desktop Development GUI
|
14
|
+
s.date = "2021-01-19"
|
15
|
+
s.description = "Glimmer is a Ruby DSL Framework 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 = [
|
18
|
-
"CHANGELOG.md",
|
19
18
|
"LICENSE.txt",
|
20
19
|
"README.md"
|
21
20
|
]
|
@@ -55,26 +54,28 @@ Gem::Specification.new do |s|
|
|
55
54
|
if s.respond_to? :add_runtime_dependency then
|
56
55
|
s.add_runtime_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
|
57
56
|
s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
|
57
|
+
s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
|
58
58
|
s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
|
59
59
|
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
60
60
|
s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
|
61
61
|
s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
|
62
62
|
s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
|
63
63
|
s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
|
64
|
-
s.add_development_dependency(%q<coveralls>.freeze, ["
|
64
|
+
s.add_development_dependency(%q<coveralls>.freeze, [">= 0"])
|
65
65
|
s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
|
66
66
|
s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
|
67
67
|
s.add_development_dependency(%q<rake-tui>.freeze, [">= 0"])
|
68
68
|
else
|
69
69
|
s.add_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
|
70
70
|
s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
|
71
|
+
s.add_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
|
71
72
|
s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
|
72
73
|
s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
73
74
|
s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
|
74
75
|
s.add_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
|
75
76
|
s.add_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
|
76
77
|
s.add_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
|
77
|
-
s.add_dependency(%q<coveralls>.freeze, ["
|
78
|
+
s.add_dependency(%q<coveralls>.freeze, [">= 0"])
|
78
79
|
s.add_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
|
79
80
|
s.add_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
|
80
81
|
s.add_dependency(%q<rake-tui>.freeze, [">= 0"])
|
data/lib/glimmer.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Copyright (c) 2007-
|
2
|
-
#
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
5
5
|
# "Software"), to deal in the Software without restriction, including
|
@@ -7,10 +7,10 @@
|
|
7
7
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
8
|
# permit persons to whom the Software is furnished to do so, subject to
|
9
9
|
# the following conditions:
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The above copyright notice and this permission notice shall be
|
12
12
|
# included in all copies or substantial portions of the Software.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
16
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
@@ -22,6 +22,7 @@
|
|
22
22
|
require 'logger'
|
23
23
|
require 'set'
|
24
24
|
require 'array_include_methods'
|
25
|
+
require 'concurrent-ruby'
|
25
26
|
|
26
27
|
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
27
28
|
|
@@ -70,7 +71,7 @@ module Glimmer
|
|
70
71
|
end
|
71
72
|
Glimmer.loop_last_data = new_loop_data
|
72
73
|
Glimmer::Config.logger.info {"Interpreting keyword: #{method_symbol}"}
|
73
|
-
Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
|
74
|
+
Glimmer::DSL::Engine.interpret(method_symbol, *args, &block)
|
74
75
|
end
|
75
76
|
rescue InvalidKeywordError => e
|
76
77
|
Glimmer::Config.logger.error {"Encountered an invalid keyword at this object: #{self}"}
|
data/lib/glimmer/config.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Copyright (c) 2007-
|
2
|
-
#
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
5
5
|
# "Software"), to deal in the Software without restriction, including
|
@@ -7,10 +7,10 @@
|
|
7
7
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
8
|
# permit persons to whom the Software is furnished to do so, subject to
|
9
9
|
# the following conditions:
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The above copyright notice and this permission notice shall be
|
12
12
|
# included in all copies or substantial portions of the Software.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
16
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
@@ -46,7 +46,7 @@ module Glimmer
|
|
46
46
|
end
|
47
47
|
|
48
48
|
# Returns Glimmer logger (standard Ruby logger)
|
49
|
-
def logger
|
49
|
+
def logger
|
50
50
|
reset_logger! unless defined? @@logger
|
51
51
|
@@logger
|
52
52
|
end
|
@@ -56,7 +56,7 @@ module Glimmer
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def reset_logger!
|
59
|
-
self.logger = Logger.new(STDOUT).tap do |logger|
|
59
|
+
self.logger = Logger.new(STDOUT).tap do |logger|
|
60
60
|
logger.level = Logger::ERROR
|
61
61
|
begin
|
62
62
|
logger.level = ENV['GLIMMER_LOGGER_LEVEL'].strip.downcase if ENV['GLIMMER_LOGGER_LEVEL']
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2007-
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -33,7 +33,7 @@ module Glimmer
|
|
33
33
|
def initialize(base_model, property_name_expression, binding_options = nil)
|
34
34
|
@base_model = base_model
|
35
35
|
@property_name_expression = property_name_expression
|
36
|
-
@binding_options = binding_options ||
|
36
|
+
@binding_options = binding_options || Concurrent::Hash.new
|
37
37
|
if computed?
|
38
38
|
@computed_model_bindings = computed_by.map do |computed_by_property_expression|
|
39
39
|
self.class.new(base_model, computed_by_property_expression)
|
@@ -120,9 +120,9 @@ module Glimmer
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def nested_property_observers_for(observer)
|
123
|
-
@nested_property_observers_collection ||=
|
123
|
+
@nested_property_observers_collection ||= Concurrent::Hash.new
|
124
124
|
unless @nested_property_observers_collection.has_key?(observer)
|
125
|
-
@nested_property_observers_collection[observer] = nested_property_names.reduce(
|
125
|
+
@nested_property_observers_collection[observer] = nested_property_names.reduce(Concurrent::Hash.new) do |output, property_name|
|
126
126
|
output.merge(
|
127
127
|
property_name => Observer.proc do |new_value|
|
128
128
|
# Ensure reattaching observers when a higher level nested property is updated (e.g. person.address changes reattaches person.address.street observer)
|
@@ -164,7 +164,7 @@ module Glimmer
|
|
164
164
|
end
|
165
165
|
|
166
166
|
def computed_observer_for(observer)
|
167
|
-
@computed_observer_collection ||=
|
167
|
+
@computed_observer_collection ||= Concurrent::Hash.new
|
168
168
|
unless @computed_observer_collection.has_key?(observer)
|
169
169
|
@computed_observer_collection[observer] = Observer.proc do |new_value|
|
170
170
|
observer.call(evaluate_property)
|
@@ -209,7 +209,7 @@ module Glimmer
|
|
209
209
|
def call(value)
|
210
210
|
return if model.nil?
|
211
211
|
converted_value = value
|
212
|
-
invoke_property_writer(model, "#{property_name}=", converted_value) unless
|
212
|
+
invoke_property_writer(model, "#{property_name}=", converted_value) unless converted_value == evaluate_property
|
213
213
|
end
|
214
214
|
|
215
215
|
def evaluate_property
|
@@ -242,7 +242,7 @@ module Glimmer
|
|
242
242
|
end
|
243
243
|
|
244
244
|
def invoke_property_writer(object, property_expression, value)
|
245
|
-
|
245
|
+
raise "Cannot invoke `#{property_expression}` because ModelBinding#binding_options[:read_only]=true" if @binding_options[:read_only]
|
246
246
|
value = convert_on_write(value)
|
247
247
|
if property_indexed?(property_expression)
|
248
248
|
property_method = '[]='
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# Copyright (c) 2007-
|
2
|
-
#
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
5
5
|
# "Software"), to deal in the Software without restriction, including
|
@@ -7,10 +7,10 @@
|
|
7
7
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
8
|
# permit persons to whom the Software is furnished to do so, subject to
|
9
9
|
# the following conditions:
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The above copyright notice and this permission notice shall be
|
12
12
|
# included in all copies or substantial portions of the Software.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
16
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2007-
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -34,7 +34,7 @@ module Glimmer
|
|
34
34
|
element_properties = element_properties.flatten.compact.uniq
|
35
35
|
return observer if has_observer?(observer) && has_observer_element_properties?(observer, element_properties)
|
36
36
|
property_observer_list << observer
|
37
|
-
observer_element_properties[observer] = element_properties_for(observer) + Set.new(element_properties)
|
37
|
+
observer_element_properties[observer] = element_properties_for(observer) + Concurrent::Set.new(element_properties)
|
38
38
|
each { |element| add_element_observer(element, observer) }
|
39
39
|
observer
|
40
40
|
end
|
@@ -55,7 +55,7 @@ module Glimmer
|
|
55
55
|
element_properties = element_properties.flatten.compact.uniq
|
56
56
|
if !element_properties.empty?
|
57
57
|
old_element_properties = element_properties_for(observer)
|
58
|
-
observer_element_properties[observer] = element_properties_for(observer) - Set.new(element_properties)
|
58
|
+
observer_element_properties[observer] = element_properties_for(observer) - Concurrent::Set.new(element_properties)
|
59
59
|
each { |element| element_properties.each { |property| observer.unobserve(element, property) } }
|
60
60
|
end
|
61
61
|
if element_properties_for(observer).empty?
|
@@ -87,15 +87,15 @@ module Glimmer
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def property_observer_list
|
90
|
-
@property_observer_list ||= Set.new
|
90
|
+
@property_observer_list ||= Concurrent::Set.new
|
91
91
|
end
|
92
92
|
|
93
93
|
def observer_element_properties
|
94
|
-
@observer_element_properties ||=
|
94
|
+
@observer_element_properties ||= Concurrent::Hash.new
|
95
95
|
end
|
96
96
|
|
97
97
|
def element_properties_for(observer)
|
98
|
-
observer_element_properties[observer] ||= Set.new
|
98
|
+
observer_element_properties[observer] ||= Concurrent::Set.new
|
99
99
|
end
|
100
100
|
|
101
101
|
def notify_observers
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2007-
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -43,7 +43,7 @@ module Glimmer
|
|
43
43
|
lambda do |value|
|
44
44
|
old_value = self.send(property_name)
|
45
45
|
unregister_dependent_observers(property_name, old_value)
|
46
|
-
self.send("
|
46
|
+
self.send("__original__#{property_writer_name}", value)
|
47
47
|
notify_observers(property_name)
|
48
48
|
ensure_array_object_observer(property_name, value, old_value)
|
49
49
|
end
|
@@ -57,7 +57,26 @@ module Glimmer
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def remove_observer(observer, property_name)
|
60
|
-
|
60
|
+
if has_observer?(observer, property_name)
|
61
|
+
property_observer_list(property_name).delete(observer)
|
62
|
+
observer.unobserve(self, property_name)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def remove_observers(property_name)
|
67
|
+
property_observer_hash[property_name.to_sym].each do |observer|
|
68
|
+
remove_observer(observer, property_name)
|
69
|
+
end
|
70
|
+
property_observer_hash.delete(property_name.to_sym)
|
71
|
+
end
|
72
|
+
|
73
|
+
def remove_all_observers
|
74
|
+
all_observers = property_observer_hash.clone
|
75
|
+
property_observer_hash.keys.each do |property_name|
|
76
|
+
remove_observers(property_name)
|
77
|
+
end
|
78
|
+
property_observer_hash.clear
|
79
|
+
all_observers
|
61
80
|
end
|
62
81
|
|
63
82
|
def has_observer?(observer, property_name)
|
@@ -73,7 +92,7 @@ module Glimmer
|
|
73
92
|
end
|
74
93
|
|
75
94
|
def property_observer_list(property_name)
|
76
|
-
property_observer_hash[property_name.to_sym] = Set.new unless property_observer_hash[property_name.to_sym]
|
95
|
+
property_observer_hash[property_name.to_sym] = Concurrent::Set.new unless property_observer_hash[property_name.to_sym]
|
77
96
|
property_observer_hash[property_name.to_sym]
|
78
97
|
end
|
79
98
|
|
@@ -86,9 +105,9 @@ module Glimmer
|
|
86
105
|
method(property_writer_name)
|
87
106
|
ensure_array_object_observer(property_name, send(property_name))
|
88
107
|
begin
|
89
|
-
|
108
|
+
method("__original__#{property_writer_name}")
|
90
109
|
rescue
|
91
|
-
define_singleton_method("
|
110
|
+
define_singleton_method("__original__#{property_writer_name}", property_writer_method(property_writer_name))
|
92
111
|
define_singleton_method(property_writer_name, &PROPERTY_WRITER_FACTORY.call(property_name))
|
93
112
|
end
|
94
113
|
rescue => e
|
@@ -107,7 +126,7 @@ module Glimmer
|
|
107
126
|
end
|
108
127
|
|
109
128
|
def ensure_array_object_observer(property_name, object, old_object = nil)
|
110
|
-
return unless object
|
129
|
+
return unless object&.is_a?(Array)
|
111
130
|
array_object_observer = array_object_observer_for(property_name)
|
112
131
|
array_observer_registration = array_object_observer.observe(object)
|
113
132
|
property_observer_list(property_name).each do |observer|
|
@@ -118,7 +137,7 @@ module Glimmer
|
|
118
137
|
end
|
119
138
|
|
120
139
|
def array_object_observer_for(property_name)
|
121
|
-
@array_object_observers ||=
|
140
|
+
@array_object_observers ||= Concurrent::Hash.new
|
122
141
|
@array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
|
123
142
|
@array_object_observers[property_name]
|
124
143
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# Copyright (c) 2007-
|
2
|
-
#
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
5
5
|
# "Software"), to deal in the Software without restriction, including
|
@@ -7,10 +7,10 @@
|
|
7
7
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
8
|
# permit persons to whom the Software is furnished to do so, subject to
|
9
9
|
# the following conditions:
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The above copyright notice and this permission notice shall be
|
12
12
|
# included in all copies or substantial portions of the Software.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
16
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
@@ -51,6 +51,7 @@ module Glimmer
|
|
51
51
|
observer.unobserve(observable, property)
|
52
52
|
end
|
53
53
|
alias unobserve unregister
|
54
|
+
alias deregister unregister
|
54
55
|
end
|
55
56
|
|
56
57
|
class << self
|
@@ -60,7 +61,7 @@ module Glimmer
|
|
60
61
|
end
|
61
62
|
|
62
63
|
def registrations
|
63
|
-
@registrations ||= Set.new
|
64
|
+
@registrations ||= Concurrent::Set.new
|
64
65
|
end
|
65
66
|
|
66
67
|
def registration_for(observable, property = nil)
|
@@ -74,7 +75,7 @@ module Glimmer
|
|
74
75
|
end
|
75
76
|
|
76
77
|
def dependents_for(registration)
|
77
|
-
dependents[registration] ||= Set.new
|
78
|
+
dependents[registration] ||= Concurrent::Set.new
|
78
79
|
end
|
79
80
|
|
80
81
|
# registers observer in an observable on a property (optional)
|
@@ -99,13 +100,14 @@ module Glimmer
|
|
99
100
|
def unregister(observable, property = nil)
|
100
101
|
return unless observable.is_a?(Observable)
|
101
102
|
# TODO optimize performance in the future via indexing and/or making a registration official object/class
|
102
|
-
observable.remove_observer(*[self, property].compact)
|
103
103
|
registration = registration_for(observable, property)
|
104
104
|
dependents_for(registration).each do |dependent|
|
105
105
|
dependent.unregister
|
106
106
|
remove_dependent(registration => dependent)
|
107
107
|
end
|
108
|
-
registrations.delete(registration)
|
108
|
+
registrations.delete(registration).tap do |registration|
|
109
|
+
observable.remove_observer(*[self, property].compact)
|
110
|
+
end
|
109
111
|
end
|
110
112
|
alias unobserve unregister
|
111
113
|
|
data/lib/glimmer/dsl/engine.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Copyright (c) 2007-
|
2
|
-
#
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
5
5
|
# "Software"), to deal in the Software without restriction, including
|
@@ -7,10 +7,10 @@
|
|
7
7
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
8
|
# permit persons to whom the Software is furnished to do so, subject to
|
9
9
|
# the following conditions:
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The above copyright notice and this permission notice shall be
|
12
12
|
# included in all copies or substantial portions of the Software.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
16
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
@@ -28,7 +28,7 @@ module Glimmer
|
|
28
28
|
module DSL
|
29
29
|
# Glimmer DSL Engine
|
30
30
|
#
|
31
|
-
# Follows Interpreter
|
31
|
+
# Follows Interpreter, Chain of Responsibility, and Singleton Design Patterns
|
32
32
|
#
|
33
33
|
# When DSL engine interprets an expression, it attempts to handle
|
34
34
|
# with ordered expression array specified via `.expressions=` method.
|
@@ -51,19 +51,19 @@ module Glimmer
|
|
51
51
|
end
|
52
52
|
if interpretation
|
53
53
|
interpretation
|
54
|
-
else
|
54
|
+
else
|
55
55
|
raise Glimmer::Error, "Unsupported keyword: #{keyword}" unless static_expression_dsl || retrieved_static_expression
|
56
56
|
Glimmer::DSL::Engine.dsl_stack.push(static_expression_dsl || Glimmer::DSL::Engine.dsl)
|
57
57
|
static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
|
58
|
-
if !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
|
59
|
-
raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent}"
|
58
|
+
if static_expression.nil? || !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block)
|
59
|
+
raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent.inspect}"
|
60
60
|
else
|
61
61
|
Glimmer::Config.logger.info {"#{static_expression.class.name} will handle expression keyword #{keyword}"}
|
62
62
|
Glimmer::DSL::Engine.interpret_expression(static_expression, keyword, *args, &block)
|
63
63
|
end
|
64
64
|
end
|
65
|
-
end
|
66
|
-
end
|
65
|
+
end
|
66
|
+
end
|
67
67
|
end
|
68
68
|
|
69
69
|
class << self
|
@@ -86,7 +86,7 @@ module Glimmer
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def disabled_dsls
|
89
|
-
@disabled_dsls ||=
|
89
|
+
@disabled_dsls ||= Concurrent::Array.new
|
90
90
|
end
|
91
91
|
|
92
92
|
def enabled_dsls=(dsl_names)
|
@@ -109,13 +109,13 @@ module Glimmer
|
|
109
109
|
|
110
110
|
# Dynamic expression chains of responsibility indexed by dsl
|
111
111
|
def dynamic_expression_chains_of_responsibility
|
112
|
-
@dynamic_expression_chains_of_responsibility ||=
|
112
|
+
@dynamic_expression_chains_of_responsibility ||= Concurrent::Hash.new
|
113
113
|
end
|
114
114
|
|
115
115
|
# Static expressions indexed by keyword and dsl
|
116
116
|
def static_expressions
|
117
|
-
@static_expressions ||=
|
118
|
-
end
|
117
|
+
@static_expressions ||= Concurrent::Hash.new
|
118
|
+
end
|
119
119
|
|
120
120
|
# Sets dynamic expression chains of responsibility. Useful for internal testing
|
121
121
|
attr_writer :dynamic_expression_chains_of_responsibility
|
@@ -132,7 +132,7 @@ module Glimmer
|
|
132
132
|
# Pattern when interpretting a DSL expression
|
133
133
|
def add_dynamic_expressions(dsl_namespace, *expression_names)
|
134
134
|
expression_names = expression_names.flatten
|
135
|
-
dsl = dsl_namespace.name.split("::").last.downcase.to_sym
|
135
|
+
dsl = dsl_namespace.name.split("::").last.downcase.to_sym
|
136
136
|
dynamic_expression_chains_of_responsibility[dsl] = expression_names.reverse.map do |expression_name|
|
137
137
|
expression_class(dsl_namespace, expression_name).new
|
138
138
|
end.reduce(nil) do |last_expresion_handler, expression|
|
@@ -140,14 +140,14 @@ module Glimmer
|
|
140
140
|
expression_handler = ExpressionHandler.new(expression)
|
141
141
|
expression_handler.next = last_expresion_handler if last_expresion_handler
|
142
142
|
expression_handler
|
143
|
-
end
|
143
|
+
end
|
144
144
|
end
|
145
145
|
|
146
146
|
def add_static_expression(static_expression)
|
147
147
|
Glimmer::Config.logger.info {"Adding static expression: #{static_expression.class.name}"}
|
148
148
|
keyword = static_expression.class.keyword
|
149
149
|
static_expression_dsl = static_expression.class.dsl
|
150
|
-
static_expressions[keyword] ||=
|
150
|
+
static_expressions[keyword] ||= Concurrent::Hash.new
|
151
151
|
static_expressions[keyword][static_expression_dsl] = static_expression
|
152
152
|
Glimmer.send(:define_method, keyword, &STATIC_EXPRESSION_METHOD_FACTORY.call(keyword))
|
153
153
|
end
|
@@ -161,10 +161,11 @@ module Glimmer
|
|
161
161
|
end
|
162
162
|
|
163
163
|
# Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { ... })
|
164
|
-
def interpret(keyword, *args, &block)
|
164
|
+
def interpret(keyword, *args, &block)
|
165
165
|
return puts(MESSAGE_NO_DSLS) if no_dsls?
|
166
166
|
keyword = keyword.to_s
|
167
167
|
dynamic_expression_dsl = (dynamic_expression_chains_of_responsibility.keys - disabled_dsls).first if dsl.nil?
|
168
|
+
# TODO consider pushing this code into interpret_expresion to provide hooks that work around it regardless of static vs dynamic
|
168
169
|
dsl_stack.push(dynamic_expression_dsl || dsl)
|
169
170
|
expression = dynamic_expression_chains_of_responsibility[dsl].handle(parent, keyword, *args, &block)
|
170
171
|
interpret_expression(expression, keyword, *args, &block)
|
@@ -185,7 +186,7 @@ module Glimmer
|
|
185
186
|
def add_content(parent, expression, &block)
|
186
187
|
if block_given? && expression.is_a?(ParentExpression)
|
187
188
|
dsl_stack.push(expression.class.dsl)
|
188
|
-
parent_stack.push(parent)
|
189
|
+
parent_stack.push(parent)
|
189
190
|
begin
|
190
191
|
expression.add_content(parent, &block)
|
191
192
|
ensure
|
@@ -202,16 +203,16 @@ module Glimmer
|
|
202
203
|
def_delegator :parent_stack, :last, :parent
|
203
204
|
|
204
205
|
def parent_stack
|
205
|
-
parent_stacks[dsl] ||=
|
206
|
+
parent_stacks[dsl] ||= Concurrent::Array.new
|
206
207
|
end
|
207
208
|
|
208
209
|
def parent_stacks
|
209
|
-
@parent_stacks ||=
|
210
|
+
@parent_stacks ||= Concurrent::Hash.new
|
210
211
|
end
|
211
212
|
|
212
213
|
# Enables multiple DSLs to play well with each other when mixing together
|
213
214
|
def dsl_stack
|
214
|
-
@dsl_stack ||=
|
215
|
+
@dsl_stack ||= Concurrent::Array.new
|
215
216
|
end
|
216
217
|
end
|
217
218
|
end
|