puppet 4.4.2-x86-mingw32 → 4.5.0-x86-mingw32

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.

Files changed (218) hide show
  1. data/CONTRIBUTING.md +5 -5
  2. data/Gemfile +2 -2
  3. data/LICENSE +2 -2
  4. data/README.md +5 -0
  5. data/ext/project_data.yaml +2 -0
  6. data/lib/hiera_puppet.rb +6 -14
  7. data/lib/puppet/application/agent.rb +2 -3
  8. data/lib/puppet/data_providers/hiera_config.rb +2 -4
  9. data/lib/puppet/data_providers/hiera_interpolate.rb +12 -154
  10. data/lib/puppet/data_providers/json_data_provider_factory.rb +0 -7
  11. data/lib/puppet/data_providers/yaml_data_provider_factory.rb +2 -8
  12. data/lib/puppet/defaults.rb +70 -7
  13. data/lib/puppet/functions.rb +69 -0
  14. data/lib/puppet/functions/dig.rb +39 -0
  15. data/lib/puppet/functions/lest.rb +53 -0
  16. data/lib/puppet/functions/lookup.rb +40 -27
  17. data/lib/puppet/functions/new.rb +502 -0
  18. data/lib/puppet/functions/regsubst.rb +11 -10
  19. data/lib/puppet/functions/then.rb +74 -0
  20. data/lib/puppet/functions/type.rb +4 -4
  21. data/lib/puppet/functions/with.rb +1 -1
  22. data/lib/puppet/indirector/catalog/compiler.rb +2 -0
  23. data/lib/puppet/indirector/resource_type/parser.rb +5 -0
  24. data/lib/puppet/indirector/rest.rb +5 -1
  25. data/lib/puppet/loaders.rb +2 -0
  26. data/lib/puppet/metatype/manager.rb +19 -2
  27. data/lib/puppet/module_tool/applications/application.rb +1 -1
  28. data/lib/puppet/module_tool/skeleton/templates/generator/Gemfile +6 -2
  29. data/lib/puppet/module_tool/skeleton/templates/generator/Rakefile +19 -4
  30. data/lib/puppet/module_tool/skeleton/templates/generator/{tests → examples}/init.pp.erb +1 -1
  31. data/lib/puppet/module_tool/skeleton/templates/generator/spec/classes/init_spec.rb.erb +0 -1
  32. data/lib/puppet/network/http/api/master/v3/environment.rb +6 -2
  33. data/lib/puppet/parser/ast/pops_bridge.rb +20 -3
  34. data/lib/puppet/parser/compiler/catalog_validator/relationship_validator.rb +24 -2
  35. data/lib/puppet/parser/e4_parser_adapter.rb +13 -12
  36. data/lib/puppet/parser/environment_compiler.rb +2 -2
  37. data/lib/puppet/parser/resource.rb +14 -5
  38. data/lib/puppet/parser/scope.rb +18 -15
  39. data/lib/puppet/plugins/data_providers/data_provider.rb +19 -8
  40. data/lib/puppet/pops.rb +6 -0
  41. data/lib/puppet/pops/adapters.rb +5 -1
  42. data/lib/puppet/pops/evaluator/access_operator.rb +52 -14
  43. data/lib/puppet/pops/evaluator/compare_operator.rb +34 -4
  44. data/lib/puppet/pops/evaluator/evaluator_impl.rb +75 -22
  45. data/lib/puppet/pops/evaluator/literal_evaluator.rb +7 -6
  46. data/lib/puppet/pops/evaluator/runtime3_converter.rb +13 -1
  47. data/lib/puppet/pops/evaluator/runtime3_support.rb +14 -4
  48. data/lib/puppet/pops/functions/dispatcher.rb +1 -1
  49. data/lib/puppet/pops/issues.rb +18 -2
  50. data/lib/puppet/pops/loader/base_loader.rb +48 -7
  51. data/lib/puppet/pops/loader/dependency_loader.rb +27 -2
  52. data/lib/puppet/pops/loader/loader.rb +12 -0
  53. data/lib/puppet/pops/loader/predefined_loader.rb +29 -0
  54. data/lib/puppet/pops/loader/runtime3_type_loader.rb +57 -0
  55. data/lib/puppet/pops/loader/static_loader.rb +92 -5
  56. data/lib/puppet/pops/loader/type_definition_instantiator.rb +25 -3
  57. data/lib/puppet/pops/loaders.rb +84 -14
  58. data/lib/puppet/pops/lookup/explainer.rb +38 -1
  59. data/lib/puppet/pops/lookup/interpolation.rb +115 -0
  60. data/lib/puppet/pops/lookup/sub_lookup.rb +86 -0
  61. data/lib/puppet/pops/model/ast_transformer.rb +8 -1
  62. data/lib/puppet/pops/model/factory.rb +31 -8
  63. data/lib/puppet/pops/model/model.rb +8 -0
  64. data/lib/puppet/pops/model/model_label_provider.rb +1 -0
  65. data/lib/puppet/pops/model/model_meta.rb +7 -1
  66. data/lib/puppet/pops/model/model_tree_dumper.rb +4 -0
  67. data/lib/puppet/pops/parser/egrammar.ra +24 -7
  68. data/lib/puppet/pops/parser/eparser.rb +863 -798
  69. data/lib/puppet/pops/parser/evaluating_parser.rb +4 -0
  70. data/lib/puppet/pops/parser/locator.rb +8 -4
  71. data/lib/puppet/pops/pcore.rb +30 -0
  72. data/lib/puppet/pops/types/class_loader.rb +2 -4
  73. data/lib/puppet/pops/types/implementation_registry.rb +146 -0
  74. data/lib/puppet/pops/types/iterable.rb +4 -4
  75. data/lib/puppet/pops/types/p_object_type.rb +846 -0
  76. data/lib/puppet/pops/types/p_runtime_type.rb +102 -0
  77. data/lib/puppet/pops/types/p_sem_ver_range_type.rb +164 -0
  78. data/lib/puppet/pops/types/p_sem_ver_type.rb +113 -0
  79. data/lib/puppet/pops/types/puppet_object.rb +21 -0
  80. data/lib/puppet/pops/types/ruby_generator.rb +258 -0
  81. data/lib/puppet/pops/types/string_converter.rb +922 -0
  82. data/lib/puppet/pops/types/type_calculator.rb +29 -5
  83. data/lib/puppet/pops/types/type_conversion_error.rb +15 -0
  84. data/lib/puppet/pops/types/type_factory.rb +49 -16
  85. data/lib/puppet/pops/types/type_formatter.rb +335 -112
  86. data/lib/puppet/pops/types/type_mismatch_describer.rb +110 -29
  87. data/lib/puppet/pops/types/type_parser.rb +205 -197
  88. data/lib/puppet/pops/types/types.rb +481 -103
  89. data/lib/puppet/pops/validation.rb +1 -1
  90. data/lib/puppet/pops/validation/checker4_0.rb +66 -4
  91. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  92. data/lib/puppet/pops/visitor.rb +3 -1
  93. data/lib/puppet/property.rb +1 -1
  94. data/lib/puppet/provider/augeas/augeas.rb +1 -1
  95. data/lib/puppet/provider/package/pip.rb +64 -20
  96. data/lib/puppet/provider/package/rpm.rb +112 -0
  97. data/lib/puppet/provider/package/yum.rb +7 -68
  98. data/lib/puppet/provider/service/daemontools.rb +3 -3
  99. data/lib/puppet/provider/service/init.rb +4 -2
  100. data/lib/puppet/provider/service/runit.rb +3 -3
  101. data/lib/puppet/provider/service/smf.rb +6 -3
  102. data/lib/puppet/provider/service/systemd.rb +59 -73
  103. data/lib/puppet/reference/providers.rb +1 -2
  104. data/lib/puppet/resource.rb +54 -37
  105. data/lib/puppet/resource/catalog.rb +31 -29
  106. data/lib/puppet/resource/type_collection.rb +23 -8
  107. data/lib/puppet/settings.rb +4 -2
  108. data/lib/puppet/settings/base_setting.rb +9 -3
  109. data/lib/puppet/settings/symbolic_enum_setting.rb +17 -0
  110. data/lib/puppet/test/test_helper.rb +0 -1
  111. data/lib/puppet/type.rb +9 -3
  112. data/lib/puppet/type/exec.rb +17 -17
  113. data/lib/puppet/type/file.rb +12 -0
  114. data/lib/puppet/type/file/content.rb +6 -6
  115. data/lib/puppet/type/file/ensure.rb +4 -4
  116. data/lib/puppet/type/file/source.rb +4 -4
  117. data/lib/puppet/type/file/target.rb +2 -2
  118. data/lib/puppet/type/mount.rb +18 -1
  119. data/lib/puppet/type/package.rb +3 -3
  120. data/lib/puppet/type/schedule.rb +4 -4
  121. data/lib/puppet/type/service.rb +15 -0
  122. data/lib/puppet/type/sshkey.rb +5 -3
  123. data/lib/puppet/type/tidy.rb +3 -3
  124. data/lib/puppet/type/zone.rb +5 -5
  125. data/lib/puppet/util/feature.rb +1 -1
  126. data/lib/puppet/util/monkey_patches.rb +8 -0
  127. data/lib/puppet/util/network_device/cisco/device.rb +16 -6
  128. data/lib/puppet/util/network_device/cisco/interface.rb +5 -6
  129. data/lib/puppet/util/plist.rb +3 -3
  130. data/lib/puppet/version.rb +1 -1
  131. data/spec/fixtures/unit/application/environments/production/data/common.yaml +13 -0
  132. data/spec/fixtures/unit/data_providers/environments/production/modules/abc/lib/puppet/functions/abc/data.rb +2 -1
  133. data/spec/fixtures/unit/data_providers/environments/production/modules/abc/manifests/init.pp +2 -1
  134. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/data/empty_key.json +1 -0
  135. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/hiera.yaml +5 -0
  136. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/manifests/init.pp +2 -0
  137. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/metadata.json +9 -0
  138. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/data/empty_key.yaml +1 -0
  139. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/hiera.yaml +5 -0
  140. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/manifests/init.pp +2 -0
  141. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/metadata.json +9 -0
  142. data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_yaml/data/empty.yaml +1 -0
  143. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/lib/puppet/type/usee_type.rb +5 -0
  144. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/manifests/init.pp +6 -0
  145. data/spec/fixtures/unit/provider/service/smf/svcs.out +4 -3
  146. data/spec/integration/module_tool/tar/mini_spec.rb +27 -27
  147. data/spec/integration/parser/catalog_spec.rb +14 -2
  148. data/spec/integration/parser/compiler_spec.rb +94 -3
  149. data/spec/integration/parser/resource_expressions_spec.rb +1 -1
  150. data/spec/integration/resource/type_collection_spec.rb +8 -0
  151. data/spec/lib/puppet_spec/compiler.rb +11 -4
  152. data/spec/shared_contexts/types_setup.rb +4 -0
  153. data/spec/unit/application/lookup_spec.rb +91 -9
  154. data/spec/unit/appmgmt_spec.rb +44 -35
  155. data/spec/unit/capability_spec.rb +33 -53
  156. data/spec/unit/data_providers/function_data_provider_spec.rb +19 -1
  157. data/spec/unit/data_providers/hiera_data_provider_spec.rb +1 -1
  158. data/spec/unit/defaults_spec.rb +18 -0
  159. data/spec/unit/functions/assert_type_spec.rb +1 -1
  160. data/spec/unit/functions/dig_spec.rb +58 -0
  161. data/spec/unit/functions/lest_spec.rb +34 -0
  162. data/spec/unit/functions/lookup_spec.rb +108 -2
  163. data/spec/unit/functions/new_spec.rb +543 -0
  164. data/spec/unit/functions/regsubst_spec.rb +8 -0
  165. data/spec/unit/functions/then_spec.rb +40 -0
  166. data/spec/unit/functions4_spec.rb +78 -10
  167. data/spec/unit/hiera_puppet_spec.rb +49 -8
  168. data/spec/unit/indirector/resource_type/parser_spec.rb +5 -0
  169. data/spec/unit/indirector/rest_spec.rb +12 -0
  170. data/spec/unit/network/http/api/master/v3/environment_spec.rb +60 -0
  171. data/spec/unit/node/environment_spec.rb +10 -0
  172. data/spec/unit/parser/compiler_spec.rb +20 -1
  173. data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
  174. data/spec/unit/parser/functions/shared.rb +1 -1
  175. data/spec/unit/parser/resource_spec.rb +8 -1
  176. data/spec/unit/parser/scope_spec.rb +45 -0
  177. data/spec/unit/pops/evaluator/access_ops_spec.rb +14 -0
  178. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +13 -5
  179. data/spec/unit/pops/loaders/static_loader_spec.rb +92 -1
  180. data/spec/unit/{data_providers/hiera_interpolation_spec.rb → pops/lookup/interpolation_spec.rb} +7 -5
  181. data/spec/unit/pops/parser/lexer2_spec.rb +2 -9
  182. data/spec/unit/pops/parser/parse_application_spec.rb +3 -8
  183. data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +19 -0
  184. data/spec/unit/pops/parser/parse_capabilities_spec.rb +3 -10
  185. data/spec/unit/pops/parser/parse_site_spec.rb +19 -10
  186. data/spec/unit/pops/parser/parser_rspec_helper.rb +0 -4
  187. data/spec/unit/pops/types/enumeration_spec.rb +13 -12
  188. data/spec/unit/pops/types/iterable_spec.rb +2 -2
  189. data/spec/unit/pops/types/p_object_type_spec.rb +1060 -0
  190. data/spec/unit/pops/types/p_sem_ver_type_spec.rb +285 -0
  191. data/spec/unit/pops/types/recursion_guard_spec.rb +19 -17
  192. data/spec/unit/pops/types/ruby_generator_spec.rb +261 -0
  193. data/spec/unit/pops/types/string_converter_spec.rb +904 -0
  194. data/spec/unit/pops/types/type_calculator_spec.rb +430 -406
  195. data/spec/unit/pops/types/type_factory_spec.rb +119 -104
  196. data/spec/unit/pops/types/type_formatter_spec.rb +73 -6
  197. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +2 -2
  198. data/spec/unit/pops/types/type_parser_spec.rb +54 -15
  199. data/spec/unit/pops/types/types_spec.rb +113 -8
  200. data/spec/unit/pops/validator/validator_spec.rb +84 -10
  201. data/spec/unit/provider/package/pip3_spec.rb +9 -270
  202. data/spec/unit/provider/package/pip_spec.rb +85 -30
  203. data/spec/unit/provider/package/rpm_spec.rb +160 -3
  204. data/spec/unit/provider/package/yum_spec.rb +23 -134
  205. data/spec/unit/provider/service/smf_spec.rb +14 -2
  206. data/spec/unit/provider/service/systemd_spec.rb +33 -41
  207. data/spec/unit/resource/capability_finder_spec.rb +10 -2
  208. data/spec/unit/settings/file_setting_spec.rb +6 -0
  209. data/spec/unit/transaction/additional_resource_generator_spec.rb +80 -65
  210. data/spec/unit/type/mount_spec.rb +51 -10
  211. data/spec/unit/type/service_spec.rb +16 -0
  212. data/spec/unit/type_spec.rb +14 -0
  213. data/spec/unit/util/feature_spec.rb +1 -1
  214. data/spec/unit/util/monkey_patches_spec.rb +60 -0
  215. data/spec/unit/util/network_device/cisco/device_spec.rb +1 -1
  216. metadata +63 -11
  217. data/lib/puppet/pops/types/types_meta.rb +0 -0
  218. data/spec/integration/provider/package_spec.rb +0 -35
