bolt 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bolt might be problematic. Click here for more details.

Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bolt/cli.rb +65 -28
  3. data/lib/bolt/config.rb +18 -8
  4. data/lib/bolt/executor.rb +21 -6
  5. data/lib/bolt/node.rb +3 -0
  6. data/lib/bolt/node/result.rb +5 -0
  7. data/lib/bolt/node/ssh.rb +81 -25
  8. data/lib/bolt/node/winrm.rb +70 -31
  9. data/lib/bolt/notifier.rb +20 -0
  10. data/lib/bolt/outputter.rb +21 -0
  11. data/lib/bolt/outputter/human.rb +30 -0
  12. data/lib/bolt/outputter/json.rb +51 -0
  13. data/lib/bolt/result.rb +32 -5
  14. data/lib/bolt/version.rb +1 -1
  15. data/vendored/puppet/lib/puppet.rb +4 -5
  16. data/vendored/puppet/lib/puppet/agent.rb +22 -2
  17. data/vendored/puppet/lib/puppet/application/agent.rb +1 -1
  18. data/vendored/puppet/lib/puppet/application/apply.rb +1 -1
  19. data/vendored/puppet/lib/puppet/configurer/downloader_factory.rb +10 -0
  20. data/vendored/puppet/lib/puppet/configurer/plugin_handler.rb +4 -4
  21. data/vendored/puppet/lib/puppet/defaults.rb +21 -2
  22. data/vendored/puppet/lib/puppet/external/nagios/parser.rb +1 -1
  23. data/vendored/puppet/lib/puppet/file_serving/configuration.rb +3 -0
  24. data/vendored/puppet/lib/puppet/file_serving/configuration/parser.rb +2 -0
  25. data/vendored/puppet/lib/puppet/file_serving/mount/locales.rb +35 -0
  26. data/vendored/puppet/lib/puppet/forge.rb +9 -3
  27. data/vendored/puppet/lib/puppet/forge/repository.rb +1 -1
  28. data/vendored/puppet/lib/puppet/functions/file_upload.rb +20 -15
  29. data/vendored/puppet/lib/puppet/functions/new.rb +1 -4
  30. data/vendored/puppet/lib/puppet/functions/run_command.rb +15 -13
  31. data/vendored/puppet/lib/puppet/functions/run_script.rb +27 -14
  32. data/vendored/puppet/lib/puppet/functions/run_task.rb +21 -19
  33. data/vendored/puppet/lib/puppet/gettext/config.rb +86 -28
  34. data/vendored/puppet/lib/puppet/indirector/catalog/compiler.rb +25 -5
  35. data/vendored/puppet/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  36. data/vendored/puppet/lib/puppet/module.rb +13 -17
  37. data/vendored/puppet/lib/puppet/pops/evaluator/access_operator.rb +20 -21
  38. data/vendored/puppet/lib/puppet/pops/evaluator/compare_operator.rb +3 -3
  39. data/vendored/puppet/lib/puppet/pops/evaluator/evaluator_impl.rb +9 -0
  40. data/vendored/puppet/lib/puppet/pops/loader/static_loader.rb +20 -1
  41. data/vendored/puppet/lib/puppet/pops/loader/task_instantiator.rb +2 -1
  42. data/vendored/puppet/lib/puppet/pops/loaders.rb +6 -41
  43. data/vendored/puppet/lib/puppet/pops/pcore.rb +9 -0
  44. data/vendored/puppet/lib/puppet/pops/serialization/from_data_converter.rb +64 -10
  45. data/vendored/puppet/lib/puppet/pops/serialization/json_path.rb +2 -1
  46. data/vendored/puppet/lib/puppet/pops/types/execution_result.rb +7 -4
  47. data/vendored/puppet/lib/puppet/pops/types/p_binary_type.rb +9 -2
  48. data/vendored/puppet/lib/puppet/pops/types/p_init_type.rb +1 -1
  49. data/vendored/puppet/lib/puppet/pops/types/p_meta_type.rb +4 -0
  50. data/vendored/puppet/lib/puppet/pops/types/p_object_type.rb +81 -4
  51. data/vendored/puppet/lib/puppet/pops/types/p_object_type_extension.rb +213 -0
  52. data/vendored/puppet/lib/puppet/pops/types/p_sem_ver_type.rb +10 -2
  53. data/vendored/puppet/lib/puppet/pops/types/puppet_object.rb +11 -1
  54. data/vendored/puppet/lib/puppet/pops/types/type_calculator.rb +2 -2
  55. data/vendored/puppet/lib/puppet/pops/types/type_factory.rb +16 -6
  56. data/vendored/puppet/lib/puppet/pops/types/type_formatter.rb +22 -14
  57. data/vendored/puppet/lib/puppet/pops/types/type_parser.rb +17 -15
  58. data/vendored/puppet/lib/puppet/pops/types/types.rb +181 -72
  59. data/vendored/puppet/lib/puppet/provider.rb +18 -8
  60. data/vendored/puppet/lib/puppet/provider/package/yum.rb +22 -7
  61. data/vendored/puppet/lib/puppet/provider/service/base.rb +21 -8
  62. data/vendored/puppet/lib/puppet/provider/service/launchd.rb +2 -3
  63. data/vendored/puppet/lib/puppet/provider/user/aix.rb +1 -0
  64. data/vendored/puppet/lib/puppet/provider/user/user_role_add.rb +7 -1
  65. data/vendored/puppet/lib/puppet/provider/user/useradd.rb +3 -2
  66. data/vendored/puppet/lib/puppet/provider/zfs/zfs.rb +5 -1
  67. data/vendored/puppet/lib/puppet/type/exec.rb +5 -4
  68. data/vendored/puppet/lib/puppet/type/macauthorization.rb +1 -1
  69. data/vendored/puppet/lib/puppet/type/user.rb +19 -0
  70. data/vendored/puppet/lib/puppet/util/log/destinations.rb +10 -0
  71. data/vendored/puppet/lib/puppet/util/windows/file.rb +35 -4
  72. data/vendored/puppet/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet.rb +1 -1
  73. data/vendored/puppet/lib/puppet/version.rb +1 -1
  74. data/vendored/puppet/lib/puppet_pal.rb +15 -5
  75. metadata +8 -3
  76. data/vendored/puppet/lib/puppet/pops/types/p_error_type.rb +0 -158
