Class: DSLCompose::Interpreter
- Inherits:
-
Object
- Object
- DSLCompose::Interpreter
- Defined in:
- lib/dsl_compose/interpreter.rb,
lib/dsl_compose/interpreter/execution.rb,
lib/dsl_compose/interpreter/interpreter_error.rb,
lib/dsl_compose/interpreter/execution/arguments.rb,
lib/dsl_compose/interpreter/execution/method_calls.rb,
lib/dsl_compose/interpreter/execution/method_calls/method_call.rb
Overview
The class is reponsible for parsing and executing a dynamic DSL (dynamic DSLs are created using the DSLCompose::DSL class).
Defined Under Namespace
Classes: Execution, InterpreterError, InvalidDescriptionError
Instance Attribute Summary collapse
-
#executions ⇒ Object
readonly
A dynamic DSL can be used multiple times on the same class, each time the DSL is used a corresponding execution will be created.
Instance Method Summary collapse
-
#add_parser_usage_note(child_class, note) ⇒ Object
the parser can provide usage notes for how this dsl is being used, these are used to generate documentation.
-
#class_dsl_executions(klass, dsl_name, on_current_class, on_ancestor_class, first_use_only) ⇒ Object
Returns an array of all executions for a given name and class.
-
#class_executions(klass) ⇒ Object
Returns an array of all executions for a given class.
-
#clear ⇒ Object
removes all executions from the interpreter, and any parser_usage_notes this is primarily used from within a test suite when dynamically creating classes for tests and then wanting to clear the interpreter before the next test.
-
#dsl_executions(dsl_name) ⇒ Object
Returns an array of all executions for a given name.
-
#execute_dsl(klass, dsl, called_from) ⇒ Object
Execute/process a dynamically defined DSL on a class.
- #executions_by_class ⇒ Object
-
#get_last_dsl_execution(klass, dsl_name) ⇒ Object
returns the most recent, closest single execution of a dsl with the provided name for the provided class.
-
#initialize ⇒ Interpreter
constructor
A new instance of Interpreter.
-
#parser_usage_notes(child_class) ⇒ Object
return the list of notes which describe how the parsers are using this DSL.
- #to_h(dsl_name) ⇒ Object
Constructor Details
#initialize ⇒ Interpreter
Returns a new instance of Interpreter.
15 16 17 |
# File 'lib/dsl_compose/interpreter.rb', line 15 def initialize @executions = [] end |
Instance Attribute Details
#executions ⇒ Object (readonly)
A dynamic DSL can be used multiple times on the same class, each time the DSL is used a corresponding execution will be created. The execution contains the resulting configuration from that particular use of the DSL.
13 14 15 |
# File 'lib/dsl_compose/interpreter.rb', line 13 def executions @executions end |
Instance Method Details
#add_parser_usage_note(child_class, note) ⇒ Object
the parser can provide usage notes for how this dsl is being used, these are used to generate documentation
21 22 23 24 25 26 27 28 |
# File 'lib/dsl_compose/interpreter.rb', line 21 def add_parser_usage_note child_class, note unless note.is_a?(String) && note.strip.length > 0 raise InvalidDescriptionError.new("The parser usage description `#{note}` is invalid, it must be of type string and have length greater than 0", called_from) end @parser_usage_notes ||= {} @parser_usage_notes[child_class] ||= [] @parser_usage_notes[child_class] << note.strip end |
#class_dsl_executions(klass, dsl_name, on_current_class, on_ancestor_class, first_use_only) ⇒ Object
Returns an array of all executions for a given name and class. This includes any ancestors of the provided class
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/dsl_compose/interpreter.rb', line 69 def class_dsl_executions klass, dsl_name, on_current_class, on_ancestor_class, first_use_only filtered_executions = @executions.filter { |e| e.dsl.name == dsl_name && ((on_current_class && e.klass == klass) || (on_ancestor_class && klass < e.klass)) } # Because the classes were evaluated in order, we can just return the # last execution if first_use_only && filtered_executions.length > 0 [filtered_executions.last] else filtered_executions end end |
#class_executions(klass) ⇒ Object
Returns an array of all executions for a given class.
58 59 60 |
# File 'lib/dsl_compose/interpreter.rb', line 58 def class_executions klass @executions.filter { |e| e.klass == klass } end |
#clear ⇒ Object
removes all executions from the interpreter, and any parser_usage_notes this is primarily used from within a test suite when dynamically creating classes for tests and then wanting to clear the interpreter before the next test.
100 101 102 103 |
# File 'lib/dsl_compose/interpreter.rb', line 100 def clear @executions = [] @parser_usage_notes = {} end |
#dsl_executions(dsl_name) ⇒ Object
Returns an array of all executions for a given name.
63 64 65 |
# File 'lib/dsl_compose/interpreter.rb', line 63 def dsl_executions dsl_name @executions.filter { |e| e.dsl.name == dsl_name } end |
#execute_dsl(klass, dsl, called_from) ⇒ Object
Execute/process a dynamically defined DSL on a class. ‘klass` is the class in which the DSL is being used, not the class in which the DSL was defined.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/dsl_compose/interpreter.rb', line 40 def execute_dsl(klass, dsl, called_from, ...) # make sure we have these variables for the exception message below # set to nil first, so that if we get an exception while setting them # it wont break the error message generation class_name = nil dsl_name = nil class_name = klass.name dsl_name = dsl.name execution = Execution.new(klass, dsl, called_from, ...) @executions << execution execution rescue => e raise e, "Error while defining DSL #{dsl_name} for class #{class_name}:\n#{e.}", e.backtrace end |
#executions_by_class ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/dsl_compose/interpreter.rb', line 120 def executions_by_class h = {} executions.each do |execution| h[execution.klass] ||= {} h[execution.klass][execution.dsl.name] ||= [] execution_h = { arguments: execution.arguments.to_h, method_calls: {} } execution.method_calls.method_calls.each do |method_call| execution_h[:method_calls][method_call.method_name] ||= [] execution_h[:method_calls][method_call.method_name] << method_call.to_h end h[execution.klass][execution.dsl.name] << execution_h end h end |
#get_last_dsl_execution(klass, dsl_name) ⇒ Object
returns the most recent, closest single execution of a dsl with the provided name for the provided class
If the dsl has been executed once or more on the provided class, then the last (most recent) execution will be returned. If the DSL was not executed on the provided class, then we traverse up the classes ancestors until we reach the ancestor where the DSL was originally defined and test each of them and return the first most recent execution of the DSL. If no execution of the DSL is found, then nil will be returned
89 90 91 92 93 94 |
# File 'lib/dsl_compose/interpreter.rb', line 89 def get_last_dsl_execution klass, dsl_name # note that this method does not need to do any special sorting, the required # order for getting the most recent execution is already guaranteed because # parent classes in ruby always have to be evaluated before their descendants class_dsl_executions(klass, dsl_name, true, true, false).last end |
#parser_usage_notes(child_class) ⇒ Object
return the list of notes which describe how the parsers are using this DSL
31 32 33 34 35 |
# File 'lib/dsl_compose/interpreter.rb', line 31 def parser_usage_notes child_class @parser_usage_notes ||= {} @parser_usage_notes[child_class] ||= [] @parser_usage_notes[child_class] end |
#to_h(dsl_name) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/dsl_compose/interpreter.rb', line 105 def to_h dsl_name h = {} dsl_executions(dsl_name).each do |execution| h[execution.klass] ||= { arguments: execution.arguments.to_h, method_calls: {} } execution.method_calls.method_calls.each do |method_call| h[execution.klass][:method_calls][method_call.method_name] ||= [] h[execution.klass][:method_calls][method_call.method_name] << method_call.to_h end end h end |