@@ -312,6 +312,8 @@ class TypeCalculator
312
312
  infer_set_Array(o)
313
313
  when Hash
314
314
  infer_set_Hash(o)
315
+ when Semantic::Version
316
+ infer_set_Version(o)
315
317
  else
316
318
  infer_set_Object(o)
317
319
  end
@@ -429,7 +431,7 @@ class TypeCalculator
429
431
 
430
432
  if t1.is_a?(PVariantType) && t2.is_a?(PVariantType)
431
433
  # The common type is one that complies with either set
432
- return PVariantType.new(t1.types | t2.types)
434
+ return PVariantType.maybe_create(t1.types | t2.types)
433
435
  end
434
436
 
435
437
  if t1.is_a?(PRegexpType) && t2.is_a?(PRegexpType)
@@ -552,7 +554,14 @@ class TypeCalculator
552
554
 
553
555
  # @api private
554
556
  def infer_Object(o)
555
- PRuntimeType.new(:ruby, o.class.name)
557
+ if o.is_a?(PuppetObject)
558
+ o._ptype
559
+ else
560
+ name = o.class.name
561
+ ir = Loaders.implementation_registry
562
+ type = ir.nil? ? nil : ir.type_for_module(name)
563
+ type.nil? ? PRuntimeType.new(:ruby, name) : type
564
+ end
556
565
  end