@@ -42,6 +42,15 @@ module Pcore
42
42
  if Puppet[:tasks]
43
43
  require_relative 'types/task'
44
44
  require_relative 'types/execution_result'
45
+
46
+ add_object_type('Target', <<-PUPPET, loader)
47
+ {
48
+ attributes => {
49
+ host => String[1],
50
+ options => { type => Hash[String[1], Data], value => {} }
51
+ }
52
+ }
53
+ PUPPET
45
54
  end
46
55
  Types::TypedModelObject.register_ptypes(loader, ir)
47
56
 
@@ -1,5 +1,57 @@
1
1
  module Puppet::Pops
2
2
  module Serialization
3
+ class Builder
4
+ def initialize(values)
5
+ @values = values
6
+ @resolved = true
7
+ end
8
+
9
+ def [](key)
10
+ @values[key]
11
+ end
12
+
13
+ def []=(key, value)
14
+ @values[key] = value
15
+ @resolved = false if value.is_a?(Builder)
16
+ end
17
+
18
+ def resolve
19
+ unless @resolved
20
+ @resolved = true
21
+ if @values.is_a?(Array)
22
+ @values.each_with_index { |v, idx| @values[idx] = v.resolve if v.is_a?(Builder) }
23
+ elsif @values.is_a?(Hash)
24
+ @values.each_pair { |k, v| @values[k] = v.resolve if v.is_a?(Builder) }
25
+ end
26
+ end
27
+ @values
28
+ end
29
+ end
30
+
31
+ class ObjectHashBuilder < Builder
32
+ def initialize(instance)
33
+ super({})
34
+ @instance = instance
35
+ end
36
+
37
+ def resolve
38
+ @instance._pcore_init_from_hash(super)
39
+ @instance
40
+ end
41
+ end
42
+
43
+ class ObjectArrayBuilder < Builder
44
+ def initialize(instance)
45
+ super({})
46
+ @instance = instance
47
+ end
48
+
49
+ def resolve
50
+ @instance.send(:initialize, *super.values)
51
+ @instance
52
+ end
53
+ end
54
+
3
55
  # Class that can process the `Data` produced by the {ToDataConverter} class and reassemble
