glimmer 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.7
1
+ 1.1.0
data/glimmer.gemspec CHANGED
@@ -1,17 +1,17 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer 1.0.7 ruby lib
5
+ # stub: glimmer 1.1.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer".freeze
9
- s.version = "1.0.7"
9
+ s.version = "1.1.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["AndyMaleh".freeze]
14
- s.date = "2021-01-11"
14
+ s.date = "2021-02-08"
15
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 = [
@@ -41,33 +41,50 @@ Gem::Specification.new do |s|
41
41
  "lib/glimmer/dsl/static_expression.rb",
42
42
  "lib/glimmer/dsl/top_level_expression.rb",
43
43
  "lib/glimmer/error.rb",
44
+ "lib/glimmer/ext/module.rb",
44
45
  "lib/glimmer/invalid_keyword_error.rb"
45
46
  ]
46
47
  s.homepage = "http://github.com/AndyObtiva/glimmer".freeze
47
48
  s.licenses = ["MIT".freeze]
48
- s.rubygems_version = "3.1.4".freeze
49
+ s.rubygems_version = "3.0.6".freeze
49
50
  s.summary = "Glimmer Ruby DSL Engine".freeze
50
51
 
51
52
  if s.respond_to? :specification_version then
52
53
  s.specification_version = 4
53
- end
54
54
 
55
- if s.respond_to? :add_runtime_dependency then
56
- s.add_runtime_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
57
- s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
58
- s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
59
- s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
60
- s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
61
- s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
62
- s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
63
- s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
64
- s.add_development_dependency(%q<coveralls>.freeze, [">= 0"])
65
- s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
66
- s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
67
- s.add_development_dependency(%q<rake-tui>.freeze, [">= 0"])
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
57
+ s.add_runtime_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
58
+ s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
59
+ s.add_development_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
60
+ s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
61
+ s.add_development_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
62
+ s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
63
+ s.add_development_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
64
+ s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
65
+ s.add_development_dependency(%q<coveralls>.freeze, [">= 0"])
66
+ s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
67
+ s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
68
+ s.add_development_dependency(%q<rake-tui>.freeze, [">= 0"])
69
+ else
70
+ s.add_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
71
+ s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
72
+ s.add_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
73
+ s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
74
+ s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
75
+ s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
76
+ s.add_dependency(%q<rake>.freeze, [">= 10.1.0", "< 14.0.0"])
77
+ s.add_dependency(%q<jeweler>.freeze, [">= 2.0.0", "< 3.0.0"])
78
+ s.add_dependency(%q<rdoc>.freeze, [">= 6.2.1", "< 7.0.0"])
79
+ s.add_dependency(%q<coveralls>.freeze, [">= 0"])
80
+ s.add_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
81
+ s.add_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
82
+ s.add_dependency(%q<rake-tui>.freeze, [">= 0"])
83
+ end
68
84
  else
69
85
  s.add_dependency(%q<array_include_methods>.freeze, [">= 1.0.4", "< 2.0.0"])
70
86
  s.add_dependency(%q<facets>.freeze, [">= 3.1.0", "< 4.0.0"])
87
+ s.add_dependency(%q<concurrent-ruby>.freeze, [">= 1.1.7", "< 2.0.0"])
71
88
  s.add_dependency(%q<rspec-mocks>.freeze, ["~> 3.5.0"])
72
89
  s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
73
90
  s.add_dependency(%q<puts_debuggerer>.freeze, ["~> 0.10.0"])
data/lib/glimmer.rb CHANGED
@@ -22,10 +22,20 @@
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
25
34
 
26
35
  $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
27
36
 
28
37
  require 'glimmer/config'
38
+ require 'glimmer/ext/module'
29
39
 
30
40
  # Glimmer provides a JRuby Desktop UI DSL + Data-Binding functionality
31
41
  #
@@ -56,7 +66,9 @@ module Glimmer
56
66
 
57
67
  def method_missing(method_symbol, *args, &block)
58
68
  # This if statement speeds up Glimmer in girb or whenever directly including on main object
59
- is_excluded = Config.excluded_keyword_checkers.reduce(false) {|result, checker| result || instance_exec(method_symbol, *args, &checker) }
69
+ is_excluded = Config.excluded_keyword_checkers.any? do |checker|
70
+ instance_exec(method_symbol, *args, &checker)
71
+ end
60
72
  if is_excluded
61
73
  Glimmer::Config.logger.debug "Glimmer excluded keyword: #{method_symbol}" if Glimmer::Config.log_excluded_keywords?
62
74
  super(method_symbol, *args, &block)
@@ -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)
@@ -72,21 +72,6 @@ module Glimmer
72
72
  nested_property? ? nested_property_name : property_name_expression