557
566
 
558
567
  # The type of all types is PType
@@ -652,7 +661,7 @@ class TypeCalculator
652
661
  # A mapping must be made to empty string. A nil value will result in an error later
653
662
  title = o.title
654
663
  title = '' if :undef == title
655
- PType.new(PResourceType.new(o.type.to_s.downcase, title))
664
+ PType.new(PResourceType.new(o.type.to_s, title))
656
665
  end
657
666
 
658
667
  # @api private
@@ -664,6 +673,16 @@ class TypeCalculator
664
673
  end
665
674
  end
666
675
 
676
+ # @api private
677
+ def infer_Version(o)
678
+ PSemVerType::DEFAULT
679
+ end
680
+
681
+ # @api private
682
+ def infer_VersionRange(o)
683
+ PSemVerRangeType::DEFAULT
684
+ end
685
+
667
686
  # @api private
668
687
  def infer_Hash(o)
669
688
  if o.empty?
@@ -699,12 +718,17 @@ class TypeCalculator
699
718
  elsif o.keys.all? {|k| PStringType::NON_EMPTY.instance?(k) }
700
719
  PStructType.new(o.each_pair.map { |k,v| PStructElement.new(PStringType.new(size_as_type(k), [k]), infer_set(v)) })
701
720
  else
702
- ktype = PVariantType.new(o.keys.map {|k| infer_set(k) })
703
- etype = PVariantType.new(o.values.map {|e| infer_set(e) })
721
+ ktype = PVariantType.maybe_create(o.keys.map {|k| infer_set(k) })
722
+ etype = PVariantType.maybe_create(o.values.map {|e| infer_set(e) })
704
723
  PHashType.new(unwrap_single_variant(ktype), unwrap_single_variant(etype), size_as_type(o))
