Class: Glimmer::DSL::Engine
- Inherits:
-
Object
- Object
- Glimmer::DSL::Engine
- Defined in:
- lib/glimmer/dsl/engine.rb
Overview
Glimmer DSL Engine
Follows Interpreter and Chain of Responsibility Design Patterns
When DSL engine interprets an expression, it attempts to handle with ordered expression array specified via ‘.expressions=` method.
Constant Summary collapse
- MESSAGE_NO_DSLS =
"Glimmer has no DSLs configured. Add glimmer-dsl-swt gem or visit https://github.com/AndyObtiva/glimmer#multi-dsl-support for more details.\n"
Class Method Summary collapse
-
.add_content(parent, expression, &block) ⇒ Object
Adds content block to parent UI object.
-
.add_dynamic_expressions(dsl_namespace, *expression_names) ⇒ Object
Sets an ordered array of DSL expressions to support.
- .add_static_expression(static_expression) ⇒ Object
- .disable_dsl(dsl_name) ⇒ Object
- .disabled_dsls ⇒ Object
- .dsl ⇒ Object
- .dsl=(dsl_name) ⇒ Object
-
.dsl_stack ⇒ Object
Enables multiple DSLs to play well with each other when mixing together.
- .dsls ⇒ Object
-
.dynamic_expression_chains_of_responsibility ⇒ Object
Dynamic expression chains of responsibility indexed by dsl.
-
.dynamic_expression_chains_of_responsibility=(chains) ⇒ Object
Sets dynamic expression chains of responsibility.
- .enable_dsl(dsl_name) ⇒ Object
- .enabled_dsls=(dsl_names) ⇒ Object
- .expression_class(dsl_namespace, expression_name) ⇒ Object
- .expression_class_name(expression_name) ⇒ Object
-
.interpret(keyword, *args, &block) ⇒ Object
Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { … }).
- .no_dsls? ⇒ Boolean
-
.parent ⇒ Object
Current parent while evaluating Glimmer DSL (nil if just started or done evaluatiing).
- .parent_stack ⇒ Object
- .parent_stacks ⇒ Object
-
.reset ⇒ Object
Resets Glimmer’s engine activity and configuration.
-
.static_expressions ⇒ Object
Static expressions indexed by keyword and dsl.
-
.static_expressions=(expressions) ⇒ Object
Sets static expressions.
Class Method Details
.add_content(parent, expression, &block) ⇒ Object
Adds content block to parent UI object
This allows evaluating parent UI object properties and children
For example, a shell widget would get properties set and children added
186 187 188 189 190 191 192 193 194 |
# File 'lib/glimmer/dsl/engine.rb', line 186 def add_content(parent, expression, &block) if block_given? && expression.is_a?(ParentExpression) dsl_stack.push(expression.class.dsl) parent_stack.push(parent) expression.add_content(parent, &block) parent_stack.pop dsl_stack.pop end end |
.add_dynamic_expressions(dsl_namespace, *expression_names) ⇒ Object
Sets an ordered array of DSL expressions to support
Every expression has an underscored name corresponding to an upper camelcase AbstractExpression subclass name in glimmer/dsl
They are used in order following the Chain of Responsibility Design Pattern when interpretting a DSL expression
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/glimmer/dsl/engine.rb', line 93 def add_dynamic_expressions(dsl_namespace, *expression_names) expression_names = expression_names.flatten dsl = dsl_namespace.name.split("::").last.downcase.to_sym dynamic_expression_chains_of_responsibility[dsl] = expression_names.reverse.map do |expression_name| expression_class(dsl_namespace, expression_name).new end.reduce(nil) do |last_expresion_handler, expression| Glimmer::Config.logger&.debug "Adding dynamic expression: #{expression.class.name}" expression_handler = ExpressionHandler.new(expression) expression_handler.next = last_expresion_handler if last_expresion_handler expression_handler end end |
.add_static_expression(static_expression) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/glimmer/dsl/engine.rb', line 106 def add_static_expression(static_expression) Glimmer::Config.logger&.debug "Adding static expression: #{static_expression.class.name}" keyword = static_expression.class.keyword static_expression_dsl = static_expression.class.dsl static_expressions[keyword] ||= {} static_expressions[keyword][static_expression_dsl] = static_expression Glimmer.send(:define_method, keyword) do |*args, &block| begin if Glimmer::DSL::Engine.no_dsls? puts Glimmer::DSL::Engine::MESSAGE_NO_DSLS else retrieved_static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl] static_expression_dsl = (Glimmer::DSL::Engine.static_expressions[keyword].keys - Glimmer::DSL::Engine.disabled_dsls).first if retrieved_static_expression.nil? interpretation = nil 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)) begin interpretation = Glimmer::DSL::Engine.interpret(keyword, *args, &block) rescue => e Glimmer::DSL::Engine.reset raise e if static_expression_dsl.nil? || !Glimmer::DSL::Engine.static_expressions[keyword][static_expression_dsl].is_a?(TopLevelExpression) end end if interpretation interpretation else raise Glimmer::Error, "Unsupported keyword: #{keyword}" unless static_expression_dsl || retrieved_static_expression Glimmer::DSL::Engine.dsl_stack.push(static_expression_dsl || Glimmer::DSL::Engine.dsl) static_expression = Glimmer::DSL::Engine.static_expressions[keyword][Glimmer::DSL::Engine.dsl] if !static_expression.can_interpret?(Glimmer::DSL::Engine.parent, keyword, *args, &block) raise Error, "Invalid use of Glimmer keyword #{keyword} with args #{args} under parent #{Glimmer::DSL::Engine.parent}" else Glimmer::Config.logger&.debug "#{static_expression.class.name} will handle expression keyword #{keyword}" static_expression.interpret(Glimmer::DSL::Engine.parent, keyword, *args, &block).tap do |ui_object| Glimmer::DSL::Engine.add_content(ui_object, static_expression, &block) unless block.nil? Glimmer::DSL::Engine.dsl_stack.pop end end end end rescue StandardError => e # Glimmer::DSL::Engine.dsl_stack.pop Glimmer::DSL::Engine.reset raise e end end end |
.disable_dsl(dsl_name) ⇒ Object
34 35 36 37 |
# File 'lib/glimmer/dsl/engine.rb', line 34 def disable_dsl(dsl_name) dsl_name = dsl_name.to_sym disabled_dsls << dsl_name end |
.disabled_dsls ⇒ Object
44 45 46 |
# File 'lib/glimmer/dsl/engine.rb', line 44 def disabled_dsls @disabled_dsls ||= [] end |
.dsl ⇒ Object
26 27 28 |
# File 'lib/glimmer/dsl/engine.rb', line 26 def dsl dsl_stack.last end |
.dsl=(dsl_name) ⇒ Object
17 18 19 20 21 22 23 24 |
# File 'lib/glimmer/dsl/engine.rb', line 17 def dsl=(dsl_name) dsl_name = dsl_name&.to_sym if dsl_name dsl_stack.push(dsl_name) else dsl_stack.clear end end |
.dsl_stack ⇒ Object
Enables multiple DSLs to play well with each other when mixing together
213 214 215 |
# File 'lib/glimmer/dsl/engine.rb', line 213 def dsl_stack @dsl_stack ||= [] end |
.dsls ⇒ Object
30 31 32 |
# File 'lib/glimmer/dsl/engine.rb', line 30 def dsls static_expressions.values.map(&:keys).flatten.uniq end |
.dynamic_expression_chains_of_responsibility ⇒ Object
Dynamic expression chains of responsibility indexed by dsl
67 68 69 |
# File 'lib/glimmer/dsl/engine.rb', line 67 def dynamic_expression_chains_of_responsibility @dynamic_expression_chains_of_responsibility ||= {} end |
.dynamic_expression_chains_of_responsibility=(chains) ⇒ Object
Sets dynamic expression chains of responsibility. Useful for internal testing
77 78 79 |
# File 'lib/glimmer/dsl/engine.rb', line 77 def dynamic_expression_chains_of_responsibility=(chains) @dynamic_expression_chains_of_responsibility = chains end |
.enable_dsl(dsl_name) ⇒ Object
39 40 41 42 |
# File 'lib/glimmer/dsl/engine.rb', line 39 def enable_dsl(dsl_name) dsl_name = dsl_name.to_sym disabled_dsls.delete(dsl_name) end |
.enabled_dsls=(dsl_names) ⇒ Object
48 49 50 51 |
# File 'lib/glimmer/dsl/engine.rb', line 48 def enabled_dsls=(dsl_names) dsls.each {|dsl_name| disable_dsl(dsl_name)} dsl_names.each {|dsl_name| enable_dsl(dsl_name)} end |
.expression_class(dsl_namespace, expression_name) ⇒ Object
153 154 155 |
# File 'lib/glimmer/dsl/engine.rb', line 153 def expression_class(dsl_namespace, expression_name) dsl_namespace.const_get(expression_class_name(expression_name).to_sym) end |
.expression_class_name(expression_name) ⇒ Object
157 158 159 |
# File 'lib/glimmer/dsl/engine.rb', line 157 def expression_class_name(expression_name) "#{expression_name}_expression".camelcase(:upper) end |
.interpret(keyword, *args, &block) ⇒ Object
Interprets Glimmer dynamic DSL expression consisting of keyword, args, and block (e.g. shell(:no_resize) { … })
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/glimmer/dsl/engine.rb', line 162 def interpret(keyword, *args, &block) if no_dsls? puts MESSAGE_NO_DSLS return end keyword = keyword.to_s dynamic_expression_dsl = (dynamic_expression_chains_of_responsibility.keys - disabled_dsls).first if dsl.nil? dsl_stack.push(dynamic_expression_dsl || dsl) expression = dynamic_expression_chains_of_responsibility[dsl].handle(parent, keyword, *args, &block) expression.interpret(parent, keyword, *args, &block).tap do |ui_object| add_content(ui_object, expression, &block) dsl_stack.pop end rescue StandardError => e # dsl_stack.pop reset raise e end |
.no_dsls? ⇒ Boolean
62 63 64 |
# File 'lib/glimmer/dsl/engine.rb', line 62 def no_dsls? static_expressions.empty? && dynamic_expression_chains_of_responsibility.empty? end |
.parent ⇒ Object
Current parent while evaluating Glimmer DSL (nil if just started or done evaluatiing)
Parents are maintained in a stack while evaluating Glimmer DSL to ensure properly ordered interpretation of DSL syntax
200 201 202 |
# File 'lib/glimmer/dsl/engine.rb', line 200 def parent parent_stack.last end |
.parent_stack ⇒ Object
204 205 206 |
# File 'lib/glimmer/dsl/engine.rb', line 204 def parent_stack parent_stacks[dsl] ||= [] end |
.parent_stacks ⇒ Object
208 209 210 |
# File 'lib/glimmer/dsl/engine.rb', line 208 def parent_stacks @parent_stacks ||= {} end |
.reset ⇒ Object
Resets Glimmer’s engine activity and configuration. Useful in rspec before or after blocks in tests.
54 55 56 57 58 59 60 |
# File 'lib/glimmer/dsl/engine.rb', line 54 def reset parent_stacks.values.each do |a_parent_stack| a_parent_stack.clear end dsl_stack.clear disabled_dsls.clear end |
.static_expressions ⇒ Object
Static expressions indexed by keyword and dsl
72 73 74 |
# File 'lib/glimmer/dsl/engine.rb', line 72 def static_expressions @static_expressions ||= {} end |
.static_expressions=(expressions) ⇒ Object
Sets static expressions. Useful for internal testing
82 83 84 |
# File 'lib/glimmer/dsl/engine.rb', line 82 def static_expressions=(expressions) @static_expressions = expressions end |