4
56
  # the objects that were converted.
5
57
  #
@@ -137,9 +189,16 @@ module Serialization
137
189
  end
138
190
 
139
191
  def build(value, &block)
140
- @current[@key] = value unless @current.nil?
141
- with_value(value, &block) if block_given?
142
- value
192
+ vx = Builder.new(value)
193
+ @current[@key] = vx unless @current.nil?
194
+ with_value(vx, &block) if block_given?
195
+ vx.resolve
196
+ end
197
+
198
+ def build_object(builder, &block)
199
+ @current[@key] = builder unless @current.nil?
200
+ with_value(builder, &block) if block_given?
201
+ builder.resolve
143
202
  end
144
203
 
145
204
  def pcore_type_hash_to_value(pcore_type, value)
@@ -148,14 +207,9 @@ module Serialization
148
207
  if value.empty?
149
208
  build(pcore_type.create)
150
209
  elsif pcore_type.implementation_class.respond_to?(:_pcore_init_from_hash)
151
- build(pcore_type.allocate) do
152
- @current._pcore_init_from_hash(with_value({}) { value.each_pair { |key, elem| with(key) { convert(elem) } } })
153
- end
210
+ build_object(ObjectHashBuilder.new(pcore_type.allocate)) { value.each_pair { |key, elem| with(key) { convert(elem) } } }
154
211
  else
155
- build(pcore_type.allocate) do
156
- args = with_value([]) { value.values.each_with_index { |elem, idx| with(idx) { convert(elem) }}}
157
- @current.send(:initialize, *args)
158
- end
212
+ build_object(ObjectArrayBuilder.new(pcore_type.allocate)) { value.each_pair { |key, elem| with(key) { convert(elem) } } }
159
213
  end
160
214
  elsif value.is_a?(String)
161
215
  build(pcore_type.create(value))
@@ -47,7 +47,8 @@ module JsonPath
47
47
  #
48
48
  def resolve(context, path)
49
49
  factory = @parser.parse_string(path)
50
- resolve_any(factory.model.body, context, path)
50
+ v = resolve_any(factory.model.body, context, path)
51
+ v.is_a?(Builder) ? v.resolve : v
51
52
  end
52
53
 
53
54
  def resolve_any(ast, context, path)
@@ -62,7 +62,8 @@ module Types
62
62
 
63
63
  def error_nodes
64
64
  result = {}
65
- @result_hash.each_pair { |k, v| result[k] = v if v.is_a?(PErrorType::Error) }
65
+ t = TypeFactory.error
66
+ @result_hash.each_pair { |k, v| result[k] = v if t.instance?(v) }
66
67
  self.class.new(result)
67
68
  end
68
69
 
@@ -75,13 +76,15 @@ module Types
75
76
  end
76
77
 
77
78
  def ok
78
- !@result_hash.values.any? { |v| v.is_a?(PErrorType::Error) }
79
+ t = TypeFactory.error
80
+ !@result_hash.values.any? { |v| t.instance?(v) }
79
81
  end
80
82
  alias_method :ok?, :ok
81
83
 
82
84
  def ok_nodes
83
85
  result = {}
84
- @result_hash.each_pair { |k, v| result[k] = v unless v.is_a?(PErrorType::Error) }
86
+ t = TypeFactory.error
87
+ @result_hash.each_pair { |k, v| result[k] = v unless t.instance?(v) }
85
88
  self.class.new(result)
86
89
  end
87
90
 
@@ -116,7 +119,7 @@ module Types
116
119
  if error.nil?
117
120
  value
118
121
  else
119
- PErrorType::Error.new(error['msg'], error['kind'], error['issue_code'] || PErrorType::DEFAULT_ISSUE_CODE, value, error['details'])
122
+ TypeFactory.error.create(error['msg'], error['kind'], error['issue_code'], value, error['details'])
120
123
  end
121
124
  end