705
724
  end
706
725
  end
707
726
 
727
+ # @api private
728
+ def infer_set_Version(o)
729
+ PSemVerType.new(Semantic::VersionRange.new(o, o))
730
+ end
731
+
708
732
  def unwrap_single_variant(possible_variant)
709
733
  if possible_variant.is_a?(PVariantType) && possible_variant.types.size == 1
710
734
  possible_variant.types[0]
@@ -0,0 +1,15 @@
1
+
2
+ module Puppet::Pops::Types
3
+ # Raised when a conversion of a value to another type failed.
4
+ #
5
+ class TypeConversionError < Puppet::Error
6
+
7
+ # Creates a new instance with a given message
8
+ #
9
+ # @param message [String] The error message describing what failed
10
+ #
11
+ def initialize(message)
12
+ super(message)
13
+ end
14
+ end
15
+ end
@@ -99,7 +99,7 @@ module TypeFactory
99
99
  # @api public
100
100
  #
101
101
  def self.variant(*types)
102
- PVariantType.new(types.map {|v| type_of(v) })
102
+ PVariantType.maybe_create(types.map {|v| type_of(v) })
103
103
  end
104
104
 
105
105
  # Produces the Struct type, either a non parameterized instance representing
@@ -110,7 +110,7 @@ module TypeFactory
110
110
  # The value can be a ruby class, a String (interpreted as the name of a ruby class) or
111
111
  # a Type.
112
112
  #
113
- # @param hash [Hash<Object, Object>] key => value hash
113
+ # @param hash [{String,PAnyType=>PAnyType}] key => value hash
114
114
  # @return [PStructType] the created Struct type
115
115
  #
116
116
  def self.struct(hash = {})
@@ -148,6 +148,15 @@ module TypeFactory
148
148
  PStructType.new(elements)
149
149
  end
150
150
 
151
+ # Produces an `Object` type from the given _hash_ that represents the features of the object
152
+ #
153
+ # @param hash [{String=>Object}] the hash of feature groups
154
+ # @return [PObjectType] the created type
155
+ #
156
+ def self.object(hash = nil)
157
+ hash.nil? || hash.empty? ? PObjectType::DEFAULT : PObjectType.new(hash)
158
+ end
159
+
151
160
  def self.tuple(types = [], size_type = nil)
152
161
  PTupleType.new(types.map {|elem| type_of(elem) }, size_type)
153
162
  end
@@ -295,21 +304,35 @@ module TypeFactory
295
304
  PCatalogEntryType::DEFAULT
296
305
  end
297
306
 
307
+ # Produces an instance of the SemVerRange type
308
+ def self.sem_ver_range
309
+ PSemVerRangeType::DEFAULT
310
+ end
311
+
312
+ # Produces an instance of the SemVer type
313
+ def self.sem_ver(*ranges)
314
+ ranges.empty? ? PSemVerType::DEFAULT : PSemVerType::new(*ranges)
315
+ end
316
+
298
317
  # Produces a PResourceType with a String type_name A PResourceType with a nil
299
318
  # or empty name is compatible with any other PResourceType. A PResourceType
300
319
  # with a given name is only compatible with a PResourceType with the same
301
320
  # name. (There is no resource-type subtyping in Puppet (yet)).
302
321
  #
303
322
  def self.resource(type_name = nil, title = nil)
304
- type_name = type_name.type_name if type_name.is_a?(PResourceType)
305
- type_name = type_name.downcase unless type_name.nil?
306
- unless type_name.nil? || type_name =~ Patterns::CLASSREF
307
- raise ArgumentError, "Illegal type name '#{type.type_name}'"
308
- end
309
- if type_name.nil? && !title.nil?
310
- raise ArgumentError, 'The type name cannot be nil, if title is given'
323
+ case type_name
324
+ when PResourceType
325
+ PResourceType.new(type_name.type_name, title)
326
+ when String
327
+ type_name = TypeFormatter.singleton.capitalize_segments(type_name)
328
+ raise ArgumentError, "Illegal type name '#{type_name}'" unless type_name =~ Patterns::CLASSREF_EXT
329
+ PResourceType.new(type_name, title)
330
+ when nil
331
+ raise ArgumentError, 'The type name cannot be nil, if title is given' unless title.nil?
332
+ PResourceType::DEFAULT
333
+ else
334
+ raise ArgumentError, "The type name cannot be a #{type_name.class.name}"
311
335
  end
312
- PResourceType.new(type_name, title)
313
336
  end
314
337
 
315
338
  # Produces PHostClassType with a string class_name. A PHostClassType with
@@ -341,6 +364,17 @@ module TypeFactory
341
364
  PHashType.new(type_of(key), type_of(value), size_type)
342
365
  end
343
366
 
367
+ # Produces a type for Hash[key,value,size]
368
+ # @param key_type [PAnyType] the key type
369
+ # @param value_type [PAnyType] the value type
370
+ # @param size_type [PIntegerType]
371
+ # @return [PHashType] the created hash type
372
+ # @api public
373
+ #
374
+ def self.hash_kv(key_type, value_type, size_type = nil)
375
+ PHashType.new(key_type, value_type, size_type)
376
+ end
377
+
344
378
  # Produces a type for Array[Data]
345
379
  # @api public
346
380
  #
@@ -434,17 +468,16 @@ module TypeFactory
434
468
  # @param name [String] the name of the unresolved type
435
469
  # @param expression [Model::Expression] an expression that will evaluate to a type
436
470
  # @return [PTypeAliasType] the type alias