73
73
  end
74
74
 
75
- def convert_on_read(value)
76
- apply_converter(@binding_options[:on_read], value)
77
- end
78
-
79
- def convert_on_write(value)
80
- apply_converter(@binding_options[:on_write], value)
81
- end
82
-
83
- def apply_converter(converter, value)
84
- return value if converter.nil?
85
- return value.send(converter) if (converter.is_a?(String) || converter.is_a?(Symbol)) && value.respond_to?(converter)
86
- return converter.call(value) if converter.respond_to?(:call, value)
87
- raise Glimmer::Error, "Unsupported bind converter: #{converter.inspect}"
88
- end
89
-
90
75
  # All nested property names
91
76
  # e.g. property name expression "address.state" gives ['address', 'state']
92
77
  # If there are any indexed property names, this returns indexes as properties.
@@ -120,9 +105,9 @@ module Glimmer
120
105
  end
121
106
 
122
107
  def nested_property_observers_for(observer)
123
- @nested_property_observers_collection ||= {}
108
+ @nested_property_observers_collection ||= Concurrent::Hash.new
124
109
  unless @nested_property_observers_collection.has_key?(observer)
125
- @nested_property_observers_collection[observer] = nested_property_names.reduce({}) do |output, property_name|
110
+ @nested_property_observers_collection[observer] = nested_property_names.reduce(Concurrent::Hash.new) do |output, property_name|
126
111
  output.merge(
127
112
  property_name => Observer.proc do |new_value|
128
113
  # Ensure reattaching observers when a higher level nested property is updated (e.g. person.address changes reattaches person.address.street observer)
@@ -164,7 +149,7 @@ module Glimmer
164
149
  end
165
150
 
166
151
  def computed_observer_for(observer)
167
- @computed_observer_collection ||= {}
152
+ @computed_observer_collection ||= Concurrent::Hash.new
168
153
  unless @computed_observer_collection.has_key?(observer)
169
154
  @computed_observer_collection[observer] = Observer.proc do |new_value|
170
155
  observer.call(evaluate_property)
@@ -215,9 +200,12 @@ module Glimmer
215
200
  def evaluate_property
216
201
  value = nil
217
202
  value = invoke_property_reader(model, property_name) unless model.nil?
218
- convert_on_read(value)
203
+ apply_processor(@binding_options[:before_read], value)
204
+ converted_value = convert_on_read(value)
205
+ apply_processor(@binding_options[:after_read], converted_value)
206
+ converted_value
219
207
  end
220
-
208
+
221
209
  def evaluate_options_property
222
210
  model.send(options_property_name) unless model.nil?
223
211
  end
@@ -230,6 +218,29 @@ module Glimmer
230
218
  property_expression.to_s.start_with?('[')
231
219
  end
232
220
 
221
+ private
222
+
223
+ def convert_on_read(value)
224
+ apply_processor(@binding_options[:on_read], value)
225
+ end
226
+
227
+ def convert_on_write(value)
228
+ apply_processor(@binding_options[:on_write], value)
229
+ end
230
+
231
+ def apply_processor(processor, value)
232
+ return value if processor.nil?
233
+ return value.send(processor) if (processor.is_a?(String) || processor.is_a?(Symbol)) && value.respond_to?(processor)
234
+ return invoke_proc_with_exact_parameters(processor, value) if processor.respond_to?(:call)
235
+ raise Glimmer::Error, "Unsupported bind processor: #{processor.inspect}"
236
+ end
237
+
238
+ def invoke_proc_with_exact_parameters(proc_object, *args)
239
+ return if proc_object.nil?
240
+ args = args[0...proc_object.parameters.size]
241
+ proc_object.call(*args)
242
+ end
243
+
233
244
  def invoke_property_reader(object, property_expression)
234
245
  if property_indexed?(property_expression)
235
246
  property_method = '[]'
@@ -243,14 +254,16 @@ module Glimmer
243
254
 
244
255
  def invoke_property_writer(object, property_expression, value)
245
256
  raise "Cannot invoke `#{property_expression}` because ModelBinding#binding_options[:read_only]=true" if @binding_options[:read_only]
246
- value = convert_on_write(value)
257
+ apply_processor(@binding_options[:before_write], value)
258
+ converted_value = convert_on_write(value)
259
+ apply_processor(@binding_options[:after_write], converted_value)
247
260
  if property_indexed?(property_expression)
248
261
  property_method = '[]='
249
262
  property_argument = property_expression[1...-2]
250
263
  property_argument = property_argument.to_i if property_argument.match(/\d+/)
251
- object.send(property_method, property_argument, value)
264
+ object.send(property_method, property_argument, converted_value)
252
265
  else
253
- object.send(property_expression, value)
266
+ object.send(property_expression, converted_value)
254
267
  end
255
268
  end
256
269
  end
@@ -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
@@ -289,6 +289,7 @@ module Glimmer
289
289
  return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
290
290
  property_observer_list.each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
291
291
  end
292
+ alias deregister_dependent_observers unregister_dependent_observers
292
293
  end
293
294
  end
294
295
  end
@@ -92,7 +92,7 @@ module Glimmer
92
92
  end
93
93
 
94
94
  def property_observer_list(property_name)
95
- 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]
96
96
  property_observer_hash[property_name.to_sym]