122
125
 
@@ -2,8 +2,15 @@ require 'base64'
2
2
  module Puppet::Pops
3
3
  module Types
4
4
 
5
- # A Puppet Language Type that exposes the {{SemanticPuppet::Version}} and {{SemanticPuppet::VersionRange}}.
6
- # The version type is parameterized with version ranges.
5
+ # A Puppet Language Type that represents binary data content (a sequence of 8-bit bytes).
6
+ # Instances of this data type can be created from `String` and `Array[Integer[0,255]]`
7
+ # values. Also see the `binary_file` function for reading binary content from a file.
8
+ #
9
+ # A `Binary` can be converted to `String` and `Array` form - see function `new` for
10
+ # the respective target data type for more information.
11
+ #
12
+ # Instances of this data type serialize as base 64 encoded strings when the serialization
13
+ # format is textual, and as binary content when a serialization format supports this.
7
14
  #
8
15
  # @api public
9
16
  class PBinaryType < PAnyType
@@ -156,7 +156,7 @@ class PInitType < PTypeWithContainedType
156
156
  rescue ArgumentError
157
157
  raise ArgumentError, _("Creation of new instance of type '%{type_name}' is not supported") % { type_name: @type.to_s }
158
158
  end
159
- param_tuples = new_func.dispatcher.dispatchers.map { |closure| closure.type.param_types }
159
+ param_tuples = new_func.dispatcher.signatures.map { |closure| closure.type.param_types }
160
160
 
161
161
  # An instance of the contained type is always a match to this type.
162
162
  single_types = [@type]
@@ -78,6 +78,10 @@ class PMetaType < PAnyType
78
78
  end
79
79
  end
80
80
 
81
+ def resolved?
82
+ @init_hash_expression.nil?
83
+ end
84
+
81
85
  # Returns the expanded string the form of the alias, e.g. <alias name> = <resolved type>
82
86
  #
83
87
  # @return [String] the expanded form of this alias
@@ -13,6 +13,7 @@ KEY_FUNCTIONS = 'functions'.freeze
13
13
  KEY_KIND = 'kind'.freeze
14
14
  KEY_OVERRIDE = 'override'.freeze
15
15
  KEY_PARENT = 'parent'.freeze
16
+ KEY_TYPE_PARAMETERS = 'type_parameters'.freeze
16
17
 
17
18
  # @api public
18
19
  class PObjectType < PMetaType
@@ -34,8 +35,14 @@ class PObjectType < PMetaType
34
35
  TypeFactory.optional(KEY_ANNOTATIONS) => TYPE_ANNOTATIONS
35
36
  })
36
37
 
38
+ TYPE_PARAMETER = TypeFactory.struct({
39
+ KEY_TYPE => PTypeType::DEFAULT,
40
+ TypeFactory.optional(KEY_ANNOTATIONS) => TYPE_ANNOTATIONS
41
+ })
42
+
37
43
  TYPE_CONSTANTS = TypeFactory.hash_kv(Pcore::TYPE_MEMBER_NAME, PAnyType::DEFAULT)
38
44
  TYPE_ATTRIBUTES = TypeFactory.hash_kv(Pcore::TYPE_MEMBER_NAME, TypeFactory.not_undef)
45
+ TYPE_PARAMETERS = TypeFactory.hash_kv(Pcore::TYPE_MEMBER_NAME, TypeFactory.not_undef)
39
46
  TYPE_ATTRIBUTE_CALLABLE = TypeFactory.callable(0,0)
40
47
 
41
48
  TYPE_FUNCTION_TYPE = PTypeType.new(PCallableType::DEFAULT)