437
- def self.type_alias(name, expression)
438
- PTypeAliasType.new(name, expression)
471
+ def self.type_alias(name = nil, expression = nil)
472
+ name.nil? ? PTypeAliasType::DEFAULT : PTypeAliasType.new(name, expression)
439
473
  end
440
474
 
441
475
  # Returns the type that represents a type reference with a given name and optional
442
476
  # parameters.
443
- # @param name [String] the name of the type
444
- # @param parameters [Array] the parameters
477
+ # @param type_string [String] the string form of the type
445
478
  # @return [PTypeReferenceType] the type reference
446
- def self.type_reference(name, parameters = nil)
447
- PTypeReferenceType.new(name, parameters)
479
+ def self.type_reference(type_string = nil)
480
+ type_string == nil ? PTypeReferenceType::DEFAULT : PTypeReferenceType.new(type_string)
448
481
  end
449
482
 
450
483
  # Returns true if the given type t is of valid range parameter type (integer
@@ -28,18 +28,71 @@ class TypeFormatter
28
28
  # @api public
29
29
  #
30
30
  def string(t)
31
- @@string_visitor.visit_this_0(self, t)
31
+ @bld = ''
32
+ append_string(t)
33
+ @bld
34
+ end
35
+
36
+ # Produces an string containing newline characters and indentation that represents the given
37
+ # type or literal _t_.
38
+ #
39
+ # @param t [Object] the type or literal to produce a string for
40
+ # @param indent [Integer] the current indentation level
41
+ # @param indent_width [Integer] the number of spaces to use for one indentation
42
+ #
43
+ # @api public
44
+ def indented_string(t, indent = 0, indent_width = 2)
45
+ @indent = indent
46
+ @indent_width = indent_width
47
+ begin
48
+ @bld = ''
49
+ (@indent * @indent_width).times { @bld << ' ' }
50
+ append_string(t)
51
+ @bld << "\n"
52
+ @bld
53
+ ensure
54
+ @indent = nil
55
+ @indent_width = nil
56
+ end
57
+ end
58
+
59
+ # @api private
60
+ def ruby_string(ref_ctor, indent, t)
61
+ @ruby = true
62
+ @ref_ctor = ref_ctor
63
+ begin
64
+ indented_string(t, indent)
65
+ ensure
66
+ @ruby = nil
67
+ @ref_ctor = nil
68
+ end
69
+ end
70
+
71
+
72
+ def append_string(t)
73
+ if @ruby && t.is_a?(PAnyType)
74
+ @ruby = false
75
+ begin
76
+ @bld << @ref_ctor << "('"
77
+ @@string_visitor.visit_this_0(self, t)
78
+ @bld << "')"
79
+ ensure
80
+ @ruby = true
81
+ end
82
+ else
83
+ @@string_visitor.visit_this_0(self, t)
84
+ end
32
85
  end
33
86
 
34
87
  # Produces a string representing the type where type aliases have been expanded
35
88
  # @api public
36
89
  #
37
90
  def alias_expanded_string(t)
38
- @expand_aliases = true
91
+ @expanded = true
39
92
  begin
40
93
  string(t)
41
94
  ensure
42
- @expand_aliases = false
95
+ @expanded = false
43
96
  end
44
97
  end
45
98
 
@@ -56,254 +109,378 @@ class TypeFormatter
56
109
  end
57
110
 
58
111
  # @api private
59
- def string_Module(t)
60
- string(TypeCalculator.singleton.type(t))
61
- end
62
-
63
- # @api private
64
- def string_NilClass(t) ; '?' ; end
112
+ def string_PAnyType(_) ; @bld << 'Any' ; end
65
113
 
66
114
  # @api private
67
- def string_String(t) ; t.inspect ; end
115
+ def string_PUndefType(_) ; @bld << 'Undef' ; end
68
116
 
69
117
  # @api private
70
- def string_Symbol(t) ; t.to_s ; end
118
+ def string_PDefaultType(_) ; @bld << 'Default' ; end
71
119
 
72
120
  # @api private
73
- def string_PAnyType(t) ; 'Any' ; end
121
+ def string_PBooleanType(_) ; @bld << 'Boolean' ; end
74
122
 
75
123
  # @api private
76
- def string_PUndefType(t) ; 'Undef' ; end
124
+ def string_PScalarType(_) ; @bld << 'Scalar' ; end
77
125
 
78
126
  # @api private
79
- def string_PDefaultType(t) ; 'Default' ; end
127
+ def string_PDataType(_) ; @bld << 'Data' ; end
80
128
 
81
129
  # @api private
82
- def string_PBooleanType(t) ; 'Boolean' ; end
83
-
84
- # @api private
85
- def string_PScalarType(t) ; 'Scalar' ; end
86
-
87
- # @api private
88
- def string_PDataType(t) ; 'Data' ; end
89
-
90
- # @api private
91
- def string_PNumericType(t) ; 'Numeric' ; end
130
+ def string_PNumericType(_) ; @bld << 'Numeric' ; end
92
131
 
93
132
  # @api private
94
133
  def string_PIntegerType(t)
95
- append_array('Integer', range_array_part(t))
134
+ append_array('Integer', t.unbounded?) { append_elements(range_array_part(t)) }
96
135
  end
97
136
 
98
137
  # @api private
99
138
  def string_PType(t)
100
- append_array('Type', t.type.nil? ? EMPTY_ARRAY : [string(t.type)])
139
+ append_array('Type', t.type.nil?) { append_string(t.type) }
101
140
  end
102
141
 
103
142
  # @api private
104
143
  def string_PIterableType(t)
105
- append_array('Iterable', t.element_type.nil? ? EMPTY_ARRAY : [string(t.element_type)])
144
+ append_array('Iterable', t.element_type.nil?) { append_string(t.element_type) }
106
145
  end
107
146
 
108
147
  # @api private
109
148
  def string_PIteratorType(t)
110
- append_array('Iterator', t.element_type.nil? ? EMPTY_ARRAY : [string(t.element_type)])
149
+ append_array('Iterator', t.element_type.nil?) { append_string(t.element_type) }
111
150
  end
112
151
 
113
152
  # @api private
114
153
  def string_PFloatType(t)
