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.
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.
- .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) { … }).
-
.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.
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
155 156 157 158 159 160 161 162 163 |
# File 'lib/glimmer/dsl/engine.rb', line 155 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
76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/glimmer/dsl/engine.rb', line 76 def add_dynamic_expressions(dsl_namespace, expression_names) 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
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/glimmer/dsl/engine.rb', line 88 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.define_method(keyword) do |*args, &block| begin 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? 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 return 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 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}" return 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 rescue => e # Glimmer::DSL::Engine.dsl_stack.pop Glimmer::DSL::Engine.reset raise e end end end |
.disable_dsl(dsl_name) ⇒ Object
31 32 33 34 |
# File 'lib/glimmer/dsl/engine.rb', line 31 def disable_dsl(dsl_name) dsl_name = dsl_name.to_sym disabled_dsls << dsl_name end |
.disabled_dsls ⇒ Object
41 42 43 |
# File 'lib/glimmer/dsl/engine.rb', line 41 def disabled_dsls @disabled_dsls ||= [] end |
.dsl ⇒ Object
23 24 25 |
# File 'lib/glimmer/dsl/engine.rb', line 23 def dsl dsl_stack.last end |
.dsl=(dsl_name) ⇒ Object
14 15 16 17 18 19 20 21 |
# File 'lib/glimmer/dsl/engine.rb', line 14 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
182 183 184 |
# File 'lib/glimmer/dsl/engine.rb', line 182 def dsl_stack @dsl_stack ||= [] end |
.dsls ⇒ Object
27 28 29 |
# File 'lib/glimmer/dsl/engine.rb', line 27 def dsls static_expressions.values.map(&:keys).flatten.uniq end |
.dynamic_expression_chains_of_responsibility ⇒ Object
Dynamic expression chains of responsibility indexed by dsl
60 61 62 |
# File 'lib/glimmer/dsl/engine.rb', line 60 def dynamic_expression_chains_of_responsibility @dynamic_expression_chains_of_responsibility ||= {} end |
.enable_dsl(dsl_name) ⇒ Object
36 37 38 39 |
# File 'lib/glimmer/dsl/engine.rb', line 36 def enable_dsl(dsl_name) dsl_name = dsl_name.to_sym disabled_dsls.delete(dsl_name) end |
.enabled_dsls=(dsl_names) ⇒ Object
45 46 47 48 |
# File 'lib/glimmer/dsl/engine.rb', line 45 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
126 127 128 |
# File 'lib/glimmer/dsl/engine.rb', line 126 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
130 131 132 |
# File 'lib/glimmer/dsl/engine.rb', line 130 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) { … })
135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/glimmer/dsl/engine.rb', line 135 def interpret(keyword, *args, &block) 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 => e # dsl_stack.pop reset raise e 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
169 170 171 |
# File 'lib/glimmer/dsl/engine.rb', line 169 def parent parent_stack.last end |
.parent_stack ⇒ Object
173 174 175 |
# File 'lib/glimmer/dsl/engine.rb', line 173 def parent_stack parent_stacks[dsl] ||= [] end |
.parent_stacks ⇒ Object
177 178 179 |
# File 'lib/glimmer/dsl/engine.rb', line 177 def parent_stacks @parent_stacks ||= {} end |
.reset ⇒ Object
Resets Glimmer’s engine activity and configuration. Useful in rspec before or after blocks in tests.
51 52 53 54 55 56 57 |
# File 'lib/glimmer/dsl/engine.rb', line 51 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
65 66 67 |
# File 'lib/glimmer/dsl/engine.rb', line 65 def static_expressions @static_expressions ||= {} end |