puppet 5.0.1 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/puppet/agent.rb +1 -0
- data/lib/puppet/defaults.rb +1 -1
- data/lib/puppet/functions.rb +6 -7
- data/lib/puppet/functions/all.rb +100 -0
- data/lib/puppet/functions/any.rb +105 -0
- data/lib/puppet/functions/defined.rb +3 -3
- data/lib/puppet/functions/new.rb +2 -1
- data/lib/puppet/functions/reduce.rb +31 -0
- data/lib/puppet/functions/tree_each.rb +200 -0
- data/lib/puppet/module.rb +30 -0
- data/lib/puppet/parser/functions/new.rb +67 -0
- data/lib/puppet/parser/functions/reduce.rb +31 -0
- data/lib/puppet/parser/relationship.rb +2 -2
- data/lib/puppet/parser/resource.rb +39 -10
- data/lib/puppet/parser/scope.rb +1 -1
- data/lib/puppet/pops/evaluator/access_operator.rb +11 -4
- data/lib/puppet/pops/evaluator/collector_transformer.rb +1 -1
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +4 -4
- data/lib/puppet/pops/evaluator/relationship_operator.rb +1 -1
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +3 -3
- data/lib/puppet/pops/evaluator/runtime3_resource_support.rb +1 -1
- data/lib/puppet/pops/loader/module_loaders.rb +1 -1
- data/lib/puppet/pops/loader/static_loader.rb +1 -2
- data/lib/puppet/pops/loaders.rb +1 -2
- data/lib/puppet/pops/lookup/context.rb +1 -1
- data/lib/puppet/pops/lookup/lookup_adapter.rb +2 -1
- data/lib/puppet/pops/model/ast.rb +440 -436
- data/lib/puppet/pops/model/factory.rb +140 -140
- data/lib/puppet/pops/pcore.rb +1 -2
- data/lib/puppet/pops/resource/param.rb +1 -1
- data/lib/puppet/pops/resource/resource_type_impl.rb +1 -1
- data/lib/puppet/pops/serialization/from_data_converter.rb +0 -12
- data/lib/puppet/pops/time/timestamp.rb +29 -17
- data/lib/puppet/pops/types/annotatable.rb +2 -2
- data/lib/puppet/pops/types/annotation.rb +8 -8
- data/lib/puppet/pops/types/class_loader.rb +3 -3
- data/lib/puppet/pops/types/implementation_registry.rb +1 -1
- data/lib/puppet/pops/types/iterable.rb +2 -2
- data/lib/puppet/pops/types/p_binary_type.rb +2 -2
- data/lib/puppet/pops/types/p_init_type.rb +238 -0
- data/lib/puppet/pops/types/p_meta_type.rb +14 -11
- data/lib/puppet/pops/types/p_object_type.rb +15 -15
- data/lib/puppet/pops/types/p_sem_ver_range_type.rb +2 -2
- data/lib/puppet/pops/types/p_sem_ver_type.rb +2 -2
- data/lib/puppet/pops/types/p_sensitive_type.rb +2 -2
- data/lib/puppet/pops/types/p_timespan_type.rb +6 -6
- data/lib/puppet/pops/types/p_timestamp_type.rb +6 -2
- data/lib/puppet/pops/types/p_type_set_type.rb +10 -9
- data/lib/puppet/pops/types/ruby_generator.rb +6 -5
- data/lib/puppet/pops/types/ruby_method.rb +2 -2
- data/lib/puppet/pops/types/string_converter.rb +1 -1
- data/lib/puppet/pops/types/tree_iterators.rb +250 -0
- data/lib/puppet/pops/types/type_calculator.rb +13 -13
- data/lib/puppet/pops/types/type_factory.rb +26 -7
- data/lib/puppet/pops/types/type_formatter.rb +9 -4
- data/lib/puppet/pops/types/type_parser.rb +8 -3
- data/lib/puppet/pops/types/type_set_reference.rb +2 -2
- data/lib/puppet/pops/types/types.rb +168 -109
- data/lib/puppet/provider/package/gem.rb +10 -9
- data/lib/puppet/provider/package/pip.rb +12 -3
- data/lib/puppet/provider/package/yum.rb +9 -1
- data/lib/puppet/resource/capability_finder.rb +30 -11
- data/lib/puppet/type/file.rb +21 -13
- data/lib/puppet/util/execution.rb +67 -14
- data/lib/puppet/util/suidmanager.rb +1 -0
- data/lib/puppet/version.rb +1 -1
- data/locales/puppet.pot +130 -66
- data/man/man5/puppet.conf.5 +1 -1
- data/spec/fixtures/unit/provider/package/yum/yum-check-update-simple.txt +1 -0
- data/spec/integration/parser/collection_spec.rb +40 -1
- data/spec/shared_contexts/types_setup.rb +41 -2
- data/spec/unit/agent_spec.rb +11 -0
- data/spec/unit/file_bucket/dipper_spec.rb +13 -4
- data/spec/unit/functions/all_spec.rb +97 -0
- data/spec/unit/functions/any_spec.rb +109 -0
- data/spec/unit/functions/hiera_spec.rb +5 -0
- data/spec/unit/functions/new_spec.rb +66 -0
- data/spec/unit/functions/tree_each_spec.rb +444 -0
- data/spec/unit/module_spec.rb +29 -0
- data/spec/unit/pops/serialization/serialization_spec.rb +2 -2
- data/spec/unit/pops/serialization/to_from_hr_spec.rb +2 -2
- data/spec/unit/pops/types/iterable_spec.rb +9 -9
- data/spec/unit/pops/types/p_init_type_spec.rb +285 -0
- data/spec/unit/pops/types/p_object_type_spec.rb +8 -8
- data/spec/unit/pops/types/p_sensitive_type_spec.rb +4 -0
- data/spec/unit/pops/types/p_timespan_type_spec.rb +14 -0
- data/spec/unit/pops/types/p_timestamp_type_spec.rb +19 -1
- data/spec/unit/pops/types/p_type_set_type_spec.rb +2 -2
- data/spec/unit/pops/types/ruby_generator_spec.rb +9 -22
- data/spec/unit/pops/types/string_converter_spec.rb +2 -2
- data/spec/unit/pops/types/type_acceptor_spec.rb +2 -2
- data/spec/unit/pops/types/type_calculator_spec.rb +43 -38
- data/spec/unit/pops/types/type_factory_spec.rb +6 -6
- data/spec/unit/pops/types/type_formatter_spec.rb +6 -6
- data/spec/unit/pops/types/types_spec.rb +16 -4
- data/spec/unit/provider/package/gem_spec.rb +6 -6
- data/spec/unit/provider/package/pip_spec.rb +44 -23
- data/spec/unit/provider/package/puppet_gem_spec.rb +1 -1
- data/spec/unit/provider/package/yum_spec.rb +8 -0
- data/spec/unit/resource/capability_finder_spec.rb +4 -5
- data/spec/unit/type/file_spec.rb +19 -14
- data/spec/unit/util/execution_spec.rb +216 -82
- data/tasks/generate_ast_model.rake +10 -2
- metadata +15 -2
@@ -10,6 +10,8 @@ KEY_VALUE = 'value'.freeze
|
|
10
10
|
class PMetaType < PAnyType
|
11
11
|
include Annotatable
|
12
12
|
|
13
|
+
attr_reader :loader
|
14
|
+
|
13
15
|
def self.register_ptype(loader, ir)
|
14
16
|
# Abstract type. It doesn't register anything
|
15
17
|
end
|
@@ -31,16 +33,17 @@ class PMetaType < PAnyType
|
|
31
33
|
# @param loader [Loader::Loader] loader to use when loading type aliases
|
32
34
|
# @return [PTypeAliasType] the receiver of the call, i.e. `self`
|
33
35
|
# @api private
|
34
|
-
def resolve(
|
36
|
+
def resolve(loader)
|
35
37
|
unless @init_hash_expression.nil?
|
38
|
+
@loader = loader
|
36
39
|
@self_recursion = true # assumed while it being found out below
|
37
40
|
|
38
41
|
init_hash_expression = @init_hash_expression
|
39
42
|
@init_hash_expression = nil
|
40
43
|
if init_hash_expression.is_a?(Model::LiteralHash)
|
41
|
-
init_hash = resolve_literal_hash(
|
44
|
+
init_hash = resolve_literal_hash(loader, init_hash_expression)
|
42
45
|
else
|
43
|
-
init_hash = resolve_hash(
|
46
|
+
init_hash = resolve_hash(loader, init_hash_expression)
|
44
47
|
end
|
45
48
|
_pcore_init_from_hash(init_hash)
|
46
49
|
|
@@ -54,22 +57,22 @@ class PMetaType < PAnyType
|
|
54
57
|
self
|
55
58
|
end
|
56
59
|
|
57
|
-
def resolve_literal_hash(
|
58
|
-
|
60
|
+
def resolve_literal_hash(loader, init_hash_expression)
|
61
|
+
TypeParser.singleton.interpret_LiteralHash(init_hash_expression, loader)
|
59
62
|
end
|
60
63
|
|
61
|
-
def resolve_hash(
|
62
|
-
resolve_type_refs(
|
64
|
+
def resolve_hash(loader, init_hash)
|
65
|
+
resolve_type_refs(loader, init_hash)
|
63
66
|
end
|
64
67
|
|
65
|
-
def resolve_type_refs(
|
68
|
+
def resolve_type_refs(loader, o)
|
66
69
|
case o
|
67
70
|
when Hash
|
68
|
-
Hash[o.map { |k, v| [resolve_type_refs(
|
71
|
+
Hash[o.map { |k, v| [resolve_type_refs(loader, k), resolve_type_refs(loader, v)] }]
|
69
72
|
when Array
|
70
|
-
o.map { |e| resolve_type_refs(
|
73
|
+
o.map { |e| resolve_type_refs(loader, e) }
|
71
74
|
when PAnyType
|
72
|
-
o.resolve(
|
75
|
+
o.resolve(loader)
|
73
76
|
else
|
74
77
|
o
|
75
78
|
end
|
@@ -25,7 +25,7 @@ class PObjectType < PMetaType
|
|
25
25
|
TYPE_OBJECT_NAME = Pcore::TYPE_QUALIFIED_REFERENCE
|
26
26
|
|
27
27
|
TYPE_ATTRIBUTE = TypeFactory.struct({
|
28
|
-
KEY_TYPE =>
|
28
|
+
KEY_TYPE => PTypeType::DEFAULT,
|
29
29
|
TypeFactory.optional(KEY_FINAL) => PBooleanType::DEFAULT,
|
30
30
|
TypeFactory.optional(KEY_OVERRIDE) => PBooleanType::DEFAULT,
|
31
31
|
TypeFactory.optional(KEY_KIND) => TYPE_ATTRIBUTE_KIND,
|
@@ -35,7 +35,7 @@ class PObjectType < PMetaType
|
|
35
35
|
TYPE_ATTRIBUTES = TypeFactory.hash_kv(Pcore::TYPE_MEMBER_NAME, TypeFactory.not_undef)
|
36
36
|
TYPE_ATTRIBUTE_CALLABLE = TypeFactory.callable(0,0)
|
37
37
|
|
38
|
-
TYPE_FUNCTION_TYPE =
|
38
|
+
TYPE_FUNCTION_TYPE = PTypeType.new(PCallableType::DEFAULT)
|
39
39
|
|
40
40
|
TYPE_FUNCTION = TypeFactory.struct({
|
41
41
|
KEY_TYPE => TYPE_FUNCTION_TYPE,
|
@@ -51,7 +51,7 @@ class PObjectType < PMetaType
|
|
51
51
|
|
52
52
|
TYPE_OBJECT_I12N = TypeFactory.struct({
|
53
53
|
TypeFactory.optional(KEY_NAME) => TYPE_OBJECT_NAME,
|
54
|
-
TypeFactory.optional(KEY_PARENT) =>
|
54
|
+
TypeFactory.optional(KEY_PARENT) => PTypeType::DEFAULT,
|
55
55
|
TypeFactory.optional(KEY_ATTRIBUTES) => TYPE_ATTRIBUTES,
|
56
56
|
TypeFactory.optional(KEY_FUNCTIONS) => TYPE_FUNCTIONS,
|
57
57
|
TypeFactory.optional(KEY_EQUALITY) => TYPE_EQUALITY,
|
@@ -64,7 +64,7 @@ class PObjectType < PMetaType
|
|
64
64
|
type = create_ptype(loader, ir, 'AnyType', '_pcore_init_hash' => TYPE_OBJECT_I12N)
|
65
65
|
|
66
66
|
# Now, when the Object type exists, add annotations with keys derived from Annotation and freeze the types.
|
67
|
-
annotations = TypeFactory.optional(PHashType.new(
|
67
|
+
annotations = TypeFactory.optional(PHashType.new(PTypeType.new(Annotation._pcore_type), TypeFactory.hash_kv(Pcore::TYPE_MEMBER_NAME, PAnyType::DEFAULT)))
|
68
68
|
TYPE_ATTRIBUTE.hashed_elements[KEY_ANNOTATIONS].replace_value_type(annotations)
|
69
69
|
TYPE_FUNCTION.hashed_elements[KEY_ANNOTATIONS].replace_value_type(annotations)
|
70
70
|
TYPE_OBJECT_I12N.hashed_elements[KEY_ANNOTATIONS].replace_value_type(annotations)
|
@@ -96,7 +96,7 @@ class PObjectType < PMetaType
|
|
96
96
|
# @option init_hash [PAnyType] 'type' The member type (required)
|
97
97
|
# @option init_hash [Boolean] 'override' `true` if this feature must override an inherited feature. Default is `false`.
|
98
98
|
# @option init_hash [Boolean] 'final' `true` if this feature cannot be overridden. Default is `false`.
|
99
|
-
# @option init_hash [Hash{
|
99
|
+
# @option init_hash [Hash{PTypeType => Hash}] 'annotations' Annotations hash. Default is `nil`.
|
100
100
|
# @api public
|
101
101
|
def initialize(name, container, init_hash)
|
102
102
|
@name = name
|
@@ -392,8 +392,8 @@ class PObjectType < PMetaType
|
|
392
392
|
end
|
393
393
|
|
394
394
|
# @api private
|
395
|
-
def new_function
|
396
|
-
@new_function ||= create_new_function
|
395
|
+
def new_function
|
396
|
+
@new_function ||= create_new_function
|
397
397
|
end
|
398
398
|
|
399
399
|
# Assign a new instance reader to this type
|
@@ -428,7 +428,7 @@ class PObjectType < PMetaType
|
|
428
428
|
end
|
429
429
|
|
430
430
|
# @api private
|
431
|
-
def create_new_function
|
431
|
+
def create_new_function
|
432
432
|
impl_class = implementation_class
|
433
433
|
class_name = impl_class.name || "Anonymous Ruby class for #{name}"
|
434
434
|
|
@@ -439,7 +439,7 @@ class PObjectType < PMetaType
|
|
439
439
|
param_types << param_names.size
|
440
440
|
|
441
441
|
create_type = TypeFactory.callable(*param_types)
|
442
|
-
from_hash_type = TypeFactory.callable(
|
442
|
+
from_hash_type = TypeFactory.callable(init_hash_type, 1, 1)
|
443
443
|
|
444
444
|
# Create and return a #new_XXX function where the dispatchers are added programmatically.
|
445
445
|
Puppet::Functions.create_loaded_function(:"new_#{name}", loader) do
|
@@ -514,7 +514,7 @@ class PObjectType < PMetaType
|
|
514
514
|
opt_names = []
|
515
515
|
non_opt_types = []
|
516
516
|
non_opt_names = []
|
517
|
-
|
517
|
+
init_hash_type.elements.each do |se|
|
518
518
|
if se.key_type.is_a?(POptionalType)
|
519
519
|
opt_names << se.name
|
520
520
|
opt_types << se.value_type
|
@@ -598,7 +598,7 @@ class PObjectType < PMetaType
|
|
598
598
|
unless attr_specs.nil? || attr_specs.empty?
|
599
599
|
@attributes = Hash[attr_specs.map do |key, attr_spec|
|
600
600
|
unless attr_spec.is_a?(Hash)
|
601
|
-
attr_type = TypeAsserter.assert_instance_of(nil,
|
601
|
+
attr_type = TypeAsserter.assert_instance_of(nil, PTypeType::DEFAULT, attr_spec) { "attribute #{label}[#{key}]" }
|
602
602
|
attr_spec = { KEY_TYPE => attr_type }
|
603
603
|
attr_spec[KEY_VALUE] = nil if attr_type.is_a?(POptionalType)
|
604
604
|
end
|
@@ -684,8 +684,8 @@ class PObjectType < PMetaType
|
|
684
684
|
#
|
685
685
|
# @return [PStructType] the initialization hash type
|
686
686
|
# @api public
|
687
|
-
def
|
688
|
-
@
|
687
|
+
def init_hash_type
|
688
|
+
@init_hash_type ||= create_init_hash_type
|
689
689
|
end
|
690
690
|
|
691
691
|
def allocate
|
@@ -704,7 +704,7 @@ class PObjectType < PMetaType
|
|
704
704
|
#
|
705
705
|
# @return [PStructType] the initialization hash type
|
706
706
|
# @api private
|
707
|
-
def
|
707
|
+
def create_init_hash_type
|
708
708
|
struct_elems = {}
|
709
709
|
attributes(true).values.each do |attr|
|
710
710
|
unless attr.kind == ATTRIBUTE_KIND_CONSTANT || attr.kind == ATTRIBUTE_KIND_DERIVED
|
@@ -818,7 +818,7 @@ class PObjectType < PMetaType
|
|
818
818
|
|
819
819
|
# @api private
|
820
820
|
def label
|
821
|
-
@name || '
|
821
|
+
@name || 'Object'
|
822
822
|
end
|
823
823
|
|
824
824
|
# @api private
|
@@ -106,9 +106,9 @@ class PSemVerRangeType < PAnyType
|
|
106
106
|
super ^ @version_range.hash
|
107
107
|
end
|
108
108
|
|
109
|
-
def self.new_function(
|
109
|
+
def self.new_function(type)
|
110
110
|
range_expr = "\\A#{range_pattern}\\Z"
|
111
|
-
|
111
|
+
@new_function ||= Puppet::Functions.create_loaded_function(:new_VersionRange, type.loader) do
|
112
112
|
local_types do
|
113
113
|
type 'SemVerRangeString = String[1]'
|
114
114
|
type 'SemVerRangeHash = Struct[{min=>Variant[default,SemVer],Optional[max]=>Variant[default,SemVer],Optional[exclude_max]=>Boolean}]'
|
@@ -55,8 +55,8 @@ class PSemVerType < PScalarType
|
|
55
55
|
end
|
56
56
|
|
57
57
|
# @api private
|
58
|
-
def self.new_function(
|
59
|
-
|
58
|
+
def self.new_function(type)
|
59
|
+
@new_function ||= Puppet::Functions.create_loaded_function(:new_Version, type.loader) do
|
60
60
|
local_types do
|
61
61
|
type 'PositiveInteger = Integer[0,default]'
|
62
62
|
type 'SemVerQualifier = Pattern[/\A(?<part>[0-9A-Za-z-]+)(?:\.\g<part>)*\Z/]'
|
@@ -38,8 +38,8 @@ class PSensitiveType < PTypeWithContainedType
|
|
38
38
|
o.is_a?(Sensitive) && @type.instance?(o.unwrap, guard)
|
39
39
|
end
|
40
40
|
|
41
|
-
def self.new_function(
|
42
|
-
@new_function ||= Puppet::Functions.create_loaded_function(:new_Sensitive, loader) do
|
41
|
+
def self.new_function(type)
|
42
|
+
@new_function ||= Puppet::Functions.create_loaded_function(:new_Sensitive, type.loader) do
|
43
43
|
|
44
44
|
dispatch :from_sensitive do
|
45
45
|
param 'Sensitive', :value
|
@@ -50,10 +50,6 @@ module Types
|
|
50
50
|
self.class == o.class && @from == o.numeric_from && @to == o.numeric_to
|
51
51
|
end
|
52
52
|
|
53
|
-
def instance?(o, guard = nil)
|
54
|
-
o.is_a?(Numeric) && o >= @from && o <= @to
|
55
|
-
end
|
56
|
-
|
57
53
|
def unbounded?
|
58
54
|
@from == -Float::INFINITY && @to == Float::INFINITY
|
59
55
|
end
|
@@ -107,8 +103,8 @@ module Types
|
|
107
103
|
)
|
108
104
|
end
|
109
105
|
|
110
|
-
def self.new_function(
|
111
|
-
@new_function ||= Puppet::Functions.create_loaded_function(:new_timespan, loader) do
|
106
|
+
def self.new_function(type)
|
107
|
+
@new_function ||= Puppet::Functions.create_loaded_function(:new_timespan, type.loader) do
|
112
108
|
local_types do
|
113
109
|
type 'Formats = Variant[String[2],Array[String[2]], 1]'
|
114
110
|
end
|
@@ -186,6 +182,10 @@ module Types
|
|
186
182
|
Time::Timespan
|
187
183
|
end
|
188
184
|
|
185
|
+
def instance?(o, guard = nil)
|
186
|
+
o.is_a?(Time::Timespan) && o >= @from && o <= @to
|
187
|
+
end
|
188
|
+
|
189
189
|
DEFAULT = PTimespanType.new(nil, nil)
|
190
190
|
end
|
191
191
|
end
|
@@ -8,8 +8,8 @@ module Types
|
|
8
8
|
)
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.new_function(
|
12
|
-
@new_function ||= Puppet::Functions.create_loaded_function(:new_timestamp, loader) do
|
11
|
+
def self.new_function(type)
|
12
|
+
@new_function ||= Puppet::Functions.create_loaded_function(:new_timestamp, type.loader) do
|
13
13
|
local_types do
|
14
14
|
type 'Formats = Variant[String[2],Array[String[2]], 1]'
|
15
15
|
end
|
@@ -63,6 +63,10 @@ module Types
|
|
63
63
|
Time::Timestamp
|
64
64
|
end
|
65
65
|
|
66
|
+
def instance?(o, guard = nil)
|
67
|
+
o.is_a?(Time::Timestamp) && o >= @from && o <= @to
|
68
|
+
end
|
69
|
+
|
66
70
|
DEFAULT = PTimestampType.new(nil, nil)
|
67
71
|
end
|
68
72
|
end
|
@@ -48,13 +48,13 @@ class PTypeSetType < PMetaType
|
|
48
48
|
TypeFactory.optional(KEY_NAME_AUTHORITY) => Pcore::TYPE_URI,
|
49
49
|
TypeFactory.optional(KEY_NAME) => Pcore::TYPE_QUALIFIED_REFERENCE,
|
50
50
|
TypeFactory.optional(KEY_VERSION) => TYPE_STRING_OR_VERSION,
|
51
|
-
TypeFactory.optional(KEY_TYPES) => TypeFactory.hash_kv(Pcore::TYPE_SIMPLE_TYPE_NAME,
|
51
|
+
TypeFactory.optional(KEY_TYPES) => TypeFactory.hash_kv(Pcore::TYPE_SIMPLE_TYPE_NAME, PTypeType::DEFAULT, PCollectionType::NOT_EMPTY_SIZE),
|
52
52
|
TypeFactory.optional(KEY_REFERENCES) => TypeFactory.hash_kv(Pcore::TYPE_SIMPLE_TYPE_NAME, TYPE_TYPE_REFERENCE_I12N, PCollectionType::NOT_EMPTY_SIZE),
|
53
53
|
TypeFactory.optional(KEY_ANNOTATIONS) => TYPE_ANNOTATIONS,
|
54
54
|
})
|
55
55
|
|
56
56
|
def self.register_ptype(loader, ir)
|
57
|
-
create_ptype(loader, ir, 'AnyType', '_pcore_init_hash' => TYPE_TYPESET_I12N.resolve(
|
57
|
+
create_ptype(loader, ir, 'AnyType', '_pcore_init_hash' => TYPE_TYPESET_I12N.resolve(loader))
|
58
58
|
end
|
59
59
|
|
60
60
|
attr_reader :pcore_uri
|
@@ -254,17 +254,18 @@ class PTypeSetType < PMetaType
|
|
254
254
|
end
|
255
255
|
|
256
256
|
# @api private
|
257
|
-
def resolve(
|
257
|
+
def resolve(loader)
|
258
258
|
super
|
259
|
-
@references.each_value { |ref| ref.resolve(
|
259
|
+
@references.each_value { |ref| ref.resolve(loader) }
|
260
260
|
tsa_loader = TypeSetLoader.new(self, loader)
|
261
|
-
@types.values.each { |type| type.resolve(
|
261
|
+
@types.values.each { |type| type.resolve(tsa_loader) }
|
262
262
|
self
|
263
263
|
end
|
264
264
|
|
265
265
|
# @api private
|
266
|
-
def resolve_literal_hash(
|
266
|
+
def resolve_literal_hash(loader, init_hash_expression)
|
267
267
|
result = {}
|
268
|
+
type_parser = TypeParser.singleton
|
268
269
|
init_hash_expression.entries.each do |entry|
|
269
270
|
key = type_parser.interpret_any(entry.key, loader)
|
270
271
|
if (key == KEY_TYPES || key == KEY_REFERENCES) && entry.value.is_a?(Model::LiteralHash)
|
@@ -297,10 +298,10 @@ class PTypeSetType < PMetaType
|
|
297
298
|
end
|
298
299
|
|
299
300
|
# @api private
|
300
|
-
def resolve_hash(
|
301
|
+
def resolve_hash(loader, init_hash)
|
301
302
|
result = Hash[init_hash.map do |key, value|
|
302
|
-
key = resolve_type_refs(
|
303
|
-
value = resolve_type_refs(
|
303
|
+
key = resolve_type_refs(loader, key)
|
304
|
+
value = resolve_type_refs(loader, value) unless key == KEY_TYPES && value.is_a?(Hash)
|
304
305
|
[key, value]
|
305
306
|
end]
|
306
307
|
name_auth = resolve_name_authority(result, loader)
|
@@ -60,6 +60,7 @@ class RubyGenerator < TypeFormatter
|
|
60
60
|
index += 1
|
61
61
|
len > segments.size ? segments.size : len
|
62
62
|
end
|
63
|
+
min_prefix_length = 0 if min_prefix_length == Float::INFINITY
|
63
64
|
|
64
65
|
common_prefix = []
|
65
66
|
segments_array = names_by_prefix.keys
|
@@ -190,17 +191,17 @@ class RubyGenerator < TypeFormatter
|
|
190
191
|
|
191
192
|
unless obj.parent.is_a?(PObjectType) && obj_attrs.empty?
|
192
193
|
# Output type safe hash constructor
|
193
|
-
bld << "\n def self.from_hash(
|
194
|
+
bld << "\n def self.from_hash(init_hash)\n"
|
194
195
|
bld << ' from_asserted_hash(' << namespace_relative(segments, TypeAsserter.name) << '.assert_instance_of('
|
195
|
-
bld << "'" << obj.label << " initializer', _pcore_type.
|
196
|
+
bld << "'" << obj.label << " initializer', _pcore_type.init_hash_type, init_hash))\n end\n\n def self.from_asserted_hash(init_hash)\n new"
|
196
197
|
unless non_opt.empty? && opt.empty?
|
197
198
|
bld << "(\n"
|
198
|
-
non_opt.each { |ip| bld << "
|
199
|
+
non_opt.each { |ip| bld << " init_hash['" << ip.name << "'],\n" }
|
199
200
|
opt.each do |ip|
|
200
201
|
if ip.value.nil?
|
201
|
-
bld << "
|
202
|
+
bld << " init_hash['" << ip.name << "'],\n"
|
202
203
|
else
|
203
|
-
bld << "
|
204
|
+
bld << " init_hash.fetch('" << ip.name << "') { "
|
204
205
|
default_string(bld, ip)
|
205
206
|
bld << " },\n"
|
206
207
|
end
|
@@ -12,8 +12,8 @@ module Types
|
|
12
12
|
)
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.from_hash(
|
16
|
-
from_asserted_hash(Types::TypeAsserter.assert_instance_of('RubyMethod initializer', _pcore_type.
|
15
|
+
def self.from_hash(init_hash)
|
16
|
+
from_asserted_hash(Types::TypeAsserter.assert_instance_of('RubyMethod initializer', _pcore_type.init_hash_type, init_hash))
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.from_asserted_hash(init_hash)
|
@@ -0,0 +1,250 @@
|
|
1
|
+
module Puppet::Pops::Types
|
2
|
+
module Iterable
|
3
|
+
|
4
|
+
class TreeIterator
|
5
|
+
include Iterable
|
6
|
+
|
7
|
+
DEFAULT_CONTAINERS = TypeFactory.variant(
|
8
|
+
PArrayType::DEFAULT,
|
9
|
+
PHashType::DEFAULT,
|
10
|
+
PObjectType::DEFAULT
|
11
|
+
)
|
12
|
+
|
13
|
+
# Creates a TreeIterator that by default treats all Array, Hash and Object instances as
|
14
|
+
# containers - the 'containers' option can be set to a type that denotes which types of values
|
15
|
+
# should be treated as containers - a `Variant[Array, Hash]` would for instance not treat
|
16
|
+
# Object values as containers, whereas just `Object` would only treat objects as containers.
|
17
|
+
#
|
18
|
+
# Unrecognized options are silently ignored
|
19
|
+
#
|
20
|
+
# @param [Hash] options the options
|
21
|
+
# @option options [PTypeType] :container_type ('Variant[Hash, Array, Object]') The type(s) that should be treated as containers. The
|
22
|
+
# given type(s) must be assignable to the default container_type.
|
23
|
+
# @option options [Boolean] :include_root ('true') If the root container itself should be included in the iteration (requires
|
24
|
+
# `include_containers` to also be `true` to take effect).
|
25
|
+
# @option options [Boolean] :include_containers ('true') If containers should be included in the iteration
|
26
|
+
# @option options [Boolean] :include_values ('true') If non containers (values) should be included in the iteration
|
27
|
+
# @option options [Boolean] :include_refs ('false') If (non containment) referenced values in Objects should be included
|
28
|
+
#
|
29
|
+
def initialize(enum, options=EMPTY_HASH)
|
30
|
+
@root = enum
|
31
|
+
@element_t = nil
|
32
|
+
@value_stack = [enum]
|
33
|
+
@indexer_stack = []
|
34
|
+
@current_path = []
|
35
|
+
@recursed = false
|
36
|
+
@containers_t = options['container_type'] || DEFAULT_CONTAINERS
|
37
|
+
unless DEFAULT_CONTAINERS.assignable?(@containers_t)
|
38
|
+
raise ArgumentError, _("Only Array, Hash, and Object types can be used as container types. Got %{type}") % {type: @containers_t}
|
39
|
+
end
|
40
|
+
@with_root = extract_option(options, 'include_root', true)
|
41
|
+
@with_containers = extract_option(options, 'include_containers', true)
|
42
|
+
@with_values = extract_option(options, 'include_values', true)
|
43
|
+
@with_root = @with_containers && extract_option(options, 'include_root', true)
|
44
|
+
unless @with_containers || @with_values
|
45
|
+
raise ArgumentError, _("Options 'include_containers' and 'include_values' cannot both be false")
|
46
|
+
end
|
47
|
+
@include_refs = !!options['include_refs']
|
48
|
+
end
|
49
|
+
|
50
|
+
# Yields each `path, value` if the block arity is 2, and only `value` if arity is 1
|
51
|
+
#
|
52
|
+
def each(&block)
|
53
|
+
loop do
|
54
|
+
if block.arity == 1
|
55
|
+
yield(self.next)
|
56
|
+
else
|
57
|
+
yield(*self.next)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def size
|
63
|
+
raise "Not yet implemented - computes size lazily"
|
64
|
+
end
|
65
|
+
|
66
|
+
def unbounded?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_array
|
71
|
+
result = []
|
72
|
+
loop do
|
73
|
+
result << self.next
|
74
|
+
end
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
def reverse_each(&block)
|
79
|
+
r = Iterator.new(PAnyType::DEFAULT, to_array.reverse_each)
|
80
|
+
block_given? ? r.each(&block) : r
|
81
|
+
end
|
82
|
+
|
83
|
+
def step(step, &block)
|
84
|
+
r = StepIterator.new(PAnyType::DEFAULT, self, step)
|
85
|
+
block_given? ? r.each(&block) : r
|
86
|
+
end
|
87
|
+
|
88
|
+
def indexer_on(val)
|
89
|
+
return nil unless @containers_t.instance?(val)
|
90
|
+
if val.is_a?(Array)
|
91
|
+
val.size.times
|
92
|
+
elsif val.is_a?(Hash)
|
93
|
+
val.each_key
|
94
|
+
else
|
95
|
+
if @include_refs
|
96
|
+
val._pcore_type.attributes.each_key
|
97
|
+
else
|
98
|
+
val._pcore_type.attributes.reject {|k,v| v.kind == PObjectType::ATTRIBUTE_KIND_REFERENCE }.each_key
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
private :indexer_on
|
103
|
+
|
104
|
+
def has_next?(iterator)
|
105
|
+
begin
|
106
|
+
iterator.peek
|
107
|
+
true
|
108
|
+
rescue StopIteration
|
109
|
+
false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
private :has_next?
|
113
|
+
|
114
|
+
def extract_option(options, key, default)
|
115
|
+
v = options[key]
|
116
|
+
v.nil? ? default : !!v
|
117
|
+
end
|
118
|
+
private :extract_option
|
119
|
+
end
|
120
|
+
|
121
|
+
class DepthFirstTreeIterator < TreeIterator
|
122
|
+
|
123
|
+
# Creates a DepthFirstTreeIterator that by default treats all Array, Hash and Object instances as
|
124
|
+
# containers - the 'containers' option can be set to a type that denotes which types of values
|
125
|
+
# should be treated as containers - a `Variant[Array, Hash]` would for instance not treat
|
126
|
+
# Object values as containers, whereas just `Object` would only treat objects as containers.
|
127
|
+
#
|
128
|
+
# @param [Hash] options the options
|
129
|
+
# @option options [PTypeType] :containers ('Variant[Hash, Array, Object]') The type(s) that should be treated as containers
|
130
|
+
# @option options [Boolean] :with_root ('true') If the root container itself should be included in the iteration
|
131
|
+
#
|
132
|
+
def initialize(enum, options = EMPTY_HASH)
|
133
|
+
super
|
134
|
+
end
|
135
|
+
|
136
|
+
def next
|
137
|
+
loop do
|
138
|
+
break if @value_stack.empty?
|
139
|
+
|
140
|
+
# first call
|
141
|
+
if @indexer_stack.empty?
|
142
|
+
@indexer_stack << indexer_on(@root)
|
143
|
+
@recursed = true
|
144
|
+
return [[], @root] if @with_root
|
145
|
+
end
|
146
|
+
|
147
|
+
begin
|
148
|
+
if @recursed
|
149
|
+
@current_path << nil
|
150
|
+
@recursed = false
|
151
|
+
end
|
152
|
+
idx = @indexer_stack[-1].next
|
153
|
+
@current_path[-1] = idx
|
154
|
+
v = @value_stack[-1]
|
155
|
+
value = v.is_a?(PuppetObject) ? v.send(idx) : v[idx]
|
156
|
+
indexer = indexer_on(value)
|
157
|
+
if indexer
|
158
|
+
# recurse
|
159
|
+
@recursed = true
|
160
|
+
@value_stack << value
|
161
|
+
@indexer_stack << indexer
|
162
|
+
redo unless @with_containers
|
163
|
+
else
|
164
|
+
redo unless @with_values
|
165
|
+
end
|
166
|
+
return [@current_path.dup, value]
|
167
|
+
|
168
|
+
rescue StopIteration
|
169
|
+
# end of current value's range of content
|
170
|
+
# pop all until out of next values
|
171
|
+
at_the_very_end = false
|
172
|
+
loop do
|
173
|
+
pop_level
|
174
|
+
at_the_very_end = @indexer_stack.empty?
|
175
|
+
break if at_the_very_end || has_next?(@indexer_stack[-1])
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
raise StopIteration
|
180
|
+
end
|
181
|
+
|
182
|
+
def pop_level
|
183
|
+
@value_stack.pop
|
184
|
+
@indexer_stack.pop
|
185
|
+
@current_path.pop
|
186
|
+
end
|
187
|
+
private :pop_level
|
188
|
+
end
|
189
|
+
|
190
|
+
class BreadthFirstTreeIterator < TreeIterator
|
191
|
+
def initialize(enum, options = EMPTY_HASH)
|
192
|
+
@path_stack = []
|
193
|
+
super
|
194
|
+
end
|
195
|
+
|
196
|
+
def next
|
197
|
+
loop do
|
198
|
+
break if @value_stack.empty?
|
199
|
+
|
200
|
+
# first call
|
201
|
+
if @indexer_stack.empty?
|
202
|
+
@indexer_stack << indexer_on(@root)
|
203
|
+
@recursed = true
|
204
|
+
return [[], @root] if @with_root
|
205
|
+
end
|
206
|
+
|
207
|
+
begin
|
208
|
+
if @recursed
|
209
|
+
@current_path << nil
|
210
|
+
@recursed = false
|
211
|
+
end
|
212
|
+
|
213
|
+
idx = @indexer_stack[0].next
|
214
|
+
@current_path[-1] = idx
|
215
|
+
v = @value_stack[0]
|
216
|
+
value = v.is_a?(PuppetObject) ? v.send(idx) : v[idx]
|
217
|
+
indexer = indexer_on(value)
|
218
|
+
if indexer
|
219
|
+
@value_stack << value
|
220
|
+
@indexer_stack << indexer
|
221
|
+
@path_stack << @current_path.dup
|
222
|
+
next unless @with_containers
|
223
|
+
end
|
224
|
+
return [@current_path.dup, value]
|
225
|
+
|
226
|
+
rescue StopIteration
|
227
|
+
# end of current value's range of content
|
228
|
+
# shift all until out of next values
|
229
|
+
at_the_very_end = false
|
230
|
+
loop do
|
231
|
+
shift_level
|
232
|
+
at_the_very_end = @indexer_stack.empty?
|
233
|
+
break if at_the_very_end || has_next?(@indexer_stack[0])
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
raise StopIteration
|
238
|
+
end
|
239
|
+
|
240
|
+
def shift_level
|
241
|
+
@value_stack.shift
|
242
|
+
@indexer_stack.shift
|
243
|
+
@current_path = @path_stack.shift
|
244
|
+
@recursed = true
|
245
|
+
end
|
246
|
+
private :shift_level
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|