115
- append_array('Float', range_array_part(t))
154
+ append_array('Float', t.unbounded? ) { append_elements(range_array_part(t)) }
116
155
  end
117
156
 
118
157
  # @api private
119
158
  def string_PRegexpType(t)
120
- append_array('Regexp', t.pattern.nil? ? EMPTY_ARRAY : [t.regexp.inspect])
159
+ append_array('Regexp', t.pattern.nil?) { append_string(t.regexp) }
121
160
  end
122
161
 
123
162
  # @api private
124
163
  def string_PStringType(t)
125
- elements = range_array_part(t.size_type)
126
- elements += t.values.map {|s| "'#{s}'" } if @debug
127
- append_array('String', elements)
164
+ range = range_array_part(t.size_type)
165
+ append_array('String', range.empty?) do
166
+ if @debug
167
+ append_elements(range, true)
168
+ append_strings(t.values, true)
169
+ chomp_list
170
+ else
171
+ append_elements(range)
172
+ end
173
+ end
128
174
  end
129
175
 
130
176
  # @api private
131
177
  def string_PEnumType(t)
132
- append_array('Enum', t.values.map {|s| "'#{s}'" })
178
+ append_array('Enum', t.values.empty?) { append_strings(t.values) }
133
179
  end
134
180
 
135
181
  # @api private
136
182
  def string_PVariantType(t)
137
- append_array('Variant', t.types.map {|t2| string(t2) })
183
+ append_array('Variant', t.types.empty?) { append_strings(t.types) }
184
+ end
185
+
186
+ # @api private
187
+ def string_PSemVerType(t)
188
+ append_array('SemVer', t.ranges.empty?) { append_strings(t.ranges) }
189
+ end
190
+
191
+ # @api private
192
+ def string_PSemVerRangeType(t)
193
+ @bld << 'SemVerRange'
138
194
  end
139
195
 
140
196
  # @api private
141
197
  def string_PTupleType(t)
142
- type_strings = t.types.map {|t2| string(t2) }
143
- type_strings += range_array_part(t.size_type) unless type_strings.empty?
144
- append_array('Tuple', type_strings)
198
+ append_array('Tuple', t.types.empty?) do
199
+ append_strings(t.types, true)
200
+ append_elements(range_array_part(t.size_type), true)
201
+ chomp_list
202
+ end
145
203
  end
146
204
 
147
205
  # @api private
148
206
  def string_PCallableType(t)
149
- elements = EMPTY_ARRAY
150
- unless t.param_types.nil?
207
+ append_array('Callable', t.param_types.nil?) do
151
208
  # translate to string, and skip Unit types
152
- elements = t.param_types.types.map {|t2| string(t2) unless t2.class == PUnitType }.compact
209
+ append_strings(t.param_types.types.reject {|t2| t2.class == PUnitType }, true)
153
210
 
154
211
  if t.param_types.types.empty?
155
- elements += ['0', '0']
212
+ append_strings([0, 0], true)
156
213
  else
157
- elements += range_array_part(t.param_types.size_type)
214
+ append_elements(range_array_part(t.param_types.size_type), true)
158
215
  end
159
216
 
160
217
  # Add block T last (after min, max) if present)
161
218
  #
162
- unless t.block_type.nil?
163
- elements << string(t.block_type)
164
- end
219
+ append_strings([t.block_type], true) unless t.block_type.nil?
220
+ chomp_list
165
221
  end
166
- append_array('Callable', elements)
167
222
  end
168
223
 
169
224
  # @api private
170
225
  def string_PStructType(t)
171
- args = t.elements.empty? ? EMPTY_ARRAY : [append_hash('', t.elements.map {|e| hash_entry_PStructElement(e)})]
172
- append_array('Struct', args)
226
+ append_array('Struct', t.elements.empty?) { append_hash(Hash[t.elements.map {|e| struct_element_pair(e) }]) }
173
227
  end
174
228
 
175
229
  # @api private
176
- def hash_entry_PStructElement(t)
230
+ def struct_element_pair(t)
177
231
  k = t.key_type
178
232
  value_optional = t.value_type.assignable?(PUndefType::DEFAULT)
179
- key_string =
180
- if k.is_a?(POptionalType)
181
- # Output as literal String
182
- value_optional ? "'#{t.name}'" : string(k)
183
- else
184
- value_optional ? "NotUndef['#{t.name}']" : "'#{t.name}'"
185
- end
186
- [key_string, string(t.value_type)]
233
+ if k.is_a?(POptionalType)
234
+ # Output as literal String
235
+ k = t.name if value_optional
236
+ else
237
+ k = value_optional ? PNotUndefType.new(k) : t.name
238
+ end
239
+ [k, t.value_type]
187
240
  end
188
241
 
189
242
  # @api private
190
243
  def string_PPatternType(t)
191
- append_array('Pattern', t.patterns.map {|s| "#{s.regexp.inspect}" })
244
+ append_array('Pattern', t.patterns.empty?) { append_strings(t.patterns.map(&:regexp)) }
192
245
  end
193
246
 
194
247
  # @api private
195
248
  def string_PCollectionType(t)
196
- append_array('Collection', range_array_part(t.size_type))
249
+ range = range_array_part(t.size_type)
250
+ append_array('Collection', range.empty? ) { append_elements(range) }
197
251
  end
198
252
 
199
253
  # @api private
200
- def string_PUnitType(t)
201
- 'Unit'
254
+ def string_PUnitType(_)
255
+ @bld << 'Unit'
202
256
  end
203
257
 
204
258
  # @api private
205
259
  def string_PRuntimeType(t)
206
- append_array('Runtime', [string(t.runtime), string(t.runtime_type_name)])
207
- end
208
-
209
- def is_empty_range?(from, to)
210
- from == 0 && to == 0
260
+ append_array('Runtime') { append_strings([t.runtime, t.name_or_pattern]) }
211
261
  end
212
262
 
213
263
  # @api private
214
264
  def string_PArrayType(t)
215
265
  if t.has_empty_range?
216
- append_array('Array', ['0', '0'])
266
+ append_array('Array') { append_strings([0, 0]) }
217
267
  else
