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
- .dsl ⇒ Object
- .dsl=(dsl_name) ⇒ Object
-
.dsl_stack ⇒ Object
Enables multiple DSLs to play well with each other when mixing together.
-
.dynamic_expression_chains_of_responsibility ⇒ Object
Dynamic expression chains of responsibility indexed by dsl.
- .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
-
.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
120 121 122 123 124 125 126 127 |
# File 'lib/glimmer/dsl/engine.rb', line 120 def add_content(parent, expression, &block) time = Time.now.to_f dsl_stack.push(expression.class.dsl) parent_stack.push(parent) if expression.is_a?(ParentExpression) expression.add_content(parent, &block) if block_given? parent_stack.pop if expression.is_a?(ParentExpression) dsl_stack.pop 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
44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/glimmer/dsl/engine.rb', line 44 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.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
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/glimmer/dsl/engine.rb', line 56 def add_static_expression(static_expression) Glimmer.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.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 raise e if static_expression_dsl.nil? 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.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 raise e end end 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
146 147 148 |
# File 'lib/glimmer/dsl/engine.rb', line 146 def dsl_stack @dsl_stack ||= [] end |
.dynamic_expression_chains_of_responsibility ⇒ Object
Dynamic expression chains of responsibility indexed by dsl
28 29 30 |
# File 'lib/glimmer/dsl/engine.rb', line 28 def dynamic_expression_chains_of_responsibility @dynamic_expression_chains_of_responsibility ||= {} end |
.expression_class(dsl_namespace, expression_name) ⇒ Object
92 93 94 |
# File 'lib/glimmer/dsl/engine.rb', line 92 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
96 97 98 |
# File 'lib/glimmer/dsl/engine.rb', line 96 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) { … })
101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/glimmer/dsl/engine.rb', line 101 def interpret(keyword, *args, &block) keyword = keyword.to_s dynamic_expression_dsl = dynamic_expression_chains_of_responsibility.keys.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 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
133 134 135 |
# File 'lib/glimmer/dsl/engine.rb', line 133 def parent parent_stack.last end |
.parent_stack ⇒ Object
137 138 139 |
# File 'lib/glimmer/dsl/engine.rb', line 137 def parent_stack parent_stacks[dsl] ||= [] end |
.parent_stacks ⇒ Object
141 142 143 |
# File 'lib/glimmer/dsl/engine.rb', line 141 def parent_stacks @parent_stacks ||= {} end |
.static_expressions ⇒ Object
Static expressions indexed by keyword and dsl
33 34 35 |
# File 'lib/glimmer/dsl/engine.rb', line 33 def static_expressions @static_expressions ||= {} end |