97
97
  end
98
98
 
@@ -124,6 +124,7 @@ module Glimmer
124
124
  return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
125
125
  property_observer_list(property_name).each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self, property_name), old_value) }
126
126
  end
127
+ alias deregister_dependent_observers unregister_dependent_observers
127
128
 
128
129
  def ensure_array_object_observer(property_name, object, old_object = nil)
129
130
  return unless object&.is_a?(Array)
@@ -137,7 +138,7 @@ module Glimmer
137
138
  end
138
139
 
139
140
  def array_object_observer_for(property_name)
140
- @array_object_observers ||= {}
141
+ @array_object_observers ||= Concurrent::Hash.new
141
142
  @array_object_observers[property_name] = ObservableModel::Notifier.new(self, property_name) unless @array_object_observers.has_key?(property_name)
142
143
  @array_object_observers[property_name]
143
144
  end
@@ -61,7 +61,7 @@ module Glimmer
61
61
  end
62
62
 
63
63
  def registrations
64
- @registrations ||= Set.new
64
+ @registrations ||= Concurrent::Set.new
65
65
  end
66
66
 
67
67
  def registration_for(observable, property = nil)
@@ -75,7 +75,7 @@ module Glimmer
75
75
  end
76
76
 
77
77
  def dependents_for(registration)
78
- dependents[registration] ||= Set.new
78
+ dependents[registration] ||= Concurrent::Set.new
79
79
  end
80
80
 
81
81
  # registers observer in an observable on a property (optional)
@@ -110,6 +110,7 @@ module Glimmer
110
110
  end
111
111
  end
112
112
  alias unobserve unregister
113
+ alias deregister unregister
113
114
 
114
115
  def unregister_dependents_with_observable(registration, dependent_observable)
115
116
  thedependents = dependents_for(registration).select do |thedependent|
@@ -117,12 +118,15 @@ module Glimmer
117
118
  end
118
119
  thedependents.each(&:unregister)
119
120
  end
121
+ alias unobserve_dependents_with_observable unregister_dependents_with_observable
122
+ alias deregister_dependents_with_observable unregister_dependents_with_observable
120
123
 
121
124
  # cleans up all registrations in observables
122
125
  def unregister_all_observables
123
126
  registrations.each(&:unregister)
124
127
  end
125
128
  alias unobserve_all_observables unregister_all_observables
129
+ alias deregister_all_observables unregister_all_observables
126
130
 
127
131
  # add dependent observer to unregister when unregistering observer
128
132
  def add_dependent(parent_to_dependent_hash)
@@ -28,7 +28,7 @@ module Glimmer
28
28
  module DSL
29
29
  # Glimmer DSL Engine
30
30
  #
31
- # Follows Interpreter and Chain of Responsibility Design Patterns
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.
@@ -37,10 +37,11 @@ module Glimmer
37
37
  STATIC_EXPRESSION_METHOD_FACTORY = lambda do |keyword|
38
38
  lambda do |*args, &block|
39
39
  if Glimmer::DSL::Engine.no_dsls?
40
- puts Glimmer::DSL::Engine::MESSAGE_NO_DSLS
40
+ puts Glimmer::DSL::Engine::MESSAGE_NO_DSLS # TODO consider switching to an error log statement
41
41
  else
42
42
  retrieved_static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl]
43
- static_expression_dsl = (Glimmer::DSL::Engine.static_expressions[keyword].keys - Glimmer::DSL::Engine.disabled_dsls).first if retrieved_static_expression.nil?
43
+ # TODO consider replacing Glimmer::DSL::Engine.static_expressions[keyword].keys - Glimmer::DSL::Engine.disabled_dsls with Glimmer::DSL::Engine.enabled_static_expression_dsls(keyword)
44
+ static_expression_dsl = (Glimmer::DSL::Engine.static_expressions[keyword].keys - Glimmer::DSL::Engine.disabled_dsls).first
44
45
  interpretation = nil