218
- append_array('Array', t == PArrayType::DATA ? EMPTY_ARRAY : [string(t.element_type)] + range_array_part(t.size_type))
268
+ append_array('Array', t == PArrayType::DATA) do
269
+ append_strings([t.element_type], true)
270
+ append_elements(range_array_part(t.size_type), true)
271
+ chomp_list
272
+ end
219
273
  end
220
274
  end
221
275
 
222
276
  # @api private
223
277
  def string_PHashType(t)
224
278
  if t.has_empty_range?
225
- append_array('Hash', ['0', '0'])
279
+ append_array('Hash') { append_strings([0, 0]) }
226
280
  else
227
- append_array('Hash', t == PHashType::DATA ? EMPTY_ARRAY : [string(t.key_type), string(t.element_type)] + range_array_part(t.size_type))
281
+ append_array('Hash', t == PHashType::DATA) do
282
+ append_strings([t.key_type, t.element_type], true)
283
+ append_elements(range_array_part(t.size_type), true)
284
+ chomp_list
285
+ end
228
286
  end
229
287
  end
230
288
 
231
289
  # @api private
232
- def string_PCatalogEntryType(t)
233
- 'CatalogEntry'
290
+ def string_PCatalogEntryType(_)
291
+ @bld << 'CatalogEntry'
234
292
  end
235
293
 
236
294
  # @api private
237
295
  def string_PHostClassType(t)
238
- append_array('Class', t.class_name.nil? ? EMPTY_ARRAY : [t.class_name])
296
+ append_array('Class', t.class_name.nil?) { append_elements([t.class_name]) }
239
297
  end
240
298
 
241
299
  # @api private
242
300
  def string_PResourceType(t)
243
301
  if t.type_name
244
- append_array(capitalize_segments(t.type_name), t.title.nil? ? EMPTY_ARRAY : ["'#{t.title}'"])
302
+ append_array(capitalize_segments(t.type_name), t.title.nil?) { append_string(t.title) }
245
303
  else
246
- 'Resource'
304
+ @bld << 'Resource'
247
305
  end
248
306
  end
249
307
 
250
308
  # @api private
251
309
  def string_PNotUndefType(t)
252
310
  contained_type = t.type
253
- if contained_type.nil? || contained_type.class == PAnyType
254
- args = EMPTY_ARRAY
255
- else
311
+ append_array('NotUndef', contained_type.nil? || contained_type.class == PAnyType) do
256
312
  if contained_type.is_a?(PStringType) && contained_type.values.size == 1
257
- args = [ "'#{contained_type.values[0]}'" ]
313
+ append_string(contained_type.values[0])
258
314
  else
259
- args = [ string(contained_type) ]
315
+ append_string(contained_type)
260
316
  end
261
317
  end
262
- append_array('NotUndef', args)
318
+ end
319
+
320
+ # @api private
321
+ def string_PAnnotatedMember(m)
322
+ hash = m.i12n_hash
323
+ if hash.size == 1
324
+ string(m.type)
325
+ else
326
+ string(hash)
327
+ end
328
+ end
329
+
330
+ # Used when printing names of well known keys in an Object type. Placed in a separate
331
+ # method to allow override.
332
+ # @api private
333
+ def symbolic_key(key)
334
+ @ruby ? "'#{key}'" : key
335
+ end
336
+
337
+ # @api private
338
+ def string_PObjectType(t)
339
+ if @expanded
340
+ begin
341
+ @expanded = false
342
+ append_array('Object') do
343
+ append_hash(t.i12n_hash.each, proc { |k| @bld << symbolic_key(k) }) do |k,v|
344
+ case k
345
+ when PObjectType::KEY_ATTRIBUTES, PObjectType::KEY_FUNCTIONS
346
+ # Types might need to be output as type references
347
+ append_hash(v) do |_, fv|
348
+ if fv.is_a?(Hash)
349
+ append_hash(fv, proc { |fak| @bld << symbolic_key(fak) }) do |fak,fav|
350
+ case fak
351
+ when PObjectType::KEY_KIND
352
+ @bld << fav
353
+ else
354
+ append_string(fav)
355
+ end
356
+ end
357
+ else
358
+ append_string(fv)
359
+ end
360
+ end
361
+ when PObjectType::KEY_EQUALITY
362
+ append_array('') { append_strings(v) } if v.is_a?(Array)
363
+ else
364
+ append_string(v)
365
+ end
366
+ end
367
+ end
368
+ ensure
369
+ @expanded = true
370
+ end
371
+ else
372
+ @bld << t.label
373
+ end
263
374
  end
264
375
 
265
376
  # @api private
266
377
  def string_POptionalType(t)
267
378
  optional_type = t.optional_type
268
- if optional_type.nil?
269
- args = EMPTY_ARRAY
270
- else
379
+ append_array('Optional', optional_type.nil?) do
271
380
  if optional_type.is_a?(PStringType) && optional_type.values.size == 1
272
- args = [ "'#{optional_type.values[0]}'" ]
381
+ append_string(optional_type.values[0])
273
382
  else
274
- args = [ string(optional_type) ]
383
+ append_string(optional_type)
275
384
  end
276
385
  end
277
- append_array('Optional', args)
278
386
  end
279
387
 
280
388
  # @api private
281
389
  def string_PTypeAliasType(t)
282
- expand = @expand_aliases
390
+ expand = @expanded
283
391
  if expand && t.self_recursion?
284
392
  @guard ||= RecursionGuard.new
285
393
  expand = (@guard.add_this(t) & RecursionGuard::SELF_RECURSION_IN_THIS) == 0
286
394
  end
287
- expand ? "#{t.name} = #{string(t.resolved_type)}" : t.name
395
+ @bld << t.name
396
+ if expand
397
+ @bld << ' = '
398
+ append_string(t.resolved_type)
399
+ end
288
400
  end
289
401
 
290
402
  # @api private
291
403
  def string_PTypeReferenceType(t)
