Class: Puppet::Pops::Evaluator::RelationshipOperator
- Includes:
- Runtime3Support
- Defined in:
- lib/puppet/pops/evaluator/relationship_operator.rb
Overview
module. Later when more is cleaned up this can be simplified further.
Defined Under Namespace
Classes: IllegalRelationshipOperandError, NotCatalogTypeError
Constant Summary collapse
- RELATIONSHIP_OPERATORS =
['->', '~>', '<-', '<~'].freeze
- REVERSE_OPERATORS =
['<-', '<~'].freeze
- RELATION_TYPE =
{ '->' => :relationship, '<-' => :relationship, '~>' => :subscription, '<~' => :subscription }.freeze
Constants included from Runtime3Support
Puppet::Pops::Evaluator::Runtime3Support::NAME_SPACE_SEPARATOR
Instance Method Summary collapse
-
#assert_catalog_type(o, scope) ⇒ Object
Asserts (and returns) the type if it is a PCatalogEntryType (A PCatalogEntryType is the base class of PClassType, and PResourceType).
-
#evaluate(left_right_evaluated, relationship_expression, scope) ⇒ Object
Evaluate a relationship.
-
#initialize ⇒ RelationshipOperator
constructor
A new instance of RelationshipOperator.
- #reverse_operator?(o) ⇒ Boolean
- #transform(o, scope) ⇒ Object
- #transform_AbstractCollector(o, scope) ⇒ Object
-
#transform_Array(o, scope) ⇒ Object
Array content needs to be transformed.
-
#transform_Collector(o, scope) ⇒ Object
This transforms a 3x Collector (the result of evaluating a 3x AST::Collection).
-
#transform_Object(o, scope) ⇒ Object
private
Catch all non transformable objects.
-
#transform_PAnyType(o, scope) ⇒ Object
private
Types are what they are, just check the type.
-
#transform_QualifiedName(o, scope) ⇒ Object
private
A qualified name is short hand for a class with this name.
-
#transform_Resource(o, scope) ⇒ Object
private
A Resource is by definition a Catalog type, but of 3.x type.
-
#transform_String(o, scope) ⇒ Object
private
A string must be a type reference in string format.
Methods included from Runtime3Support
#add_relationship, #call_function, #capitalize_qualified_name, #coerce_numeric, #convert, #create_local_scope_from, #create_match_scope_from, #create_resource_defaults, #create_resource_overrides, #create_resource_parameter, #create_resources, #diagnostic_producer, #external_call_function, #extract_file_line, #fail, #find_resource, #get_resource_parameter_value, #get_scope_nesting_level, #get_variable_value, #is_parameter_of_resource?, #is_true?, #optionally_fail, #runtime_issue, #set_match_data, #set_scope_nesting_level, #set_variable, #variable_bound?, #variable_exists?
Constructor Details
#initialize ⇒ RelationshipOperator
Returns a new instance of RelationshipOperator.
35 36 37 38 39 40 41 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 35 def initialize @type_transformer_visitor = Visitor.new(self, "transform", 1, 1) @type_calculator = Types::TypeCalculator.new() tf = Types::TypeFactory @catalog_type = tf.variant(tf.catalog_entry, tf.type_type(tf.catalog_entry)) end |
Instance Method Details
#assert_catalog_type(o, scope) ⇒ Object
Asserts (and returns) the type if it is a PCatalogEntryType (A PCatalogEntryType is the base class of PClassType, and PResourceType).
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 99 def assert_catalog_type(o, scope) unless @type_calculator.assignable?(@catalog_type, o) raise NotCatalogTypeError, o end # TODO must check if this is an abstract PResourceType (i.e. without a type_name) - which should fail ? # e.g. File -> File (and other similar constructs) - maybe the catalog protects against this since references # may be to future objects... o end |
#evaluate(left_right_evaluated, relationship_expression, scope) ⇒ Object
Evaluate a relationship. TODO: The error reporting is not fine grained since evaluation has already taken place There is no references to the original source expressions at this point, only the overall relationship expression. (e.g.. the expression may be [‘string’, func_call(), etc.] -> func_call()) To implement this, the general evaluator needs to be able to track each evaluation result and associate it with a corresponding expression. This structure should then be passed to the relationship operator.
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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 126 def evaluate(left_right_evaluated, relationship_expression, scope) # assert operator (should have been validated, but this logic makes assumptions which would # screw things up royally). Better safe than sorry. unless RELATIONSHIP_OPERATORS.include?(relationship_expression.operator) fail(Issues::UNSUPPORTED_OPERATOR, relationship_expression, { :operator => relationship_expression.operator }) end begin # Turn each side into an array of types (this also asserts their type) # (note wrap in array first if value is not already an array) # # TODO: Later when objects are Puppet Runtime Objects and know their type, it will be more efficient to check/infer # the type first since a chained operation then does not have to visit each element again. This is not meaningful now # since inference needs to visit each object each time, and this is what the transformation does anyway). # # real is [left, right], and both the left and right may be a single value or an array. In each case all content # should be flattened, and then transformed to a type. left or right may also be a value that is transformed # into an array, and thus the resulting left and right must be flattened individually # Once flattened, the operands should be sets (to remove duplicate entries) # real = left_right_evaluated.collect { |x| [x].flatten.collect { |y| transform(y, scope) } } real[0].flatten! real[1].flatten! real[0].uniq! real[1].uniq! # reverse order if operator is Right to Left source, target = reverse_operator?(relationship_expression) ? real.reverse : real # Add the relationships to the catalog source.each { |s| target.each { |t| add_relationship(s, t, RELATION_TYPE[relationship_expression.operator], scope) } } # The result is the transformed source RHS unless it is empty, in which case the transformed LHS is returned. # This closes the gap created by an empty set of references in a chain of relationship # such that X -> [ ] -> Y results in X -> Y. # result = real[1].empty? ? real[0] : real[1] if real[1].empty? # right side empty, simply use the left (whatever it may be) result = real[0] else right = real[1] if right.size == 1 && right[0].is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector) # the collector when evaluated later may result in an empty set, if so, the # lazy relationship forming logic needs to have access to the left value. adapter = Puppet::Pops::Adapters::EmptyAlternativeAdapter.adapt(right[0]) adapter.empty_alternative = real[0] end result = right end result rescue NotCatalogTypeError => e fail(Issues::NOT_CATALOG_TYPE, relationship_expression, { :type => @type_calculator.string(e.type) }) rescue IllegalRelationshipOperandError => e fail(Issues::ILLEGAL_RELATIONSHIP_OPERAND_TYPE, relationship_expression, { :operand => e.operand }) end end |
#reverse_operator?(o) ⇒ Boolean
183 184 185 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 183 def reverse_operator?(o) REVERSE_OPERATORS.include?(o.operator) end |
#transform(o, scope) ⇒ Object
43 44 45 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 43 def transform(o, scope) @type_transformer_visitor.visit_this_1(self, o, scope) end |
#transform_AbstractCollector(o, scope) ⇒ Object
87 88 89 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 87 def transform_AbstractCollector(o, scope) o end |
#transform_Array(o, scope) ⇒ Object
Array content needs to be transformed
92 93 94 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 92 def transform_Array(o, scope) o.map { |x| transform(x, scope) } end |
#transform_Collector(o, scope) ⇒ Object
This transforms a 3x Collector (the result of evaluating a 3x AST::Collection). It is passed through verbatim since it is evaluated late by the compiler. At the point where the relationship is evaluated, it is simply recorded with the compiler for later evaluation. If one of the sides of the relationship is a Collector it is evaluated before the actual relationship is formed. (All of this happens at a later point in time.
83 84 85 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 83 def transform_Collector(o, scope) o end |
#transform_Object(o, scope) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Catch all non transformable objects
49 50 51 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 49 def transform_Object(o, scope) raise IllegalRelationshipOperandError, o end |
#transform_PAnyType(o, scope) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Types are what they are, just check the type
73 74 75 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 73 def transform_PAnyType(o, scope) assert_catalog_type(o, scope) end |
#transform_QualifiedName(o, scope) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
A qualified name is short hand for a class with this name
67 68 69 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 67 def transform_QualifiedName(o, scope) Types::TypeFactory.host_class(o.value) end |
#transform_Resource(o, scope) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
A Resource is by definition a Catalog type, but of 3.x type
55 56 57 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 55 def transform_Resource(o, scope) Types::TypeFactory.resource(o.type, o.title) end |
#transform_String(o, scope) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
A string must be a type reference in string format
61 62 63 |
# File 'lib/puppet/pops/evaluator/relationship_operator.rb', line 61 def transform_String(o, scope) assert_catalog_type(Types::TypeParser.singleton.parse(o), scope) end |