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
160 161 162 163 164 165 166 167 168 |
# File 'lib/glimmer/dsl/engine.rb', line 160 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 125 126 127 128 129 |
# 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.send(: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).last 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 rescue StandardError => 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
187 188 189 |
# File 'lib/glimmer/dsl/engine.rb', line 187 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
131 132 133 |
# File 'lib/glimmer/dsl/engine.rb', line 131 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
135 136 137 |
# File 'lib/glimmer/dsl/engine.rb', line 135 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) { … })
140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/glimmer/dsl/engine.rb', line 140 def interpret(keyword, *args, &block) keyword = keyword.to_s dynamic_expression_dsl = (dynamic_expression_chains_of_responsibility.keys - disabled_dsls).last 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 |
.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
174 175 176 |
# File 'lib/glimmer/dsl/engine.rb', line 174 def parent parent_stack.last end |
.parent_stack ⇒ Object
178 179 180 |
# File 'lib/glimmer/dsl/engine.rb', line 178 def parent_stack parent_stacks[dsl] ||= [] end |
.parent_stacks ⇒ Object
182 183 184 |
# File 'lib/glimmer/dsl/engine.rb', line 182 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 |