292
- if t.parameters.empty?
293
- t.name
294
- else
295
- append_array(t.name.clone, t.parameters.map {|p| string(p) })
296
- end
404
+ append_array('TypeReference') { append_string(t.type_string) }
405
+ end
406
+
407
+ # @api private
408
+ def string_Array(t)
409
+ append_array('') { append_strings(t) }
410
+ end
411
+
412
+ # @api private
413
+ def string_FalseClass(t) ; @bld << 'false' ; end
414
+
415
+ # @api private
416
+ def string_Hash(t)
417
+ append_hash(t)
418
+ end
419
+
420
+ # @api private
421
+ def string_Module(t)
422
+ append_string(TypeCalculator.singleton.type(t))
297
423
  end
298
424
 
425
+ # @api private
426
+ def string_NilClass(t) ; @bld << (@ruby ? 'nil' : '?') ; end
427
+
428
+ # @api private
429
+ def string_Numeric(t) ; @bld << t.to_s ; end
430
+
431
+ # @api private
432
+ def string_Regexp(t) ; @bld << t.inspect; end
433
+
434
+ # @api private
435
+ def string_String(t)
436
+ # Use single qoute on strings that does not contain single quotes, control characters, or backslashes.
437
+ # TODO: This should move to StringConverter when this formatter is changed to take advantage of it
438
+ @bld << (t.ascii_only? && (t =~ /^(?:'|\p{Cntrl}|\\)$/).nil? ? "'#{t}'" : t.inspect)
439
+ end
440
+
441
+ # @api private
442
+ def string_Symbol(t) ; @bld << t.to_s ; end
443
+
444
+ # @api private
445
+ def string_TrueClass(t) ; @bld << 'true' ; end
446
+
447
+ # @api private
448
+ def string_Version(t) ; @bld << "'#{t}'" ; end
449
+
450
+ # @api private
451
+ def string_VersionRange(t) ; @bld << "'#{t}'" ; end
452
+
299
453
  # Debugging to_s to reduce the amount of output
300
454
  def to_s
301
455
  '[a TypeFormatter]'
302
456
  end
303
457
 
304
- private
305
-
306
458
  NAME_SEGMENT_SEPARATOR = '::'.freeze
459
+ STARTS_WITH_ASCII_CAPITAL = /^[A-Z]/
460
+
461
+ # Capitalizes each segment in a name separated with the {NAME_SEPARATOR} conditionally. The name
462
+ # will not be subject to capitalization if it already starts with a capital letter. This to avoid
463
+ # that existing camel casing is lost.
464
+ #
465
+ # @param qualified_name [String] the name to capitalize
466
+ # @return [String] the capitalized name
467
+ #
468
+ # @api private
469
+ def capitalize_segments(qualified_name)
470
+ if !qualified_name.is_a?(String) || qualified_name =~ STARTS_WITH_ASCII_CAPITAL
471
+ qualified_name
472
+ else
473
+ segments = qualified_name.split(NAME_SEGMENT_SEPARATOR)
474
+ if segments.size == 1
475
+ qualified_name.capitalize
476
+ else
477
+ segments.each(&:capitalize!)
478
+ segments.join(NAME_SEGMENT_SEPARATOR)
479
+ end
480
+ end
481
+ end
482
+
483
+ private
307
484
 
308
485
  COMMA_SEP = ', '.freeze
309
486
 
@@ -313,30 +490,76 @@ class TypeFormatter
313
490
  t.nil? || t.unbounded? ? EMPTY_ARRAY : [t.from.nil? ? 'default' : t.from.to_s , t.to.nil? ? 'default' : t.to.to_s ]
314
491
  end
315
492
 
316
- def append_array(bld, array)
493
+ def append_elements(array, to_be_continued = false)
317
494
  case array.size
318
495
  when 0
319
496
  when 1
320
- bld << '[' << array[0] << ']'
497
+ @bld << array[0]
498
+ @bld << COMMA_SEP if to_be_continued
321
499
  else
322
- bld << '['
323
- array.each { |elem| bld << elem << COMMA_SEP }
324
- bld.chomp!(COMMA_SEP)
325
- bld << ']'
500
+ array.each { |elem| @bld << elem << COMMA_SEP }
501
+ chomp_list unless to_be_continued
502
+ end
503
+ end
504
+
505
+ def append_strings(array, to_be_continued = false)
506
+ case array.size
507
+ when 0
508
+ when 1
509
+ append_string(array[0])
510
+ @bld << COMMA_SEP if to_be_continued
511
+ else
512
+ array.each do |elem|
513
+ append_string(elem)
514
+ @bld << COMMA_SEP
515
+ end
516
+ chomp_list unless to_be_continued
517
+ end
518
+ end
519
+
520
+ def append_array(start, empty = false)
521
+ @bld << start
522
+ unless empty
523
+ @bld << '['
524
+ yield
525
+ @bld << ']'
526
+ end
527
+ end
528
+
529
+ def append_hash(hash, key_proc = nil)
530
+ @bld << '{'
531
+ @indent += 1 if @indent
532
+ hash.each do |k, v|
533
+ newline if @indent
534
+ if key_proc.nil?
535
+ append_string(k)
536
+ else
537
+ key_proc.call(k)
538
+ end
539
+ @bld << HASH_ENTRY_OP
540
+ if block_given?
541
+ yield(k, v)
542
+ else
543
+ append_string(v)
544
+ end
545
+ @bld << COMMA_SEP
546
+ end
547
+ chomp_list
548
+ if @indent
549
+ @indent -= 1
550
+ newline
326
551
  end
327
- bld
552
+ @bld << '}'
328
553
  end
329
554
 
330
- def append_hash(bld, hash_entries)
331
- bld << '{'
332
- hash_entries.each { |k, v| bld << k << HASH_ENTRY_OP << v << COMMA_SEP }
333
- bld.chomp!(COMMA_SEP)
334
- bld << '}'
335
- bld
555
+ def newline
556
+ @bld.rstrip!
557
+ @bld << "\n"
558
+ (@indent * @indent_width).times { @bld << ' ' }
336
559
  end
337
560
 
338
- def capitalize_segments(s)
339
- s.split(NAME_SEGMENT_SEPARATOR).map(&:capitalize).join(NAME_SEGMENT_SEPARATOR)
561
+ def chomp_list
562
+ @bld.chomp!(COMMA_SEP)
340
563
  end
341
564
 
342
565
  @singleton = new