45
46
  if retrieved_static_expression.nil? && Glimmer::DSL::Engine.dsl && (static_expression_dsl.nil? || !Glimmer::DSL::Engine.static_expressions[keyword][static_expression_dsl].is_a?(TopLevelExpression))
46
47
  begin
@@ -55,8 +56,9 @@ module Glimmer
55
56
  raise Glimmer::Error, "Unsupported keyword: #{keyword}" unless static_expression_dsl || retrieved_static_expression
56
57
  Glimmer::DSL::Engine.dsl_stack.push(static_expression_dsl || Glimmer::DSL::Engine.dsl)
57
58
  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}"
59
+ static_expression_can_interpret = nil
60
+ if static_expression.nil? || !(static_expression_can_interpret = static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block))
61
+ raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent.inspect} with DSL #{Glimmer::DSL::Engine.dsl.inspect} and static expression #{static_expression.inspect} having can_interpret? as #{static_expression_can_interpret.inspect}"
60
62
  else
61
63
  Glimmer::Config.logger.info {"#{static_expression.class.name} will handle expression keyword #{keyword}"}
62
64
  Glimmer::DSL::Engine.interpret_expression(static_expression, keyword, *args, &block)
@@ -86,7 +88,7 @@ module Glimmer
86
88
  end
87
89
 
88
90
  def disabled_dsls
89
- @disabled_dsls ||= []
91
+ @disabled_dsls ||= Concurrent::Array.new
90
92
  end
91
93
 
92
94
  def enabled_dsls=(dsl_names)
@@ -109,12 +111,12 @@ module Glimmer
109
111
 
110
112
  # Dynamic expression chains of responsibility indexed by dsl
111
113
  def dynamic_expression_chains_of_responsibility
112
- @dynamic_expression_chains_of_responsibility ||= {}
114
+ @dynamic_expression_chains_of_responsibility ||= Concurrent::Hash.new
113
115
  end
114
116
 
115
117
  # Static expressions indexed by keyword and dsl
116
118
  def static_expressions
117
- @static_expressions ||= {}
119
+ @static_expressions ||= Concurrent::Hash.new
118
120
  end
119
121
 
120
122
  # Sets dynamic expression chains of responsibility. Useful for internal testing
@@ -147,7 +149,7 @@ module Glimmer
147
149
  Glimmer::Config.logger.info {"Adding static expression: #{static_expression.class.name}"}
148
150
  keyword = static_expression.class.keyword
149
151
  static_expression_dsl = static_expression.class.dsl
150
- static_expressions[keyword] ||= {}
152
+ static_expressions[keyword] ||= Concurrent::Hash.new
151
153
  static_expressions[keyword][static_expression_dsl] = static_expression
152
154
  Glimmer.send(:define_method, keyword, &STATIC_EXPRESSION_METHOD_FACTORY.call(keyword))
153
155
  end
@@ -162,7 +164,7 @@ module Glimmer
162
164
 
163
165
  # Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { ... })
164
166
  def interpret(keyword, *args, &block)
165
- return puts(MESSAGE_NO_DSLS) if no_dsls?
167
+ return puts(MESSAGE_NO_DSLS) if no_dsls? # TODO consider switching to an error log statement
166
168
  keyword = keyword.to_s
167
169
  dynamic_expression_dsl = (dynamic_expression_chains_of_responsibility.keys - disabled_dsls).first if dsl.nil?
168
170
  # TODO consider pushing this code into interpret_expresion to provide hooks that work around it regardless of static vs dynamic
@@ -203,16 +205,16 @@ module Glimmer
203
205
  def_delegator :parent_stack, :last, :parent
204
206
 
205
207
  def parent_stack
206
- parent_stacks[dsl] ||= []
208
+ parent_stacks[dsl] ||= Concurrent::Array.new
207
209
  end
208
210
 
209
211
  def parent_stacks
210
- @parent_stacks ||= {}
212
+ @parent_stacks ||= Concurrent::Hash.new
211
213
  end
212
214
 
213
215
  # Enables multiple DSLs to play well with each other when mixing together
214
216
  def dsl_stack
215
- @dsl_stack ||= []
217
+ @dsl_stack ||= Concurrent::Array.new
216
218
  end
217
219
  end
218
220
  end
@@ -0,0 +1,11 @@
1
+ class Module
2
+ alias append_features_without_glimmer append_features
3
+ def append_features(mod)
4
+ if self == Glimmer && mod == Object
5
+ Glimmer::Config.logger.debug { 'Appending Glimmer to Singleton Class of main object (not appending to Object everywhere to avoid method pollution)' }
6
+ TOPLEVEL_BINDING.receiver.singleton_class.include(self)
7
+ else
8
+ append_features_without_glimmer(mod)
9
+ end
10
+ end
11
+ end