@@ -55,6 +62,7 @@ class PObjectType < PMetaType
55
62
  TYPE_OBJECT_I12N = TypeFactory.struct({
56
63
  TypeFactory.optional(KEY_NAME) => TYPE_OBJECT_NAME,
57
64
  TypeFactory.optional(KEY_PARENT) => PTypeType::DEFAULT,
65
+ TypeFactory.optional(KEY_TYPE_PARAMETERS) => TYPE_PARAMETERS,
58
66
  TypeFactory.optional(KEY_ATTRIBUTES) => TYPE_ATTRIBUTES,
59
67
  TypeFactory.optional(KEY_CONSTANTS) => TYPE_CONSTANTS,
60
68
  TypeFactory.optional(KEY_FUNCTIONS) => TYPE_FUNCTIONS,
@@ -335,6 +343,22 @@ class PObjectType < PMetaType
335
343
  end
336
344
  end
337
345
 
346
+ class PTypeParameter < PAttribute
347
+ # @return [Hash{String=>Object}] the hash
348
+ # @api private
349
+ def _pcore_init_hash
350
+ hash = super
351
+ hash[KEY_TYPE] = hash[KEY_TYPE].type
352
+ hash.delete(KEY_VALUE) if hash.include?(KEY_VALUE) && hash[KEY_VALUE].nil?
353
+ hash
354
+ end
355
+
356
+ # @api private
357
+ def self.feature_type
358
+ 'type_parameter'
359
+ end
360
+ end
361
+
338
362
  # Describes a named Function in an Object type
339
363
  # @api public
340
364
  class PFunction < PAnnotatedMember
@@ -359,8 +383,6 @@ class PObjectType < PMetaType
359
383
 
360
384
  attr_reader :name
361
385
  attr_reader :parent
362
- attr_reader :attributes
363
- attr_reader :functions
364
386
  attr_reader :equality
365
387
  attr_reader :checks
366
388
  attr_reader :annotations
@@ -387,6 +409,7 @@ class PObjectType < PMetaType
387
409
  _pcore_init_from_hash(_pcore_init_hash)
388
410
  @loader = init_hash_expression unless init_hash_expression.nil?
389
411
  else
412
+ @type_parameters = EMPTY_HASH
390
413
  @attributes = EMPTY_HASH
391
414
  @functions = EMPTY_HASH
392
415
  @name = TypeAsserter.assert_instance_of('object name', TYPE_OBJECT_NAME, _pcore_init_hash)
@@ -595,6 +618,7 @@ class PObjectType < PMetaType
595
618
  # @api private
596
619
  def _pcore_init_from_hash(init_hash)
597
620
  TypeAsserter.assert_instance_of('object initializer', TYPE_OBJECT_I12N, init_hash)
621
+ @type_parameters = EMPTY_HASH
598
622
  @attributes = EMPTY_HASH
599
623
  @functions = EMPTY_HASH
600
624
 
@@ -605,6 +629,7 @@ class PObjectType < PMetaType
605
629
  @parent = init_hash[KEY_PARENT]
606
630
 
607
631
  parent_members = EMPTY_HASH
632
+ parent_type_params = EMPTY_HASH
608
633
  parent_object_type = nil
609
634
  unless @parent.nil?
610
635
  check_self_recursion(self)
@@ -613,6 +638,24 @@ class PObjectType < PMetaType
613
638
  if rp.is_a?(PObjectType)
614
639
  parent_object_type = rp
615
640
  parent_members = rp.members(true)
641
+ parent_type_params = rp.type_parameters(true)
642
+ end
643
+ end
644
+
645
+ type_parameters = init_hash[KEY_TYPE_PARAMETERS]
646
+ unless type_parameters.nil? || type_parameters.empty?
647
+ @type_parameters = {}
648
+ type_parameters.each do |key, param_spec|
649
+ param_value = :undef
650
+ if param_spec.is_a?(Hash)
651
+ param_type = param_spec[KEY_TYPE]
652
+ param_value = param_spec[KEY_VALUE] if param_spec.include?(KEY_VALUE)
653
+ else
654
+ param_type = TypeAsserter.assert_instance_of(nil, PTypeType::DEFAULT, param_spec) { "type_parameter #{label}[#{key}]" }
655
+ end
656
+ param_type = POptionalType.new(param_type) unless param_type.is_a?(POptionalType)
657
+ type_param = PTypeParameter.new(key, self, KEY_TYPE => param_type, KEY_VALUE => param_value).assert_override(parent_type_params)
658
+ @type_parameters[key] = type_param
616
659
  end
617
660
  end
618
661
 
@@ -634,7 +677,7 @@ class PObjectType < PMetaType
634
677
  KEY_KIND => ATTRIBUTE_KIND_CONSTANT
635
678
  }
636
679
  # Indicate override if parent member exists. Type check etc. will take place later on.
637
- attr_spec[KEY_OVERRIDE] = true if parent_members.include?(key)
680
+ attr_spec[KEY_OVERRIDE] = parent_members.include?(key)
638
681
  attr_specs[key] = attr_spec
639
682
  end
640
683
  end
@@ -715,6 +758,7 @@ class PObjectType < PMetaType
715
758
  guarded_recursion(guard, nil) do |g|
716
759
  super(visitor, g)
717
760
  @parent.accept(visitor, g) unless parent.nil?
761
+ @type_parameters.values.each { |p| p.accept(visitor, g) }
718
762
  @attributes.values.each { |a| a.accept(visitor, g) }
719
763
  @functions.values.each { |f| f.accept(visitor, g) }
720
764
  end
@@ -771,6 +815,7 @@ class PObjectType < PMetaType
771
815
  result = super()
772
816
  result[KEY_NAME] = @name if include_name && !@name.nil?
773
817
  result[KEY_PARENT] = @parent unless @parent.nil?
818
+ result[KEY_TYPE_PARAMETERS] = compressed_members_hash(@type_parameters) unless @type_parameters.empty?
774
819
  unless @attributes.empty?
775
820
  # Divide attributes into constants and others
776
821
  tc = TypeCalculator.singleton
@@ -795,6 +840,7 @@ class PObjectType < PMetaType
795
840
  self.class == o.class &&
796
841
  @name == o.name &&
797
842
  @parent == o.parent &&
843
+ @type_parameters == o.type_parameters &&
798
844
  @attributes == o.attributes &&
799
845
  @functions == o.functions &&
800
846
  @equality == o.equality &&
@@ -802,7 +848,7 @@ class PObjectType < PMetaType
802
848
  end
803
849
 
804
850
  def hash
805
- @name.nil? ? [@parent, @attributes, @functions].hash : @name.hash
851
+ @name.nil? ? [@parent, @type_parameters, @attributes, @functions].hash : @name.hash
806
852
  end
807
853
 
808
854
  def kind_of_callable?(optional=true, guard = nil)
@@ -817,6 +863,14 @@ class PObjectType < PMetaType
817
863
  @parent.nil? ? false : @parent.iterable_type(guard)
818
864
  end
819
865
 
866
+ def parameterized?
867
+ if @type_parameters.empty?
868
+ @parent.is_a?(PObjectType) ? @parent.parameterized? : false
869
+ else
870
+ true
871
+ end
872
+ end
873
+
820
874
  # Returns the members (attributes and functions) of this `Object` type. If _include_parent_ is `true`, then all
821
875
  # inherited members will be included in the returned `Hash`.
822
876
  #
@@ -891,6 +945,18 @@ class PObjectType < PMetaType
891
945
  label.split(DOUBLE_COLON).last
892
946
  end
893
947
 
948
+ # Returns the type_parameters of this `Object` type. If _include_parent_ is `true`, then all
949
+ # inherited type_parameters will be included in the returned `Hash`.
950
+ #
951
+ # @param include_parent [Boolean] `true` if inherited type_parameters should be included
952
+ # @return [Hash{String=>PTypeParameter}] a hash with the type_parameters
953
+ # @api public
954
+ def type_parameters(include_parent = false)
955
+ all = {}
956
+ collect_type_parameters(all, include_parent)
957
+ all
958
+ end
959
+
894
960
  protected
895
961
 
896
962
  # An Object type is only assignable from another Object type. The other type
@@ -903,6 +969,8 @@ class PObjectType < PMetaType
903
969
  op = o.parent
904
970
  op.nil? ? false : assignable?(op, guard)
905
971
  end
972
+ elsif o.is_a?(PObjectTypeExtension)
973
+ assignable?(o.base_type, guard)
906
974
  else
907
975
  false
908
976
  end
@@ -936,6 +1004,15 @@ class PObjectType < PMetaType
936
1004
  nil
937
1005
  end
938
1006
 
1007
+ def collect_type_parameters(collector, include_parent)
1008
+ if include_parent
1009
+ parent = resolved_parent
1010
+ parent.collect_type_parameters(collector, include_parent) if parent.is_a?(PObjectType)
1011
+ end
1012
+ collector.merge!(@type_parameters)
1013
+ nil
1014
+ end
1015
+
939
1016
  private
940
1017
 
941
1018
  def compressed_members_hash(features)
@@ -0,0 +1,213 @@
1
+ module Puppet::Pops
2
+ module Types
3
+
4
+ # Base class for Parameterized Object implementations. The wrapper impersonates the base
5
+ # object and extends it with methods to filter assignable types and instances based on parameter
6
+ # values.
7
+ #
8
+ # @api public
9
+ class PObjectTypeExtension < PAnyType
10
+ def self.register_ptype(loader, ir)
11
+ create_ptype(loader, ir, 'AnyType',
12
+ 'base_type' => {
13
+ KEY_TYPE => PTypeType::DEFAULT
14
+ },
15
+ 'init_parameters' => {
16
+ KEY_TYPE => PArrayType::DEFAULT
17
+ }
18
+ )
19
+ end
20
+
21
+ attr_reader :base_type, :parameters
22
+
23
+ # @api private
24
+ def self.create(base_type, init_parameters)
25
+ impl_class = Loaders.implementation_registry.module_for_type("#{base_type.name}TypeExtension") || self
26
+ impl_class.new(base_type, init_parameters)
27
+ end
28
+
29
+ # @api private
30
+ def initialize(base_type, init_parameters)
31
+ pts = base_type.type_parameters(true)
32
+ raise Puppet::ParseError, _('The %{label}-Type cannot be parameterized using []') % { label: base_type.label } if pts.empty?
33
+ @base_type = base_type
34
+
35
+ named_args = false
36
+ if init_parameters.is_a?(PuppetObject)
37
+ init_parameters = parameters_from_instance(init_parameters, pts)
38
+ else
39
+ named_args = init_parameters.size == 1 && init_parameters[0].is_a?(Hash)
40
+ if named_args
41
+ # Catch case when first parameter is an assignable Hash
42
+ named_args = pts.size >= 1 && !pts.values[0].type.instance?(init_parameters[0])
43
+ end
44
+ end
45
+
46
+ by_name = {}
47
+ if named_args
48
+ hash = init_parameters[0]
49
+ hash.each_pair do |pn, pv|
50
+ tp = pts[pn]
51
+ if tp.nil?
52
+ raise Puppet::ParseError, _("'%{pn}' is not a known type parameter for %{label}-Type") % { pn: pn, label: base_type.label }
53
+ end
54
+ by_name[pn] = check_param(tp, pv) unless pv == :default
55
+ end
56
+ else
57
+ pts.values.each_with_index do |tp, idx|
58
+ if idx < init_parameters.size
59
+ pv = init_parameters[idx]
60
+ by_name[tp.name] = check_param(tp, pv) unless pv == :default
61
+ end
62
+ end
63
+ end
64
+ if by_name.empty?
65
+ raise Puppet::ParseError, _('The %{label}-Type cannot be parameterized using an empty parameter list') % { label: base_type.label }
66
+ end
67
+ @parameters = by_name
68
+ end
69
+
70
+ def check_param(type_param, v)
71
+ TypeAsserter.assert_instance_of(nil, type_param.type, v) { type_param.label }
72
+ end
73
+
74
+ # Return the parameter values as positional arguments with unset values as :default. The
75
+ # array is stripped from trailing :default values
76
+ # @return [Array] the parameter values
77
+ # @api private
78
+ def init_parameters
79
+ pts = @base_type.type_parameters(true)
80
+ if pts.size > 2
81
+ @parameters
82
+ else
83
+ result = pts.values.map do |tp|
84
+ pn = tp.name
85
+ @parameters.include?(pn) ? @parameters[pn] : :default
86
+ end
87
+ # Remove trailing defaults
88
+ result.pop while result.last == :default
89
+ result
90
+ end
91
+ end
92
+
93
+ # @api private
94
+ def eql?(o)
95
+ super(o) && @base_type.eql?(o.base_type) && @parameters.eql?(o.parameters)
96
+ end
97
+
98
+ # @api private
99
+ def generalize
100
+ @base_type
101
+ end
102
+
103
+ # @api private
104
+ def hash
105
+ @base_type.hash ^ @parameters.hash
106
+ end
107
+
108
+ # @api private
109
+ def loader
110
+ @base_type.loader
111
+ end
112
+
113
+ # @api private
114
+ def check_self_recursion(originator)
115
+ @base_type.check_self_recursion(originator)
116
+ end
117
+
118
+ # @api private
119
+ def create(*args)
120
+ @base_type.create(*args)
121
+ end
122
+
123
+ # @api private
124
+ def instance?(o, guard = nil)
125
+ @base_type.instance?(o, guard) && test_instance?(o, guard)
126
+ end
127
+
128
+ # @api private
129
+ def new_function
130
+ @base_type.new_function
131
+ end
132
+
133
+ # @api private
134
+ def simple_name
135
+ @base_type.simple_name
136
+ end
137
+
138
+ protected
139
+
140
+ # Creates an array of type parameters from the attributes that matches the
141
+ # type parameters by name. Type parameters for which there is no matching attribute
142
+ # will have `nil` in their corresponding position on the array.
143
+ #
144
+ # @return [Array] array of values from instance that maps to type parameters
145
+ def parameters_from_instance(instance, type_parameters)
146
+ attrs = @base_type.attributes(true)
147
+ type_parameters.keys.map do |pn|
148
+ attr = attrs[pn]
149
+ attr.nil? ? nil : instance.send(pn)
150
+ end
151
+ end
152
+
153
+ # Checks that the given `param_values` hash contains all keys present in the `parameters` of
154
+ # this instance and that each keyed value is a match for the given parameter. The match is done
155
+ # using case expression semantics.
156
+ #
157
+ # This method is only called when a given type is found to be assignable to the base type of
158
+ # this extension.
159
+ #
160
+ # @param param_values[Hash] the parameter values of the assignable type
161
+ # @param guard[RecursionGuard] guard against endless recursion
162
+ # @return [Boolean] true or false to indicate assignability
163
+ # @api public
164
+ def test_assignable?(param_values, guard)
165
+ # Default implementation performs case expression style matching of all parameter values
166
+ # provided that the value exist (this should always be the case, since all defaults have
167
+ # been assigned at this point)
168
+ eval = Parser::EvaluatingParser.singleton.evaluator
169
+ @parameters.keys.all? do |pn|
170
+ if param_values.include?(pn)
171
+ a = param_values[pn]
172
+ b = @parameters[pn]
173
+ eval.match?(a, b) || a.is_a?(PAnyType) && b.is_a?(PAnyType) && b.assignable?(a)
174
+ else
175
+ false
176
+ end
177
+ end
178
+ end
179
+
180
+ # Checks that the given instance `o` has one attribute for each key present in the `parameters` of
181
+ # this instance and that each attribute value is a match for the given parameter. The match is done
182
+ # using case expression semantics.
183
+ #
184
+ # This method is only called when the given value is found to be an instance of the base type of
185
+ # this extension.
186
+ #
187
+ # @param o [Object] the instance to test
188
+ # @param guard[RecursionGuard] guard against endless recursion
189
+ # @return [Boolean] true or false to indicate if the value is an instance or not
190
+ # @api public
191
+ def test_instance?(o, guard)
192
+ eval = Parser::EvaluatingParser.singleton.evaluator
193
+ @parameters.keys.all? do |pn|
194
+ begin
195
+ m = o.public_method(pn)
196
+ m.arity == 0 ? eval.match?(m.call, @parameters[pn]) : false
197
+ rescue NameError
198
+ false
199
+ end
200
+ end
201
+ end
202
+
203
+ # @api private
204
+ def _assignable?(o, guard = nil)
205
+ if o.is_a?(PObjectTypeExtension)
206
+ @base_type.assignable?(o.base_type, guard) && test_assignable?(o.parameters, guard)
207
+ else
208
+ @base_type.assignable?(o, guard) && test_assignable?(EMPTY_HASH, guard)
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end