puppet 4.2.3 → 4.3.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.

Files changed (337) hide show
  1. data/Gemfile +3 -0
  2. data/README.md +1 -1
  3. data/ext/debian/puppet.init +0 -1
  4. data/ext/debian/puppet.logrotate +14 -5
  5. data/ext/osx/puppet.plist +0 -2
  6. data/ext/redhat/client.init +13 -5
  7. data/ext/redhat/logrotate +15 -3
  8. data/ext/redhat/puppet.spec.erb +5 -1
  9. data/ext/redhat/server.init +1 -1
  10. data/ext/systemd/puppet.service +1 -0
  11. data/lib/puppet.rb +12 -0
  12. data/lib/puppet/agent.rb +4 -4
  13. data/lib/puppet/agent/locker.rb +11 -2
  14. data/lib/puppet/application/agent.rb +5 -1
  15. data/lib/puppet/application/apply.rb +4 -0
  16. data/lib/puppet/application/filebucket.rb +78 -4
  17. data/lib/puppet/application/lookup.rb +356 -0
  18. data/lib/puppet/application/master.rb +3 -0
  19. data/lib/puppet/configurer.rb +9 -5
  20. data/lib/puppet/context.rb +16 -1
  21. data/lib/puppet/context/trusted_information.rb +21 -1
  22. data/lib/puppet/daemon.rb +17 -13
  23. data/lib/puppet/data_binding.rb +4 -2
  24. data/lib/puppet/data_providers.rb +12 -13
  25. data/lib/puppet/data_providers/data_adapter.rb +7 -68
  26. data/lib/puppet/data_providers/data_function_support.rb +5 -26
  27. data/lib/puppet/data_providers/function_env_data_provider.rb +0 -10
  28. data/lib/puppet/data_providers/function_module_data_provider.rb +0 -22
  29. data/lib/puppet/data_providers/hiera_config.rb +106 -0
  30. data/lib/puppet/data_providers/hiera_env_data_provider.rb +18 -0
  31. data/lib/puppet/data_providers/hiera_interpolate.rb +97 -0
  32. data/lib/puppet/data_providers/hiera_module_data_provider.rb +23 -0
  33. data/lib/puppet/data_providers/hiera_support.rb +37 -0
  34. data/lib/puppet/data_providers/json_data_provider_factory.rb +31 -0
  35. data/lib/puppet/data_providers/lookup_adapter.rb +200 -0
  36. data/lib/puppet/data_providers/yaml_data_provider_factory.rb +32 -0
  37. data/lib/puppet/defaults.rb +12 -2
  38. data/lib/puppet/error.rb +4 -0
  39. data/lib/puppet/face/module/changes.rb +2 -1
  40. data/lib/puppet/feature/cfacter.rb +1 -0
  41. data/lib/puppet/file_bucket/dipper.rb +58 -2
  42. data/lib/puppet/functions.rb +2 -4
  43. data/lib/puppet/functions/assert_type.rb +48 -12
  44. data/lib/puppet/functions/defined.rb +79 -48
  45. data/lib/puppet/functions/each.rb +85 -27
  46. data/lib/puppet/functions/filter.rb +58 -23
  47. data/lib/puppet/functions/hiera.rb +76 -3
  48. data/lib/puppet/functions/hiera_array.rb +65 -3
  49. data/lib/puppet/functions/hiera_hash.rb +74 -2
  50. data/lib/puppet/functions/hiera_include.rb +75 -2
  51. data/lib/puppet/functions/lookup.rb +19 -17
  52. data/lib/puppet/functions/map.rb +56 -21
  53. data/lib/puppet/functions/match.rb +29 -12
  54. data/lib/puppet/functions/reduce.rb +95 -58
  55. data/lib/puppet/functions/versioncmp.rb +36 -0
  56. data/lib/puppet/functions/with.rb +15 -7
  57. data/lib/puppet/indirector/catalog/compiler.rb +3 -3
  58. data/lib/puppet/indirector/catalog/static_compiler.rb +46 -30
  59. data/lib/puppet/indirector/data_binding/none.rb +4 -1
  60. data/lib/puppet/indirector/file_bucket_file/file.rb +58 -1
  61. data/lib/puppet/indirector/hiera.rb +4 -0
  62. data/lib/puppet/indirector/json.rb +1 -1
  63. data/lib/puppet/indirector/msgpack.rb +1 -1
  64. data/lib/puppet/indirector/request.rb +7 -8
  65. data/lib/puppet/indirector/resource_type/parser.rb +5 -3
  66. data/lib/puppet/info_service.rb +7 -0
  67. data/lib/puppet/info_service/class_information_service.rb +111 -0
  68. data/lib/puppet/module_tool/metadata.rb +32 -9
  69. data/lib/puppet/module_tool/skeleton/templates/generator/README.md.erb +42 -38
  70. data/lib/puppet/network/authconfig.rb +21 -1
  71. data/lib/puppet/network/authorization.rb +8 -1
  72. data/lib/puppet/network/http/api/master/v3.rb +7 -1
  73. data/lib/puppet/network/http/api/master/v3/environment.rb +59 -0
  74. data/lib/puppet/node/environment.rb +9 -2
  75. data/lib/puppet/parser.rb +3 -0
  76. data/lib/puppet/parser/ast/pops_bridge.rb +39 -1
  77. data/lib/puppet/parser/compiler.rb +302 -12
  78. data/lib/puppet/parser/compiler/catalog_validator.rb +33 -0
  79. data/lib/puppet/parser/compiler/catalog_validator/env_relationship_validator.rb +64 -0
  80. data/lib/puppet/parser/compiler/catalog_validator/relationship_validator.rb +38 -0
  81. data/lib/puppet/parser/compiler/catalog_validator/site_validator.rb +20 -0
  82. data/lib/puppet/parser/environment_compiler.rb +165 -0
  83. data/lib/puppet/parser/functions/assert_type.rb +46 -16
  84. data/lib/puppet/parser/functions/defined.rb +105 -68
  85. data/lib/puppet/parser/functions/each.rb +85 -27
  86. data/lib/puppet/parser/functions/filter.rb +59 -23
  87. data/lib/puppet/parser/functions/hiera.rb +83 -27
  88. data/lib/puppet/parser/functions/hiera_array.rb +71 -28
  89. data/lib/puppet/parser/functions/hiera_hash.rb +81 -30
  90. data/lib/puppet/parser/functions/hiera_include.rb +81 -40
  91. data/lib/puppet/parser/functions/map.rb +55 -20
  92. data/lib/puppet/parser/functions/match.rb +27 -12
  93. data/lib/puppet/parser/functions/reduce.rb +97 -60
  94. data/lib/puppet/parser/functions/with.rb +16 -8
  95. data/lib/puppet/parser/resource.rb +98 -19
  96. data/lib/puppet/plugins/configuration.rb +3 -2
  97. data/lib/puppet/plugins/data_providers.rb +12 -60
  98. data/lib/puppet/plugins/data_providers/data_provider.rb +283 -0
  99. data/lib/puppet/plugins/data_providers/registry.rb +84 -0
  100. data/lib/puppet/pops.rb +19 -17
  101. data/lib/puppet/pops/adapters.rb +12 -0
  102. data/lib/puppet/pops/binder/binder.rb +2 -2
  103. data/lib/puppet/pops/binder/bindings_checker.rb +1 -1
  104. data/lib/puppet/pops/binder/bindings_label_provider.rb +3 -1
  105. data/lib/puppet/pops/binder/bindings_loader.rb +6 -2
  106. data/lib/puppet/pops/binder/bindings_model_meta.rb +2 -2
  107. data/lib/puppet/pops/binder/config/binder_config.rb +1 -1
  108. data/lib/puppet/pops/binder/injector.rb +4 -4
  109. data/lib/puppet/pops/binder/key_factory.rb +3 -9
  110. data/lib/puppet/pops/binder/scheme_handler/module_scheme.rb +68 -9
  111. data/lib/puppet/pops/evaluator/access_operator.rb +27 -60
  112. data/lib/puppet/pops/evaluator/closure.rb +8 -8
  113. data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +1 -1
  114. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -5
  115. data/lib/puppet/pops/evaluator/literal_evaluator.rb +87 -0
  116. data/lib/puppet/pops/evaluator/relationship_operator.rb +7 -1
  117. data/lib/puppet/pops/functions/dispatcher.rb +3 -3
  118. data/lib/puppet/pops/issues.rb +1 -1
  119. data/lib/puppet/pops/label_provider.rb +1 -1
  120. data/lib/puppet/pops/lookup.rb +25 -47
  121. data/lib/puppet/pops/lookup/explainer.rb +402 -0
  122. data/lib/puppet/pops/lookup/invocation.rb +117 -0
  123. data/lib/puppet/pops/merge_strategy.rb +73 -5
  124. data/lib/puppet/pops/model/factory.rb +34 -0
  125. data/lib/puppet/pops/model/model_label_provider.rb +10 -1
  126. data/lib/puppet/pops/model/model_meta.rb +15 -0
  127. data/lib/puppet/pops/model/model_tree_dumper.rb +18 -0
  128. data/lib/puppet/pops/parser/code_merger.rb +13 -1
  129. data/lib/puppet/pops/parser/egrammar.ra +56 -3
  130. data/lib/puppet/pops/parser/eparser.rb +1549 -1352
  131. data/lib/puppet/pops/parser/lexer2.rb +31 -6
  132. data/lib/puppet/pops/parser/locator.rb +1 -1
  133. data/lib/puppet/pops/parser/parser_support.rb +25 -13
  134. data/lib/puppet/pops/types/enumeration.rb +1 -2
  135. data/lib/puppet/pops/types/type_asserter.rb +16 -15
  136. data/lib/puppet/pops/types/type_assertion_error.rb +1 -0
  137. data/lib/puppet/pops/types/type_calculator.rb +171 -1020
  138. data/lib/puppet/pops/types/type_factory.rb +87 -148
  139. data/lib/puppet/pops/types/type_mismatch_describer.rb +743 -0
  140. data/lib/puppet/pops/types/type_parser.rb +116 -127
  141. data/lib/puppet/pops/types/types.rb +1394 -255
  142. data/lib/puppet/pops/types/types_meta.rb +0 -234
  143. data/lib/puppet/pops/validation.rb +7 -2
  144. data/lib/puppet/pops/validation/checker4_0.rb +28 -0
  145. data/lib/puppet/provider/augeas/augeas.rb +50 -0
  146. data/lib/puppet/provider/group/directoryservice.rb +10 -0
  147. data/lib/puppet/provider/package/dnf.rb +41 -0
  148. data/lib/puppet/provider/package/gem.rb +7 -2
  149. data/lib/puppet/provider/package/rpm.rb +1 -0
  150. data/lib/puppet/provider/package/windows/exe_package.rb +10 -8
  151. data/lib/puppet/provider/package/windows/msi_package.rb +4 -3
  152. data/lib/puppet/provider/package/windows/package.rb +9 -1
  153. data/lib/puppet/provider/package/yum.rb +14 -9
  154. data/lib/puppet/provider/service/bsd.rb +1 -1
  155. data/lib/puppet/provider/service/debian.rb +21 -0
  156. data/lib/puppet/provider/service/init.rb +6 -0
  157. data/lib/puppet/provider/service/rcng.rb +51 -0
  158. data/lib/puppet/provider/service/redhat.rb +2 -1
  159. data/lib/puppet/provider/service/smf.rb +43 -2
  160. data/lib/puppet/provider/service/src.rb +27 -0
  161. data/lib/puppet/provider/service/systemd.rb +15 -3
  162. data/lib/puppet/provider/sshkey/parsed.rb +19 -9
  163. data/lib/puppet/reference/report.rb +9 -12
  164. data/lib/puppet/reports.rb +5 -1
  165. data/lib/puppet/resource.rb +50 -73
  166. data/lib/puppet/resource/capability_finder.rb +95 -0
  167. data/lib/puppet/resource/catalog.rb +47 -7
  168. data/lib/puppet/resource/status.rb +0 -2
  169. data/lib/puppet/resource/type.rb +238 -44
  170. data/lib/puppet/resource/type_collection.rb +60 -2
  171. data/lib/puppet/settings.rb +2 -2
  172. data/lib/puppet/ssl/certificate_authority/interface.rb +2 -2
  173. data/lib/puppet/ssl/oids.rb +9 -1
  174. data/lib/puppet/transaction.rb +4 -1
  175. data/lib/puppet/transaction/additional_resource_generator.rb +71 -8
  176. data/lib/puppet/transaction/resource_harness.rb +9 -4
  177. data/lib/puppet/type.rb +74 -3
  178. data/lib/puppet/type/augeas.rb +8 -0
  179. data/lib/puppet/type/file/source.rb +14 -12
  180. data/lib/puppet/type/user.rb +4 -2
  181. data/lib/puppet/util/windows/security.rb +4 -1
  182. data/lib/puppet/util/windows/taskscheduler.rb +1 -1
  183. data/lib/puppet/version.rb +1 -1
  184. data/spec/fixtures/unit/application/environments/production/data/common.yaml +3 -0
  185. data/spec/fixtures/unit/application/environments/production/environment.conf +1 -0
  186. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/data/bad.json +3 -0
  187. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/environment.conf +2 -0
  188. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/hiera.yaml +5 -0
  189. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_json/manifests/site.pp +5 -0
  190. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/data/bad.yaml +3 -0
  191. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/environment.conf +2 -0
  192. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/hiera.yaml +5 -0
  193. data/spec/fixtures/unit/data_providers/environments/hiera_bad_syntax_yaml/manifests/site.pp +5 -0
  194. data/spec/fixtures/unit/data_providers/environments/hiera_defaults/data/common.yaml +2 -0
  195. data/spec/fixtures/unit/data_providers/environments/hiera_defaults/environment.conf +2 -0
  196. data/spec/fixtures/unit/data_providers/environments/hiera_defaults/manifests/site.pp +1 -0
  197. data/spec/fixtures/unit/data_providers/environments/hiera_defaults/modules/one/data/common.yaml +2 -0
  198. data/spec/fixtures/unit/data_providers/environments/hiera_defaults/modules/one/manifests/init.pp +5 -0
  199. data/spec/fixtures/unit/data_providers/environments/hiera_defaults/modules/one/metadata.json +9 -0
  200. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/first.json +3 -0
  201. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/name.yaml +2 -0
  202. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/second.json +3 -0
  203. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data1/single.yaml +2 -0
  204. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/data2/single.yaml +2 -0
  205. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/environment.conf +2 -0
  206. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/hiera.yaml +18 -0
  207. data/spec/fixtures/unit/data_providers/environments/hiera_env_config/manifests/site.pp +5 -0
  208. data/spec/fixtures/unit/data_providers/environments/hiera_misc/data/common.yaml +46 -0
  209. data/spec/fixtures/unit/data_providers/environments/hiera_misc/environment.conf +2 -0
  210. data/spec/fixtures/unit/data_providers/environments/hiera_misc/manifests/site.pp +1 -0
  211. data/spec/fixtures/unit/data_providers/environments/hiera_misc/modules/one/data/common.yaml +30 -0
  212. data/spec/fixtures/unit/data_providers/environments/hiera_misc/modules/one/manifests/init.pp +13 -0
  213. data/spec/fixtures/unit/data_providers/environments/hiera_misc/modules/one/metadata.json +9 -0
  214. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/environment.conf +2 -0
  215. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/manifests/site.pp +1 -0
  216. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/first.json +3 -0
  217. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/name.yaml +1 -0
  218. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/second.json +3 -0
  219. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data1/single.yaml +2 -0
  220. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/data2/single.yaml +2 -0
  221. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/hiera.yaml +18 -0
  222. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/manifests/init.pp +5 -0
  223. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/modules/one/metadata.json +9 -0
  224. data/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_env_data.rb +1 -0
  225. data/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_module_data.rb +1 -0
  226. data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/data/first.json +3 -0
  227. data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/hiera.yaml +8 -0
  228. data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/manifests/init.pp +5 -0
  229. data/spec/fixtures/unit/functions/lookup/environments/production/modules/hieraprovider/metadata.json +9 -0
  230. data/spec/fixtures/unit/functions/lookup/environments/production/modules/meta/lib/puppet/functions/meta/data.rb +9 -0
  231. data/spec/fixtures/unit/functions/lookup/environments/production/modules/meta/manifests/init.pp +3 -0
  232. data/spec/fixtures/unit/functions/lookup/environments/production/modules/meta/metadata.json +9 -0
  233. data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/lib/puppet/bindings/metawcp/default.rb +10 -0
  234. data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/lib/puppet_x/thallgren/sample_module_data.rb +23 -0
  235. data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/manifests/init.pp +3 -0
  236. data/spec/fixtures/unit/functions/lookup/environments/production/modules/metawcp/metadata.json +9 -0
  237. data/spec/fixtures/unit/provider/package/yum/yum-check-update-security.txt +184 -0
  238. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_get/should_yield_to_the_block.yml +24 -0
  239. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_head/should_yield_to_the_block.yml +24 -0
  240. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_post/should_yield_to_the_block.yml +24 -0
  241. data/spec/integration/data_binding_spec.rb +229 -0
  242. data/spec/integration/file_bucket/file_spec.rb +2 -2
  243. data/spec/integration/parser/compiler_spec.rb +23 -19
  244. data/spec/integration/parser/resource_expressions_spec.rb +4 -4
  245. data/spec/integration/parser/undef_param_spec.rb +1 -1
  246. data/spec/integration/resource/catalog_spec.rb +1 -1
  247. data/spec/integration/type/package_spec.rb +2 -0
  248. data/spec/integration/util/windows/security_spec.rb +18 -0
  249. data/spec/lib/matchers/include_in_order.rb +2 -2
  250. data/spec/shared_behaviours/iterative_functions.rb +8 -8
  251. data/spec/spec_helper.rb +7 -0
  252. data/spec/unit/agent/locker_spec.rb +4 -4
  253. data/spec/unit/agent_spec.rb +0 -8
  254. data/spec/unit/application/agent_spec.rb +5 -0
  255. data/spec/unit/application/apply_spec.rb +8 -0
  256. data/spec/unit/application/filebucket_spec.rb +87 -1
  257. data/spec/unit/application/lookup_spec.rb +195 -0
  258. data/spec/unit/appmgmt_spec.rb +657 -0
  259. data/spec/unit/capability_spec.rb +414 -0
  260. data/spec/unit/configurer_spec.rb +7 -1
  261. data/spec/unit/context/trusted_information_spec.rb +24 -1
  262. data/spec/unit/daemon_spec.rb +18 -8
  263. data/spec/unit/data_providers/hiera_data_provider_spec.rb +201 -0
  264. data/spec/unit/file_bucket/dipper_spec.rb +210 -1
  265. data/spec/unit/functions/assert_type_spec.rb +5 -7
  266. data/spec/unit/functions/defined_spec.rb +2 -2
  267. data/spec/unit/functions/epp_spec.rb +2 -2
  268. data/spec/unit/functions/lookup_spec.rb +200 -9
  269. data/spec/unit/functions/regsubst_spec.rb +17 -8
  270. data/spec/unit/functions/scanf_spec.rb +1 -1
  271. data/spec/unit/functions/split_spec.rb +2 -2
  272. data/spec/unit/functions/versioncmp_spec.rb +36 -0
  273. data/spec/unit/functions4_spec.rb +58 -72
  274. data/spec/unit/indirector/catalog/compiler_spec.rb +28 -8
  275. data/spec/unit/indirector/catalog/static_compiler_spec.rb +38 -20
  276. data/spec/unit/indirector/data_binding/none_spec.rb +2 -2
  277. data/spec/unit/indirector/file_bucket_file/file_spec.rb +52 -1
  278. data/spec/unit/indirector/request_spec.rb +8 -8
  279. data/spec/unit/info_service_spec.rb +236 -0
  280. data/spec/unit/module_tool/metadata_spec.rb +31 -2
  281. data/spec/unit/network/authconfig_spec.rb +62 -32
  282. data/spec/unit/network/authorization_spec.rb +30 -2
  283. data/spec/unit/network/http/connection_spec.rb +14 -19
  284. data/spec/unit/parser/compiler_spec.rb +86 -2
  285. data/spec/unit/parser/functions/create_resources_spec.rb +1 -1
  286. data/spec/unit/parser/resource_spec.rb +2 -20
  287. data/spec/unit/pops/binder/config/binder_config_spec.rb +1 -1
  288. data/spec/unit/pops/binder/injector_spec.rb +3 -3
  289. data/spec/unit/pops/evaluator/access_ops_spec.rb +13 -11
  290. data/spec/unit/pops/evaluator/basic_expressions_spec.rb +1 -2
  291. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +19 -11
  292. data/spec/unit/pops/evaluator/literal_evaluator_spec.rb +43 -0
  293. data/spec/unit/pops/label_provider_spec.rb +5 -1
  294. data/spec/unit/pops/parser/lexer2_spec.rb +33 -7
  295. data/spec/unit/pops/parser/parse_application_spec.rb +40 -0
  296. data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +4 -0
  297. data/spec/unit/pops/parser/parse_capabilities_spec.rb +47 -0
  298. data/spec/unit/pops/parser/parse_site_spec.rb +38 -0
  299. data/spec/unit/pops/parser/parser_rspec_helper.rb +5 -0
  300. data/spec/unit/pops/parser/parser_spec.rb +18 -0
  301. data/spec/unit/pops/types/type_calculator_spec.rb +427 -444
  302. data/spec/unit/pops/types/type_factory_spec.rb +12 -12
  303. data/spec/unit/pops/types/type_parser_spec.rb +7 -12
  304. data/spec/unit/pops/validator/validator_spec.rb +25 -0
  305. data/spec/unit/provider/augeas/augeas_spec.rb +50 -0
  306. data/spec/unit/provider/group/directoryservice_spec.rb +33 -0
  307. data/spec/unit/provider/group/windows_adsi_spec.rb +3 -0
  308. data/spec/unit/provider/package/dnf_spec.rb +92 -0
  309. data/spec/unit/provider/package/gem_spec.rb +7 -0
  310. data/spec/unit/provider/package/rpm_spec.rb +25 -2
  311. data/spec/unit/provider/package/windows/package_spec.rb +41 -0
  312. data/spec/unit/provider/package/yum_spec.rb +21 -13
  313. data/spec/unit/provider/scheduled_task/win32_taskscheduler_spec.rb +10 -0
  314. data/spec/unit/provider/service/debian_spec.rb +27 -0
  315. data/spec/unit/provider/service/rcng_spec.rb +41 -0
  316. data/spec/unit/provider/service/redhat_spec.rb +8 -1
  317. data/spec/unit/provider/service/smf_spec.rb +30 -5
  318. data/spec/unit/provider/service/src_spec.rb +19 -4
  319. data/spec/unit/provider/service/systemd_spec.rb +78 -29
  320. data/spec/unit/provider/sshkey/parsed_spec.rb +23 -0
  321. data/spec/unit/reports_spec.rb +10 -0
  322. data/spec/unit/resource/capability_finder_spec.rb +56 -0
  323. data/spec/unit/resource/catalog_spec.rb +31 -8
  324. data/spec/unit/resource/type_collection_spec.rb +23 -2
  325. data/spec/unit/resource/type_spec.rb +1 -1
  326. data/spec/unit/resource_spec.rb +22 -4
  327. data/spec/unit/settings_spec.rb +90 -1
  328. data/spec/unit/ssl/certificate_authority/interface_spec.rb +4 -3
  329. data/spec/unit/ssl/oids_spec.rb +8 -0
  330. data/spec/unit/transaction/additional_resource_generator_spec.rb +78 -5
  331. data/spec/unit/transaction/report_spec.rb +24 -1
  332. data/spec/unit/type/package_spec.rb +1 -0
  333. data/spec/unit/type/user_spec.rb +14 -7
  334. data/spec/unit/type_spec.rb +1 -1
  335. metadata +169 -5
  336. data/lib/puppet/pops/evaluator/callable_mismatch_describer.rb +0 -175
  337. data/spec/integration/data_binding.rb +0 -104
@@ -11,9 +11,8 @@ class Puppet::Pops::Types::TypeParser
11
11
 
12
12
  # @api public
13
13
  def initialize
14
- @parser = Puppet::Pops::Parser::Parser.new()
15
- @type_transformer = Puppet::Pops::Visitor.new(nil, "interpret", 0, 0)
16
- @undef_t = TYPES.undef
14
+ @parser = Puppet::Pops::Parser::Parser.new
15
+ @type_transformer = Puppet::Pops::Visitor.new(nil, 'interpret', 0, 0)
17
16
  end
18
17
 
19
18
  # Produces a *puppet type* based on the given string.
@@ -113,87 +112,87 @@ class Puppet::Pops::Types::TypeParser
113
112
  # @api private
114
113
  def interpret_QualifiedReference(name_ast)
115
114
  case name_ast.value
116
- when "integer"
115
+ when 'integer'
117
116
  TYPES.integer
118
117
 
119
- when "float"
118
+ when 'float'
120
119
  TYPES.float
121
120
 
122
- when "numeric"
121
+ when 'numeric'
123
122
  TYPES.numeric
124
123
 
125
- when "string"
124
+ when 'string'
126
125
  TYPES.string
127
126
 
128
- when "enum"
127
+ when 'enum'
129
128
  TYPES.enum
130
129
 
131
- when "boolean"
130
+ when 'boolean'
132
131
  TYPES.boolean
133
132
 
134
- when "pattern"
133
+ when 'pattern'
135
134
  TYPES.pattern
136
135
 
137
- when "regexp"
136
+ when 'regexp'
138
137
  TYPES.regexp
139
138
 
140
- when "data"
139
+ when 'data'
141
140
  TYPES.data
142
141
 
143
- when "array"
142
+ when 'array'
144
143
  TYPES.array_of_data
145
144
 
146
- when "hash"
145
+ when 'hash'
147
146
  TYPES.hash_of_data
148
147
 
149
- when "class"
150
- TYPES.host_class()
148
+ when 'class'
149
+ TYPES.host_class
151
150
 
152
- when "resource"
153
- TYPES.resource()
151
+ when 'resource'
152
+ TYPES.resource
154
153
 
155
- when "collection"
156
- TYPES.collection()
154
+ when 'collection'
155
+ TYPES.collection
157
156
 
158
- when "scalar"
159
- TYPES.scalar()
157
+ when 'scalar'
158
+ TYPES.scalar
160
159
 
161
- when "catalogentry"
162
- TYPES.catalog_entry()
160
+ when 'catalogentry'
161
+ TYPES.catalog_entry
163
162
 
164
- when "undef"
165
- TYPES.undef()
163
+ when 'undef'
164
+ TYPES.undef
166
165
 
167
- when "notundef"
166
+ when 'notundef'
168
167
  TYPES.not_undef()
169
168
 
170
- when "default"
169
+ when 'default'
171
170
  TYPES.default()
171
+
172
+ when 'any'
173
+ TYPES.any
172
174
 
173
- when "any"
174
- TYPES.any()
175
+ when 'variant'
176
+ TYPES.variant
175
177
 
176
- when "variant"
177
- TYPES.variant()
178
+ when 'optional'
179
+ TYPES.optional
178
180
 
179
- when "optional"
180
- TYPES.optional()
181
+ when 'runtime'
182
+ TYPES.runtime
181
183
 
182
- when "runtime"
183
- TYPES.runtime()
184
+ when 'type'
185
+ TYPES.type_type
184
186
 
185
- when "type"
186
- TYPES.type_type()
187
+ when 'tuple'
188
+ TYPES.tuple
187
189
 
188
- when "tuple"
189
- TYPES.tuple()
190
+ when 'struct'
191
+ TYPES.struct
190
192
 
191
- when "struct"
192
- TYPES.struct()
193
-
194
- when "callable"
193
+ when 'callable'
195
194
  # A generic callable as opposed to one that does not accept arguments
196
- TYPES.all_callables()
195
+ TYPES.all_callables
197
196
 
198
197
  else
199
198
  TYPES.resource(name_ast.value)
@@ -209,118 +208,112 @@ class Puppet::Pops::Types::TypeParser
209
208
  end
210
209
 
211
210
  case parameterized_ast.left_expr.value
212
- when "array"
211
+ when 'array'
213
212
  case parameters.size
214
213
  when 1
215
214
  when 2
216
215
  size_type =
217
- if parameters[1].is_a?(Puppet::Pops::Types::PIntegerType)
218
- parameters[1].copy
219
- else
220
- assert_range_parameter(parameters[1])
221
- TYPES.range(parameters[1], :default)
222
- end
216
+ if parameters[1].is_a?(Puppet::Pops::Types::PIntegerType)
217
+ parameters[1]
218
+ else
219
+ assert_range_parameter(parameters[1])
220
+ TYPES.range(parameters[1], :default)
221
+ end
223
222
  when 3
224
223
  assert_range_parameter(parameters[1])
225
224
  assert_range_parameter(parameters[2])
226
225
  size_type = TYPES.range(parameters[1], parameters[2])
227
226
  else
228
- raise_invalid_parameters_error("Array", "1 to 3", parameters.size)
227
+ raise_invalid_parameters_error('Array', '1 to 3', parameters.size)
229
228
  end
230
229
  assert_type(parameters[0])
231
- t = TYPES.array_of(parameters[0])
232
- t.size_type = size_type if size_type
233
- t
230
+ TYPES.array_of(parameters[0], size_type)
234
231
 
235
- when "hash"
236
- result = case parameters.size
232
+ when 'hash'
233
+ case parameters.size
237
234
  when 2
238
235
  assert_type(parameters[0])
239
236
  assert_type(parameters[1])
240
237
  TYPES.hash_of(parameters[1], parameters[0])
241
238
  when 3
242
239
  size_type =
243
- if parameters[2].is_a?(Puppet::Pops::Types::PIntegerType)
244
- parameters[2].copy
245
- else
246
- assert_range_parameter(parameters[2])
247
- TYPES.range(parameters[2], :default)
248
- end
240
+ if parameters[2].is_a?(Puppet::Pops::Types::PIntegerType)
241
+ parameters[2]
242
+ else
243
+ assert_range_parameter(parameters[2])
244
+ TYPES.range(parameters[2], :default)
245
+ end
249
246
  assert_type(parameters[0])
250
247
  assert_type(parameters[1])
251
- TYPES.hash_of(parameters[1], parameters[0])
248
+ TYPES.hash_of(parameters[1], parameters[0], size_type)
252
249
  when 4
253
250
  assert_range_parameter(parameters[2])
254
251
  assert_range_parameter(parameters[3])
255
- size_type = TYPES.range(parameters[2], parameters[3])
256
252
  assert_type(parameters[0])
257
253
  assert_type(parameters[1])
258
- TYPES.hash_of(parameters[1], parameters[0])
254
+ TYPES.hash_of(parameters[1], parameters[0], TYPES.range(parameters[2], parameters[3]))
259
255
  else
260
- raise_invalid_parameters_error("Hash", "2 to 4", parameters.size)
256
+ raise_invalid_parameters_error('Hash', '2 to 4', parameters.size)
261
257
  end
262
- result.size_type = size_type if size_type
263
- result
264
258
 
265
- when "collection"
259
+ when 'collection'
266
260
  size_type = case parameters.size
267
- when 1
268
- if parameters[0].is_a?(Puppet::Pops::Types::PIntegerType)
269
- parameters[0].copy
270
- else
261
+ when 1
262
+ if parameters[0].is_a?(Puppet::Pops::Types::PIntegerType)
263
+ parameters[0]
264
+ else
265
+ assert_range_parameter(parameters[0])
266
+ TYPES.range(parameters[0], :default)
267
+ end
268
+ when 2
271
269
  assert_range_parameter(parameters[0])
272
- TYPES.range(parameters[0], :default)
270
+ assert_range_parameter(parameters[1])
271
+ TYPES.range(parameters[0], parameters[1])
272
+ else
273
+ raise_invalid_parameters_error('Collection', '1 to 2', parameters.size)
273
274
  end
274
- when 2
275
- assert_range_parameter(parameters[0])
276
- assert_range_parameter(parameters[1])
277
- TYPES.range(parameters[0], parameters[1])
278
- else
279
- raise_invalid_parameters_error("Collection", "1 to 2", parameters.size)
280
- end
281
- result = TYPES.collection
282
- result.size_type = size_type
283
- result
275
+ TYPES.collection(size_type)
284
276
 
285
- when "class"
277
+ when 'class'
286
278
  if parameters.size != 1
287
- raise_invalid_parameters_error("Class", 1, parameters.size)
279
+ raise_invalid_parameters_error('Class', 1, parameters.size)
288
280
  end
289
281
  TYPES.host_class(parameters[0])
290
282
 
291
- when "resource"
283
+ when 'resource'
292
284
  if parameters.size == 1
293
285
  TYPES.resource(parameters[0])
294
286
  elsif parameters.size != 2
295
- raise_invalid_parameters_error("Resource", "1 or 2", parameters.size)
287
+ raise_invalid_parameters_error('Resource', '1 or 2', parameters.size)
296
288
  else
297
289
  TYPES.resource(parameters[0], parameters[1])
298
290
  end
299
291
 
300
- when "regexp"
292
+ when 'regexp'
301
293
  # 1 parameter being a string, or regular expression
302
- raise_invalid_parameters_error("Regexp", "1", parameters.size) unless parameters.size == 1
294
+ raise_invalid_parameters_error('Regexp', '1', parameters.size) unless parameters.size == 1
303
295
  TYPES.regexp(parameters[0])
304
296
 
305
- when "enum"
297
+ when 'enum'
306
298
  # 1..m parameters being strings
307
- raise_invalid_parameters_error("Enum", "1 or more", parameters.size) unless parameters.size >= 1
299
+ raise_invalid_parameters_error('Enum', '1 or more', parameters.size) unless parameters.size >= 1
308
300
  TYPES.enum(*parameters)
309
301
 
310
- when "pattern"
302
+ when 'pattern'
311
303
  # 1..m parameters being strings or regular expressions
312
- raise_invalid_parameters_error("Pattern", "1 or more", parameters.size) unless parameters.size >= 1
304
+ raise_invalid_parameters_error('Pattern', '1 or more', parameters.size) unless parameters.size >= 1
313
305
  TYPES.pattern(*parameters)
314
306
 
315
- when "variant"
307
+ when 'variant'
316
308
  # 1..m parameters being strings or regular expressions
317
- raise_invalid_parameters_error("Variant", "1 or more", parameters.size) unless parameters.size >= 1
309
+ raise_invalid_parameters_error('Variant', '1 or more', parameters.size) unless parameters.size >= 1
318
310
  TYPES.variant(*parameters)
319
311
 
320
- when "tuple"
312
+ when 'tuple'
321
313
  # 1..m parameters being types (last two optionally integer or literal default
322
- raise_invalid_parameters_error("Tuple", "1 or more", parameters.size) unless parameters.size >= 1
314
+ raise_invalid_parameters_error('Tuple', '1 or more', parameters.size) unless parameters.size >= 1
323
315
  length = parameters.size
316
+ size_type = nil
324
317
  if TYPES.is_range_parameter?(parameters[-2])
325
318
  # min, max specification
326
319
  min = parameters[-2]
@@ -329,30 +322,28 @@ class Puppet::Pops::Types::TypeParser
329
322
  max = parameters[-1]
330
323
  max = max == :default ? nil : max
331
324
  parameters = parameters[0, length-2]
325
+ size_type = TYPES.range(min, max)
332
326
  elsif TYPES.is_range_parameter?(parameters[-1])
333
327
  min = parameters[-1]
334
328
  min = (min == :default || min == 'default') ? 0 : min
335
329
  max = nil
336
330
  parameters = parameters[0, length-1]
331
+ size_type = TYPES.range(min, max)
337
332
  end
338
- t = TYPES.tuple(*parameters)
339
- if min || max
340
- TYPES.constrain_size(t, min, max)
341
- end
342
- t
333
+ TYPES.tuple(parameters, size_type)
343
334
 
344
- when "callable"
335
+ when 'callable'
345
336
  # 1..m parameters being types (last three optionally integer or literal default, and a callable)
346
337
  TYPES.callable(*parameters)
347
338
 
348
- when "struct"
339
+ when 'struct'
349
340
  # 1..m parameters being types (last two optionally integer or literal default
350
- raise_invalid_parameters_error("Struct", "1", parameters.size) unless parameters.size == 1
341
+ raise_invalid_parameters_error('Struct', '1', parameters.size) unless parameters.size == 1
351
342
  h = parameters[0]
352
343
  raise_invalid_type_specification_error unless h.is_a?(Hash)
353
344
  TYPES.struct(h)
354
345
 
355
- when "integer"
346
+ when 'integer'
356
347
  if parameters.size == 1
357
348
  case parameters[0]
358
349
  when Integer
@@ -361,12 +352,12 @@ class Puppet::Pops::Types::TypeParser
361
352
  TYPES.integer # unbound
362
353
  end
363
354
  elsif parameters.size != 2
364
- raise_invalid_parameters_error("Integer", "1 or 2", parameters.size)
355
+ raise_invalid_parameters_error('Integer', '1 or 2', parameters.size)
365
356
  else
366
357
  TYPES.range(parameters[0] == :default ? nil : parameters[0], parameters[1] == :default ? nil : parameters[1])
367
358
  end
368
359
 
369
- when "float"
360
+ when 'float'
370
361
  if parameters.size == 1
371
362
  case parameters[0]
372
363
  when Integer, Float
@@ -375,17 +366,17 @@ class Puppet::Pops::Types::TypeParser
375
366
  TYPES.float # unbound
376
367
  end
377
368
  elsif parameters.size != 2
378
- raise_invalid_parameters_error("Float", "1 or 2", parameters.size)
369
+ raise_invalid_parameters_error('Float', '1 or 2', parameters.size)
379
370
  else
380
371
  TYPES.float_range(parameters[0] == :default ? nil : parameters[0], parameters[1] == :default ? nil : parameters[1])
381
372
  end
382
373
 
383
- when "string"
374
+ when 'string'
384
375
  size_type =
385
376
  case parameters.size
386
377
  when 1
387
378
  if parameters[0].is_a?(Puppet::Pops::Types::PIntegerType)
388
- parameters[0].copy
379
+ parameters[0]
389
380
  else
390
381
  assert_range_parameter(parameters[0])
391
382
  TYPES.range(parameters[0], :default)
@@ -395,24 +386,22 @@ class Puppet::Pops::Types::TypeParser
395
386
  assert_range_parameter(parameters[1])
396
387
  TYPES.range(parameters[0], parameters[1])
397
388
  else
398
- raise_invalid_parameters_error("String", "1 to 2", parameters.size)
389
+ raise_invalid_parameters_error('String', '1 to 2', parameters.size)
399
390
  end
400
- result = TYPES.string
401
- result.size_type = size_type
402
- result
391
+ TYPES.string(size_type)
403
392
 
404
- when "optional"
393
+ when 'optional'
405
394
  if parameters.size != 1
406
- raise_invalid_parameters_error("Optional", 1, parameters.size)
395
+ raise_invalid_parameters_error('Optional', 1, parameters.size)
407
396
  end
408
397
  param = parameters[0]
409
398
  assert_type(param) unless param.is_a?(String)
410
399
  TYPES.optional(param)
411
400
 
412
- when "any", "data", "catalogentry", "boolean", "scalar", "undef", "numeric", "default"
401
+ when 'any', 'data', 'catalogentry', 'boolean', 'scalar', 'undef', 'numeric', 'default'
413
402
  raise_unparameterized_type_error(parameterized_ast.left_expr)
414
403
 
415
- when "notundef"
404
+ when 'notundef'
416
405
  case parameters.size
417
406
  when 0
418
407
  TYPES.not_undef
@@ -424,15 +413,15 @@ class Puppet::Pops::Types::TypeParser
424
413
  raise_invalid_parameters_error("NotUndef", "0 to 1", parameters.size)
425
414
  end
426
415
 
427
- when "type"
416
+ when 'type'
428
417
  if parameters.size != 1
429
- raise_invalid_parameters_error("Type", 1, parameters.size)
418
+ raise_invalid_parameters_error('Type', 1, parameters.size)
430
419
  end
431
420
  assert_type(parameters[0])
432
421
  TYPES.type_type(parameters[0])
433
422
 
434
- when "runtime"
435
- raise_invalid_parameters_error("Runtime", "2", parameters.size) unless parameters.size == 2
423
+ when 'runtime'
424
+ raise_invalid_parameters_error('Runtime', '2', parameters.size) unless parameters.size == 2
436
425
  TYPES.runtime(*parameters)
437
426
 
438
427
  else
@@ -476,6 +465,6 @@ class Puppet::Pops::Types::TypeParser
476
465
 
477
466
  def original_text_of(ast)
478
467
  position = Puppet::Pops::Adapters::SourcePosAdapter.adapt(ast)
479
- position.extract_text()
468
+ position.extract_text
480
469
  end
481
470
  end
@@ -1,415 +1,1554 @@
1
1
  require 'rgen/metamodel_builder'
2
2
 
3
3
  # The Types model is a model of Puppet Language types.
4
- # It consists of two parts; the meta-model expressed using RGen (in types_meta.rb) and this file which
5
- # mixes in the implementation.
4
+ #
5
+ # The exact relationship between types is not visible in this model wrt. the PDataType which is an abstraction
6
+ # of Scalar, Array[Data], and Hash[Scalar, Data] nested to any depth. This means it is not possible to
7
+ # infer the type by simply looking at the inheritance hierarchy. The {Puppet::Pops::Types::TypeCalculator} should
8
+ # be used to answer questions about types. The {Puppet::Pops::Types::TypeFactory} should be used to create an instance
9
+ # of a type whenever one is needed.
10
+ #
11
+ # The implementation of the Types model contains methods that are required for the type objects to behave as
12
+ # expected when comparing them and using them as keys in hashes. (No other logic is, or should be included directly in
13
+ # the model's classes).
6
14
  #
7
15
  # @api public
8
16
  #
9
17
  module Puppet::Pops
10
- require 'puppet/pops/types/types_meta'
11
-
12
18
  # TODO: See PUP-2978 for possible performance optimization
13
-
14
- # Mix in implementation part of the Bindings Module
15
19
  module Types
16
- class TypeModelObject < RGen::MetamodelBuilder::MMBase
20
+ class TypedModelObject < Object
17
21
  include Puppet::Pops::Visitable
18
22
  include Puppet::Pops::Adaptable
19
- include Puppet::Pops::Containment
20
23
  end
21
24
 
22
- class PAnyType < TypeModelObject
23
- module ClassModule
24
- # Produce a deep copy of the type
25
- def copy
26
- Marshal.load(Marshal.dump(self))
25
+ # Base type for all types
26
+ # @api public
27
+ #
28
+ class PAnyType < TypedModelObject
29
+ # Checks if _o_ is a type that is assignable to this type.
30
+ # If _o_ is a `Class` then it is first converted to a type.
31
+ # If _o_ is a Variant, then it is considered assignable when all its types are assignable
32
+ # @return [Boolean] `true` when _o_ is assignable to this type
33
+ # @api public
34
+ def assignable?(o)
35
+ case o
36
+ when Class
37
+ # Safe to call _assignable directly since a Class never is a Unit or Variant
38
+ _assignable?(Puppet::Pops::Types::TypeCalculator.singleton.type(o))
39
+ when PUnitType
40
+ true
41
+ when PVariantType
42
+ # Assignable if all contained types are assignable
43
+ o.types.all? { |vt| assignable?(vt) }
44
+ when PNotUndefType
45
+ if !(o.type.nil? || o.type.assignable?(PUndefType::DEFAULT))
46
+ assignable?(o.type)
47
+ else
48
+ _assignable?(o)
49
+ end
50
+ else
51
+ _assignable?(o)
27
52
  end
53
+ end
54
+
55
+ # Returns `true` if this instance is a callable that accepts the given _args_
56
+ #
57
+ # @return [Boolean]
58
+ def callable?(args)
59
+ args.is_a?(PAnyType) && kind_of_callable? && args.callable_args?(self)
60
+ end
61
+
62
+ # Returns `true` if this instance is considered valid as arguments to _callable_
63
+ # @return [Boolean]
64
+ # @api private
65
+ def callable_args?(callable)
66
+ false
67
+ end
68
+
69
+ # Subclasses that are enumerable will override this method to return `true`
70
+ # @return [Boolean] false#
71
+ def enumerable?
72
+ is_a?(Enumerable)
73
+ end
74
+
75
+ # Generalizes value specific types. Types that are not value specific will return `self` otherwize
76
+ # the generalized type is returned.
77
+ #
78
+ # @return [PAnyType] The generalized type
79
+ # @api public
80
+ def generalize
81
+ # Applicable to all types that have no variables
82
+ self
83
+ end
84
+
85
+ # Responds `true` for all callables, variants of callables and unless _optional_ is
86
+ # false, all optional callables.
87
+ # @return [Boolean] `true`if this type is considered callable
88
+ # @api private
89
+ def kind_of_callable?(optional=true)
90
+ false
91
+ end
92
+
93
+ def hash
94
+ self.class.hash
95
+ end
96
+
97
+ # Returns true if the given argument _o_ is an instance of this type
98
+ # @return [Boolean]
99
+ def instance?(o)
100
+ true
101
+ end
102
+
103
+ def ==(o)
104
+ self.class == o.class
105
+ end
106
+
107
+ alias eql? ==
108
+
109
+ # Strips the class name from all module prefixes, the leading 'P' and the ending 'Type'. I.e.
110
+ # an instance of Puppet::Pops::Types::PVariantType will return 'Variant'
111
+ # @return [String] the simple name of this type
112
+ def simple_name
113
+ n = self.class.name
114
+ n[n.rindex('::')+3..n.size-5]
115
+ end
116
+
117
+ def to_s
118
+ Puppet::Pops::Types::TypeCalculator.string(self)
119
+ end
120
+
121
+ # The default instance of this type. Each type in the type system has this constant
122
+ # declared.
123
+ #
124
+ DEFAULT = PAnyType.new
125
+
126
+ protected
127
+
128
+ # @api private
129
+ def _assignable?(o)
130
+ o.is_a?(PAnyType)
131
+ end
28
132
 
29
- def hash
30
- self.class.hash
133
+ NAME_SEGMENT_SEPARATOR = '::'.freeze
134
+
135
+ # @api private
136
+ def class_from_string(str)
137
+ begin
138
+ str.split(NAME_SEGMENT_SEPARATOR).reduce(Object) do |memo, name_segment|
139
+ memo.const_get(name_segment)
140
+ end
141
+ rescue NameError
142
+ return nil
31
143
  end
144
+ end
32
145
 
33
- def ==(o)
34
- self.class == o.class
146
+ # Produces the tuple entry at the given index given a tuple type, its from/to constraints on the last
147
+ # type, and an index.
148
+ # Produces nil if the index is out of bounds
149
+ # from must be less than to, and from may not be less than 0
150
+ #
151
+ # @api private
152
+ #
153
+ def tuple_entry_at(tuple_t, from, to, index)
154
+ regular = (tuple_t.types.size - 1)
155
+ if index < regular
156
+ tuple_t.types[index]
157
+ elsif index < regular + to
158
+ # in the varargs part
159
+ tuple_t.types[-1]
160
+ else
161
+ nil
35
162
  end
163
+ end
36
164
 
37
- alias eql? ==
38
165
 
39
- def to_s
40
- Puppet::Pops::Types::TypeCalculator.string(self)
166
+ # Transform size_type to min, max
167
+ # if size_type == nil the constraint is 1,1
168
+ # if size_type.from == nil min size = 1
169
+ # if size_type.to == nil max size == Infinity
170
+ #
171
+ # @api private
172
+ def type_to_range(size_type)
173
+ return [1,1] if size_type.nil?
174
+ from = size_type.from
175
+ to = size_type.to
176
+ [from.nil? ? 1 : from, to.nil? ? Float::INFINITY : to]
177
+ end
178
+ end
179
+
180
+ # The type of types.
181
+ # @api public
182
+ #
183
+ class PType < PAnyType
184
+ attr_reader :type
185
+
186
+ def initialize(type)
187
+ @type = type
188
+ end
189
+
190
+ def instance?(o)
191
+ if o.is_a?(PAnyType)
192
+ type.nil? || type.assignable?(o)
193
+ else
194
+ assignable?(TypeCalculator.infer(o))
41
195
  end
42
196
  end
197
+
198
+ def generalize
199
+ @type.nil? ? DEFAULT : PType.new(type.generalize)
200
+ end
201
+
202
+ def hash
203
+ 31 * @type.hash
204
+ end
205
+
206
+ def ==(o)
207
+ self.class == o.class && @type == o.type
208
+ end
209
+
210
+ def simple_name
211
+ # since this the class is inconsistently named PType and not PTypeType
212
+ 'Type'
213
+ end
214
+
215
+ DEFAULT = PType.new(nil)
216
+
217
+ protected
218
+
219
+ # @api private
220
+ def _assignable?(o)
221
+ return false unless o.is_a?(PType)
222
+ return true if @type.nil? # wide enough to handle all types
223
+ return false if o.type.nil? # wider than t
224
+ @type.assignable?(o.type)
225
+ end
43
226
  end
44
227
 
45
228
  class PNotUndefType < PAnyType
46
- module ClassModule
47
- def hash
48
- [self.class, type].hash
49
- end
229
+ attr_reader :type
50
230
 
51
- def ==(o)
52
- self.class == o.class && type == o.type
53
- end
231
+ def initialize(type = nil)
232
+ @type = type.class == PAnyType ? nil : type
233
+ end
234
+
235
+ def instance?(o)
236
+ !(o.nil? || o == :undef) && (@type.nil? || @type.instance?(o))
237
+ end
238
+
239
+ def generalize
240
+ @type.nil? ? DEFAULT : PNotUndefType.new(type.generalize)
241
+ end
242
+
243
+ def hash
244
+ 31 * @type.hash
245
+ end
246
+
247
+ def ==(o)
248
+ self.class == o.class && @type == o.type
249
+ end
250
+
251
+ DEFAULT = PNotUndefType.new
252
+
253
+ protected
254
+
255
+ # @api private
256
+ def _assignable?(o)
257
+ o.is_a?(PAnyType) && !o.assignable?(PUndefType::DEFAULT) && (@type.nil? || @type.assignable?(o))
54
258
  end
55
259
  end
56
260
 
57
- class PType < PAnyType
58
- module ClassModule
59
- def hash
60
- [self.class, type].hash
61
- end
261
+ # @api public
262
+ #
263
+ class PUndefType < PAnyType
264
+ def instance?(o)
265
+ o.nil? || o == :undef
266
+ end
62
267
 
63
- def ==(o)
64
- self.class == o.class && type == o.type
65
- end
268
+ # @api private
269
+ def callable_args?(callable_t)
270
+ # if callable_t is Optional (or indeed PUndefType), this means that 'missing callable' is accepted
271
+ callable_t.assignable?(DEFAULT)
272
+ end
273
+
274
+ DEFAULT = PUndefType.new
275
+
276
+ protected
277
+ # @api private
278
+ def _assignable?(o)
279
+ o.is_a?(PUndefType)
280
+ end
281
+ end
282
+
283
+ # A type private to the type system that describes "ignored type" - i.e. "I am what you are"
284
+ # @api private
285
+ #
286
+ class PUnitType < PAnyType
287
+ def instance?(o)
288
+ true
289
+ end
290
+
291
+ DEFAULT = PUnitType.new
292
+
293
+ protected
294
+ # @api private
295
+ def _assignable?(o)
296
+ true
297
+ end
298
+ end
299
+
300
+ # @api public
301
+ #
302
+ class PDefaultType < PAnyType
303
+ def instance?(o)
304
+ o == :default
305
+ end
306
+
307
+ DEFAULT = PDefaultType.new
308
+
309
+ protected
310
+ # @api private
311
+ def _assignable?(o)
312
+ o.is_a?(PDefaultType)
66
313
  end
67
314
  end
68
315
 
316
+ # A flexible data type, being assignable to its subtypes as well as PArrayType and PHashType with element type assignable to PDataType.
317
+ #
318
+ # @api public
319
+ #
69
320
  class PDataType < PAnyType
70
- module ClassModule
71
- def ==(o)
72
- self.class == o.class ||
73
- o.class == PVariantType && o == Puppet::Pops::Types::TypeCalculator.data_variant()
321
+ def ==(o)
322
+ self.class == o.class || o.class == PVariantType && o == PVariantType::DATA
323
+ end
324
+
325
+ def instance?(o)
326
+ PVariantType::DATA.instance?(o)
327
+ end
328
+
329
+ DEFAULT = PDataType.new
330
+
331
+ protected
332
+
333
+ # Data is assignable by other Data and by Array[Data] and Hash[Scalar, Data]
334
+ # @api private
335
+ def _assignable?(o)
336
+ # We cannot put the NotUndefType[Data] in the @data_variant_t since that causes an endless recursion
337
+ case o
338
+ when Types::PDataType
339
+ true
340
+ when Types::PNotUndefType
341
+ assignable?(o.type || PUndefType::DEFAULT)
342
+ else
343
+ PVariantType::DATA.assignable?(o)
74
344
  end
75
345
  end
76
346
  end
77
347
 
78
- class PVariantType < PAnyType
79
- module ClassModule
348
+ # Type that is PDataType compatible, but is not a PCollectionType.
349
+ # @api public
350
+ #
351
+ class PScalarType < PAnyType
80
352
 
81
- def hash
82
- [self.class, Set.new(self.types)].hash
83
- end
353
+ def instance?(o)
354
+ assignable?(TypeCalculator.infer(o))
355
+ end
84
356
 
85
- def ==(o)
86
- (self.class == o.class && Set.new(types) == Set.new(o.types)) ||
87
- (o.class == PDataType && self == Puppet::Pops::Types::TypeCalculator.data_variant())
88
- end
357
+ DEFAULT = PScalarType.new
358
+
359
+ protected
360
+
361
+ # @api private
362
+ def _assignable?(o)
363
+ o.is_a?(PScalarType)
89
364
  end
90
365
  end
91
366
 
367
+ # A string type describing the set of strings having one of the given values
368
+ # @api public
369
+ #
92
370
  class PEnumType < PScalarType
93
- module ClassModule
94
- def hash
95
- [self.class, Set.new(self.values)].hash
96
- end
371
+ include Enumerable
97
372
 
98
- def ==(o)
99
- self.class == o.class && Set.new(values) == Set.new(o.values)
100
- end
373
+ attr_reader :values
374
+
375
+ def initialize(values)
376
+ @values = values.sort.freeze
101
377
  end
102
- end
103
378
 
104
- class PIntegerType < PNumericType
105
- module ClassModule
106
- # The integer type is enumerable when it defines a range
107
- include Enumerable
108
-
109
- # Returns Float.Infinity if one end of the range is unbound
110
- def size
111
- return Float::INFINITY if from.nil? || to.nil?
112
- 1+(to-from).abs
113
- end
114
-
115
- # Returns the range as an array ordered so the smaller number is always first.
116
- # The number may be Infinity or -Infinity.
117
- def range
118
- f = from || -Float::INFINITY
119
- t = to || Float::INFINITY
120
- if f < t
121
- [f, t]
122
- else
123
- [t,f]
124
- end
379
+ # Returns Enumerator if no block is given, otherwise, calls the given
380
+ # block with each of the strings for this enum
381
+ def each
382
+ if block_given?
383
+ values.each { |x| yield x }
384
+ else
385
+ values.to_enum
125
386
  end
387
+ end
126
388
 
127
- # Returns Enumerator if no block is given
128
- # Returns self if size is infinity (does not yield)
129
- def each
130
- return self.to_enum unless block_given?
131
- return nil if from.nil? || to.nil?
132
- if to < from
133
- from.downto(to) {|x| yield x }
389
+ def hash
390
+ @values.hash
391
+ end
392
+
393
+ def ==(o)
394
+ self.class == o.class && @values == o.values
395
+ end
396
+
397
+ DEFAULT = PEnumType.new([])
398
+
399
+ protected
400
+
401
+ # @api private
402
+ def _assignable?(o)
403
+ return true if self == o
404
+ svalues = values
405
+ if svalues.empty?
406
+ return true if o.is_a?(PStringType) || o.is_a?(PEnumType) || o.is_a?(PPatternType)
407
+ end
408
+ case o
409
+ when PStringType
410
+ # if the set of strings are all found in the set of enums
411
+ !o.values.empty? && o.values.all? { |s| svalues.any? { |e| e == s }}
412
+ when PEnumType
413
+ !o.values.empty? && o.values.all? { |s| svalues.any? {|e| e == s }}
134
414
  else
135
- from.upto(to) {|x| yield x }
136
- end
415
+ false
137
416
  end
417
+ end
418
+ end
138
419
 
139
- def hash
140
- [self.class, from, to].hash
420
+ # @api public
421
+ #
422
+ class PNumericType < PScalarType
423
+ def initialize(from, to = Float::INFINITY)
424
+ from = -Float::INFINITY if from.nil? || from == :default
425
+ to = Float::INFINITY if to.nil? || to == :default
426
+
427
+ # Always create in right order
428
+ if from <= to
429
+ @from = from
430
+ @to = to
431
+ else
432
+ @to = from
433
+ @from = to
141
434
  end
435
+ end
436
+
437
+ # Returns the lower bound of the numeric range or `nil` if no lower bound is set.
438
+ # @return [Float,Integer]
439
+ def from
440
+ @from == -Float::INFINITY ? nil : @from
441
+ end
442
+
443
+ # Returns the upper bound of the numeric range or `nil` if no upper bound is set.
444
+ # @return [Float,Integer]
445
+ def to
446
+ @to == Float::INFINITY ? nil : @to
447
+ end
448
+
449
+ # Same as #from but will return `-Float::Infinity` instead of `nil` if no lower bound is set.
450
+ # @return [Float,Integer]
451
+ def numeric_from
452
+ @from
453
+ end
454
+
455
+ # Same as #to but will return `Float::Infinity` instead of `nil` if no lower bound is set.
456
+ # @return [Float,Integer]
457
+ def numeric_to
458
+ @to
459
+ end
460
+
461
+ def hash
462
+ @from.hash * 31 + @to.hash
463
+ end
464
+
465
+ def ==(o)
466
+ self.class == o.class && @from == o.numeric_from && @to == o.numeric_to
467
+ end
468
+
469
+ def instance?(o)
470
+ o.is_a?(Numeric) && o >= @from && o <= @to
471
+ end
472
+
473
+ def unbounded?
474
+ @from == -Float::INFINITY && @to == Float::INFINITY
475
+ end
476
+
477
+ DEFAULT = PNumericType.new(-Float::INFINITY)
478
+
479
+ protected
480
+
481
+ # @api_private
482
+ def _assignable?(o)
483
+ return false unless o.is_a?(self.class)
484
+ # If o min and max are within the range of t
485
+ @from <= o.numeric_from && @to >= o.numeric_to
486
+ end
487
+ end
488
+
489
+ # @api public
490
+ #
491
+ class PIntegerType < PNumericType
492
+ # The integer type is enumerable when it defines a range
493
+ include Enumerable
494
+
495
+ def enumerable?
496
+ @from != -Float::INFINITY && @to != Float::INFINITY
497
+ end
498
+
499
+ def generalize
500
+ DEFAULT
501
+ end
502
+
503
+ def instance?(o)
504
+ o.is_a?(Integer) && o >= numeric_from && o <= numeric_to
505
+ end
506
+
507
+ # Returns Float.Infinity if one end of the range is unbound
508
+ def size
509
+ return Float::INFINITY if @from == -Float::INFINITY || @to == Float::INFINITY
510
+ 1+(to-from).abs
511
+ end
512
+
513
+ # Returns the range as an array ordered so the smaller number is always first.
514
+ # The number may be Infinity or -Infinity.
515
+ def range
516
+ [@from, @to]
517
+ end
142
518
 
143
- def ==(o)
144
- self.class == o.class && from == o.from && to == o.to
519
+ # Returns Enumerator if no block is given
520
+ # Returns nil if size is infinity (does not yield)
521
+ def each
522
+ if block_given?
523
+ enumerable? ? @from.upto(@to) { |x| yield x } : nil
524
+ else
525
+ to_enum
145
526
  end
146
527
  end
528
+
529
+ # Returns a range where both to and from are positive numbers. Negative
530
+ # numbers are converted to zero
531
+ # @return [PIntegerType] a positive range
532
+ def to_size
533
+ @from >= 0 ? self : PIntegerType.new(0, @to < 0 ? 0 : @to)
534
+ end
535
+
536
+ DEFAULT = PIntegerType.new(-Float::INFINITY)
147
537
  end
148
538
 
539
+ # @api public
540
+ #
149
541
  class PFloatType < PNumericType
150
- module ClassModule
151
- def hash
152
- [self.class, from, to].hash
153
- end
542
+ def generalize
543
+ DEFAULT
544
+ end
545
+
546
+ def instance?(o)
547
+ o.is_a?(Float) && o >= numeric_from && o <= numeric_to
548
+ end
549
+
550
+ DEFAULT = PFloatType.new(-Float::INFINITY)
551
+ end
552
+
553
+ # @api public
554
+ #
555
+ class PCollectionType < PAnyType
556
+ attr_reader :element_type, :size_type
557
+
558
+ def initialize(element_type, size_type = nil)
559
+ @element_type = element_type
560
+ @size_type = size_type
561
+ end
154
562
 
155
- def ==(o)
156
- self.class == o.class && from == o.from && to == o.to
563
+ def generalize
564
+ @element_type.nil? ? DEFAULT : PCollectionType.new(element_type.generalize, nil)
565
+ end
566
+
567
+ def instance?(o)
568
+ assignable?(TypeCalculator.infer(o))
569
+ end
570
+
571
+ # Returns an array with from (min) size to (max) size
572
+ def size_range
573
+ (@size_type || DEFAULT_SIZE).range
574
+ end
575
+
576
+ def hash
577
+ @element_type.hash * 31 + @size_type.hash
578
+ end
579
+
580
+ def ==(o)
581
+ self.class == o.class && @element_type == o.element_type && @size_type == o.size_type
582
+ end
583
+
584
+
585
+ DEFAULT_SIZE = PIntegerType.new(0)
586
+ ZERO_SIZE = PIntegerType.new(0, 0)
587
+ DEFAULT = PCollectionType.new(nil)
588
+
589
+ protected
590
+
591
+ # @api private
592
+ #
593
+ def _assignable?(o)
594
+ case o
595
+ when PCollectionType
596
+ (@size_type || DEFAULT_SIZE).assignable?(o.size_type || DEFAULT_SIZE)
597
+ when PTupleType
598
+ # compute the tuple's min/max size, and check if that size matches
599
+ from, to = type_to_range(o.size_type)
600
+ from = o.types.size - 1 + from
601
+ to = o.types.size - 1 + to
602
+ (@size_type || DEFAULT_SIZE).assignable?(PIntegerType.new(from, to))
603
+ when PStructType
604
+ from = to = o.elements.size
605
+ (@size_type || DEFAULT_SIZE).assignable?(PIntegerType.new(from, to))
606
+ else
607
+ false
157
608
  end
158
609
  end
159
610
  end
160
611
 
612
+ # @api public
613
+ #
161
614
  class PStringType < PScalarType
162
- module ClassModule
615
+ attr_reader :size_type, :values
163
616
 
164
- def hash
165
- [self.class, self.size_type, Set.new(self.values)].hash
617
+ def generalize
618
+ DEFAULT
619
+ end
620
+
621
+ def initialize(size_type, values = [])
622
+ @size_type = size_type
623
+ @values = values.sort.freeze
624
+ end
625
+
626
+ def hash
627
+ @size_type.hash * 31 + @values.hash
628
+ end
629
+
630
+ def ==(o)
631
+ self.class == o.class && @size_type == o.size_type && @values == o.values
632
+ end
633
+
634
+ def instance?(o)
635
+ # true if size compliant
636
+ if o.is_a?(String) && (@size_type.nil? || @size_type.instance?(o.size))
637
+ @values.empty? || @values.include?(o)
638
+ else
639
+ false
166
640
  end
641
+ end
167
642
 
168
- def ==(o)
169
- self.class == o.class && self.size_type == o.size_type && Set.new(values) == Set.new(o.values)
643
+ DEFAULT = PStringType.new(nil)
644
+ NON_EMPTY = PStringType.new(PIntegerType.new(1))
645
+
646
+ protected
647
+
648
+ # @api private
649
+ def _assignable?(o)
650
+ if values.empty?
651
+ # A general string is assignable by any other string or pattern restricted string
652
+ # if the string has a size constraint it does not match since there is no reasonable way
653
+ # to compute the min/max length a pattern will match. For enum, it is possible to test that
654
+ # each enumerator value is within range
655
+ case o
656
+ when PStringType
657
+ # true if size compliant
658
+ (@size_type || PCollectionType::DEFAULT_SIZE).assignable?(o.size_type || PCollectionType::DEFAULT_SIZE)
659
+
660
+ when PPatternType
661
+ # true if size constraint is at least 0 to +Infinity (which is the same as the default)
662
+ @size_type.nil? || @size_type.assignable?(PCollectionType::DEFAULT_SIZE)
663
+
664
+ when PEnumType
665
+ if o.values.empty?
666
+ # enum represents all enums, and thus all strings, a sized constrained string can thus not
667
+ # be assigned any enum (unless it is max size).
668
+ @size_type.nil? || @size_type.assignable?(PCollectionType::DEFAULT_SIZE)
669
+ else
670
+ # true if all enum values are within range
671
+ orange = o.values.map(&:size).minmax
672
+ srange = (@size_type || PCollectionType::DEFAULT_SIZE).range
673
+ # If o min and max are within the range of t
674
+ srange[0] <= orange[0] && srange[1] >= orange[1]
675
+ end
676
+ else
677
+ # no other type matches string
678
+ false
679
+ end
680
+ elsif o.is_a?(PStringType)
681
+ # A specific string acts as a set of strings - must have exactly the same strings
682
+ # In this case, size does not matter since the definition is very precise anyway
683
+ values == o.values
684
+ else
685
+ # All others are false, since no other type describes the same set of specific strings
686
+ false
170
687
  end
171
688
  end
172
689
  end
173
690
 
691
+ # @api public
692
+ #
174
693
  class PRegexpType < PScalarType
175
- module ClassModule
176
- def regexp_derived
177
- pattern_or_blank = pattern || ''
178
- @_regexp = Regexp.new(pattern_or_blank) unless @_regexp && @_regexp.source == pattern_or_blank
179
- @_regexp
180
- end
694
+ attr_reader :pattern
181
695
 
182
- def hash
183
- [self.class, pattern].hash
184
- end
696
+ def initialize(pattern)
697
+ @pattern = pattern
698
+ end
185
699
 
186
- def ==(o)
187
- self.class == o.class && pattern == o.pattern
188
- end
700
+ def regexp
701
+ @regexp ||= Regexp.new(@pattern || '')
702
+ end
703
+
704
+ def hash
705
+ @pattern.hash
706
+ end
707
+
708
+ def ==(o)
709
+ self.class == o.class && @pattern == o.pattern
710
+ end
711
+
712
+ DEFAULT = PRegexpType.new(nil)
713
+
714
+ protected
715
+
716
+ # @api private
717
+ #
718
+ def _assignable?(o)
719
+ o.is_a?(PRegexpType) && (@pattern.nil? || @pattern == o.pattern)
189
720
  end
190
721
  end
191
722
 
723
+ # Represents a subtype of String that narrows the string to those matching the patterns
724
+ # If specified without a pattern it is basically the same as the String type.
725
+ #
726
+ # @api public
727
+ #
192
728
  class PPatternType < PScalarType
193
- module ClassModule
729
+ attr_reader :patterns
194
730
 
195
- def hash
196
- [self.class, Set.new(patterns)].hash
197
- end
731
+ def initialize(patterns)
732
+ @patterns = patterns.freeze
733
+ end
198
734
 
199
- def ==(o)
200
- self.class == o.class && Set.new(patterns) == Set.new(o.patterns)
201
- end
735
+ def hash
736
+ @patterns.hash
202
737
  end
203
- end
204
738
 
205
- class PCollectionType < PAnyType
206
- module ClassModule
207
- # Returns an array with from (min) size to (max) size
208
- def size_range
209
- return [0, Float::INFINITY] if size_type.nil?
210
- f = size_type.from || 0
211
- t = size_type.to || Float::INFINITY
212
- if f < t
213
- [f, t]
739
+ def ==(o)
740
+ self.class == o.class && (@patterns | o.patterns).size == @patterns.size
741
+ end
742
+
743
+ DEFAULT = PPatternType.new([])
744
+
745
+ protected
746
+
747
+ # @api private
748
+ #
749
+ def _assignable?(o)
750
+ return true if self == o
751
+ case o
752
+ when PStringType, PEnumType
753
+ if o.values.empty?
754
+ # Strings / Enums (unknown which ones) cannot all match a pattern, but if there is no pattern it is ok
755
+ # (There should really always be a pattern, but better safe than sorry).
756
+ @patterns.empty?
214
757
  else
215
- [t,f]
758
+ # all strings in String/Enum type must match one of the patterns in Pattern type,
759
+ # or Pattern represents all Patterns == all Strings
760
+ regexps = @patterns.map { |p| p.regexp }
761
+ regexps.empty? || o.values.all? { |v| regexps.any? {|re| re.match(v) } }
216
762
  end
763
+ when PPatternType
764
+ @patterns.empty?
765
+ else
766
+ false
217
767
  end
768
+ end
769
+ end
218
770
 
219
- def hash
220
- [self.class, element_type, size_type].hash
221
- end
771
+ # @api public
772
+ #
773
+ class PBooleanType < PScalarType
222
774
 
223
- def ==(o)
224
- self.class == o.class && element_type == o.element_type && size_type == o.size_type
225
- end
775
+ def instance?(o)
776
+ o == true || o == false
226
777
  end
227
- end
228
778
 
229
- class PStructElement < TypeModelObject
230
- module ClassModule
231
- def hash
232
- [self.class, value_type, key_type].hash
233
- end
779
+ DEFAULT = PBooleanType.new
234
780
 
235
- def name
236
- k = key_type
237
- k = k.optional_type if k.is_a?(POptionalType)
238
- k.values[0]
239
- end
781
+ protected
240
782
 
241
- def ==(o)
242
- self.class == o.class && value_type == o.value_type && key_type == o.key_type
243
- end
783
+ # @api private
784
+ #
785
+ def _assignable?(o)
786
+ o.is_a?(PBooleanType)
244
787
  end
245
788
  end
246
789
 
790
+ # @api public
791
+ #
792
+ # @api public
793
+ #
794
+ class PStructElement < TypedModelObject
795
+ attr_accessor :key_type, :value_type
796
+
797
+ def hash
798
+ value_type.hash * 31 + key_type.hash
799
+ end
800
+
801
+ def name
802
+ k = key_type
803
+ k = k.optional_type if k.is_a?(POptionalType)
804
+ k.values[0]
805
+ end
806
+
807
+ def initialize(key_type, value_type)
808
+ @key_type = key_type
809
+ @value_type = value_type
810
+ end
811
+
812
+ def generalize
813
+ PStructElement.new(@key_type, @value_type.generalize)
814
+ end
815
+
816
+ def <=>(o)
817
+ self.name <=> o.name
818
+ end
819
+
820
+ def ==(o)
821
+ self.class == o.class && value_type == o.value_type && key_type == o.key_type
822
+ end
823
+ end
247
824
 
825
+ # @api public
826
+ #
248
827
  class PStructType < PAnyType
249
- module ClassModule
250
- def hashed_elements_derived
251
- @_hashed ||= elements.reduce({}) {|memo, e| memo[e.name] = e; memo }
252
- @_hashed
253
- end
828
+ include Enumerable
254
829
 
255
- def clear_hashed_elements
256
- @_hashed = nil
257
- end
830
+ def initialize(elements)
831
+ @elements = elements.sort.freeze
832
+ end
258
833
 
259
- def hash
260
- [self.class, Set.new(elements)].hash
834
+ def each
835
+ if block_given?
836
+ elements.each { |elem| yield elem }
837
+ else
838
+ elements.to_enum
261
839
  end
840
+ end
262
841
 
263
- def ==(o)
264
- self.class == o.class && hashed_elements == o.hashed_elements
842
+ def generalize
843
+ @elements.empty? ? DEFAULT : PStructType.new(@elements.map { |se| se.generalize })
844
+ end
845
+
846
+ def hashed_elements
847
+ @hashed ||= @elements.reduce({}) {|memo, e| memo[e.name] = e; memo }
848
+ end
849
+
850
+ def hash
851
+ @elements.hash
852
+ end
853
+
854
+ def ==(o)
855
+ self.class == o.class && @elements == o.elements
856
+ end
857
+
858
+ def elements
859
+ @elements
860
+ end
861
+
862
+ def instance?(o)
863
+ return false unless o.is_a?(Hash)
864
+ matched = 0
865
+ @elements.all? do |e|
866
+ key = e.name
867
+ v = o[key]
868
+ if v.nil? && !o.include?(key)
869
+ # Entry is missing. Only OK when key is optional
870
+ e.key_type.assignable?(PUndefType::DEFAULT)
871
+ else
872
+ matched += 1
873
+ e.value_type.instance?(v)
874
+ end
875
+ end && matched == o.size
876
+ end
877
+
878
+ DEFAULT = PStructType.new([])
879
+
880
+ protected
881
+
882
+ # @api private
883
+ def _assignable?(o)
884
+ if o.is_a?(Types::PStructType)
885
+ h2 = o.hashed_elements
886
+ matched = 0
887
+ elements.all? do |e1|
888
+ e2 = h2[e1.name]
889
+ if e2.nil?
890
+ e1.key_type.assignable?(PUndefType::DEFAULT)
891
+ else
892
+ matched += 1
893
+ e1.key_type.assignable?(e2.key_type) && e1.value_type.assignable?(e2.value_type)
894
+ end
895
+ end && matched == h2.size
896
+ elsif o.is_a?(Types::PHashType)
897
+ required = 0
898
+ required_elements_assignable = elements.all? do |e|
899
+ if e.key_type.assignable?(PUndefType::DEFAULT)
900
+ true
901
+ else
902
+ required += 1
903
+ e.value_type.assignable?(o.element_type)
904
+ end
905
+ end
906
+ if required_elements_assignable
907
+ size_o = o.size_type || collection_default_size_t
908
+ PIntegerType.new(required, elements.size).assignable?(size_o)
909
+ end
910
+ else
911
+ false
265
912
  end
266
913
  end
267
914
  end
268
915
 
916
+ # @api public
917
+ #
269
918
  class PTupleType < PAnyType
270
- module ClassModule
271
- # Returns the number of elements accepted [min, max] in the tuple
272
- def size_range
273
- types_size = types.size
274
- size_type.nil? ? [types_size, types_size] : size_type.range
275
- end
276
-
277
- # Returns the number of accepted occurrences [min, max] of the last type in the tuple
278
- # The defaults is [1,1]
279
- #
280
- def repeat_last_range
281
- types_size = types.size
282
- if size_type.nil?
283
- return [1, 1]
919
+ include Enumerable
920
+
921
+ # If set, describes min and max required of the given types - if max > size of
922
+ # types, the last type entry repeats
923
+ #
924
+ attr_reader :size_type
925
+
926
+ attr_reader :types
927
+
928
+ # @api private
929
+ def callable_args?(callable_t)
930
+ unless size_type.nil?
931
+ raise ArgumentError, 'Callable tuple may not have a size constraint when used as args'
932
+ end
933
+
934
+ params_tuple = callable_t.param_types
935
+ param_block_t = callable_t.block_type
936
+ arg_types = @types
937
+ arg_block_t = arg_types.last
938
+ if arg_block_t.kind_of_callable?
939
+ # Can't pass a block to a callable that doesn't accept one
940
+ return false if param_block_t.nil?
941
+
942
+ # Check that the block is of the right tyṕe
943
+ return false unless param_block_t.assignable?(arg_block_t)
944
+
945
+ # Check other arguments
946
+ arg_count = arg_types.size - 1
947
+ params_size_t = params_tuple.size_type || PIntegerType.new(*params_tuple.size_range)
948
+ return false unless params_size_t.assignable?(PIntegerType.new(arg_count, arg_count))
949
+
950
+ ctypes = params_tuple.types
951
+ arg_count.times do |index|
952
+ return false unless (ctypes[index] || ctypes[-1]).assignable?(arg_types[index])
284
953
  end
285
- from, to = size_type.range()
286
- min = from - (types_size-1)
287
- min = min <= 0 ? 0 : min
288
- max = to - (types_size-1)
289
- [min, max]
954
+ return true
290
955
  end
291
956
 
292
- def hash
293
- [self.class, size_type, Set.new(types)].hash
957
+ # Check that tuple is assignable and that the block (if declared) is optional
958
+ params_tuple.assignable?(self) && (param_block_t.nil? || param_block_t.assignable?(PUndefType::DEFAULT))
959
+ end
960
+
961
+ def initialize(types, size_type = nil)
962
+ @types = types
963
+ @size_type = size_type.nil? ? nil : size_type.to_size
964
+ end
965
+
966
+ # Returns Enumerator for the types if no block is given, otherwise, calls the given
967
+ # block with each of the types in this tuple
968
+ def each
969
+ if block_given?
970
+ types.each { |x| yield x }
971
+ else
972
+ types.to_enum
294
973
  end
974
+ end
295
975
 
296
- def ==(o)
297
- self.class == o.class && types == o.types && size_type == o.size_type
976
+ def generalize
977
+ self == DEFAULT ? self : PTupleType.new(@types.map {|t| t.generalize })
978
+ end
979
+
980
+ def instance?(o)
981
+ return false unless o.is_a?(Array)
982
+ # compute the tuple's min/max size, and check if that size matches
983
+ size_t = size_type || PIntegerType.new(*size_range)
984
+
985
+ return false unless size_t.instance?(o.size)
986
+ o.each_with_index do |element, index|
987
+ return false unless (types[index] || types[-1]).instance?(element)
298
988
  end
989
+ true
299
990
  end
300
- end
301
991
 
302
- class PCallableType < PAnyType
303
- module ClassModule
304
- # Returns the number of accepted arguments [min, max]
305
- def size_range
306
- param_types.size_range
307
- end
308
-
309
- # Returns the number of accepted arguments for the last parameter type [min, max]
310
- #
311
- def last_range
312
- param_types.repeat_last_range
313
- end
314
-
315
- # Range [0,0], [0,1], or [1,1] for the block
316
- #
317
- def block_range
318
- case block_type
319
- when Puppet::Pops::Types::POptionalType
320
- [0,1]
321
- when Puppet::Pops::Types::PVariantType, Puppet::Pops::Types::PCallableType
322
- [1,1]
992
+ # Returns the number of elements accepted [min, max] in the tuple
993
+ def size_range
994
+ if @size_type.nil?
995
+ types_size = @types.size
996
+ [types_size, types_size]
997
+ else
998
+ @size_type.range
999
+ end
1000
+ end
1001
+
1002
+ # Returns the number of accepted occurrences [min, max] of the last type in the tuple
1003
+ # The defaults is [1,1]
1004
+ #
1005
+ def repeat_last_range
1006
+ if @size_type.nil?
1007
+ return [1, 1]
1008
+ end
1009
+ types_size = @types.size
1010
+ from, to = @size_type.range
1011
+ min = from - (types_size-1)
1012
+ min = min <= 0 ? 0 : min
1013
+ max = to - (types_size-1)
1014
+ [min, max]
1015
+ end
1016
+
1017
+ def hash
1018
+ @size_type.hash * 31 + @types.hash
1019
+ end
1020
+
1021
+ def ==(o)
1022
+ self.class == o.class && @types == o.types && @size_type == o.size_type
1023
+ end
1024
+
1025
+ DATA = PTupleType.new([PDataType::DEFAULT], PCollectionType::DEFAULT_SIZE)
1026
+ DEFAULT = PTupleType.new([])
1027
+
1028
+ protected
1029
+
1030
+ # @api private
1031
+ def _assignable?(o)
1032
+ return true if self == o
1033
+ s_types = types
1034
+ return true if s_types.empty? && (o.is_a?(PArrayType))
1035
+ size_s = size_type || PIntegerType.new(*size_range)
1036
+
1037
+ if o.is_a?(PTupleType)
1038
+ size_o = o.size_type || PIntegerType.new(*o.size_range)
1039
+
1040
+ # not assignable if the number of types in o is outside number of types in t1
1041
+ if size_s.assignable?(size_o)
1042
+ o_types = o.types
1043
+ o_types.size.times do |index|
1044
+ return false unless (s_types[index] || s_types[-1]).assignable?(o_types[index])
1045
+ end
1046
+ return true
323
1047
  else
324
- [0,0]
1048
+ return false
325
1049
  end
1050
+ elsif o.is_a?(PArrayType)
1051
+ o_entry = o.element_type
1052
+ # Array of anything can not be assigned (unless tuple is tuple of anything) - this case
1053
+ # was handled at the top of this method.
1054
+ #
1055
+ return false if o_entry.nil?
1056
+ size_o = o.size_type || PCollectionType::DEFAULT_SIZE
1057
+ return false unless size_s.assignable?(size_o)
1058
+ [s_types.size, size_o.range[1]].min.times { |index| return false unless (s_types[index] || s_types[-1]).assignable?(o_entry) }
1059
+ true
1060
+ else
1061
+ false
326
1062
  end
1063
+ end
1064
+ end
327
1065
 
328
- def hash
329
- [self.class, Set.new(param_types), block_type].hash
330
- end
1066
+ # @api public
1067
+ #
1068
+ class PCallableType < PAnyType
1069
+ # Types of parameters as a Tuple with required/optional count, or an Integer with min (required), max count
1070
+ # @return [PTupleType] the tuple representing the parameter types
1071
+ attr_reader :param_types
1072
+
1073
+ # Although being an abstract type reference, only Callable, or all Callables wrapped in
1074
+ # Optional or Variant are supported
1075
+ # If not set, the meaning is that block is not supported.
1076
+ # @return [PAnyType|nil] the block type
1077
+ attr_reader :block_type
1078
+
1079
+ # @param param_types [PTupleType]
1080
+ # @param block_type [PAnyType|nil]
1081
+ def initialize(param_types, block_type = nil)
1082
+ @param_types = param_types
1083
+ @block_type = block_type
1084
+ end
331
1085
 
332
- def ==(o)
333
- self.class == o.class && param_types == o.param_types && block_type == o.block_type
1086
+ def generalize
1087
+ return self if self == DEFAULT
1088
+ params_t = @param_types.nil? ? nil : @param_types.generalize
1089
+ block_t = @block_type.nil? ? nil : @block_type.generalize
1090
+ PCallableType.new(params_t, block_t)
1091
+ end
1092
+
1093
+ def instance?(o)
1094
+ assignable?(TypeCalculator.infer(o))
1095
+ end
1096
+
1097
+ # @api private
1098
+ def callable_args?(required_callable_t)
1099
+ # If the required callable is euqal or more specific than self, self is acceptable arguments
1100
+ required_callable_t.assignable?(self)
1101
+ end
1102
+
1103
+ def kind_of_callable?(optional=true)
1104
+ true
1105
+ end
1106
+
1107
+ # Returns the number of accepted arguments [min, max]
1108
+ def size_range
1109
+ @param_types.nil? ? nil : @param_types.size_range
1110
+ end
1111
+
1112
+ # Returns the number of accepted arguments for the last parameter type [min, max]
1113
+ #
1114
+ def last_range
1115
+ @param_types.nil? ? nil : @param_types.repeat_last_range
1116
+ end
1117
+
1118
+ # Range [0,0], [0,1], or [1,1] for the block
1119
+ #
1120
+ def block_range
1121
+ case block_type
1122
+ when POptionalType
1123
+ [0,1]
1124
+ when PVariantType, PCallableType
1125
+ [1,1]
1126
+ else
1127
+ [0,0]
334
1128
  end
335
1129
  end
1130
+
1131
+ def hash
1132
+ @param_types.hash * 31 + @block_type.hash
1133
+ end
1134
+
1135
+ def ==(o)
1136
+ self.class == o.class && @param_types == o.param_types && @block_type == o.block_type
1137
+ end
1138
+
1139
+ DEFAULT = PCallableType.new(nil)
1140
+
1141
+ protected
1142
+
1143
+ # @api private
1144
+ def _assignable?(o)
1145
+ return false unless o.is_a?(PCallableType)
1146
+ # nil param_types means, any other Callable is assignable
1147
+ return true if @param_types.nil?
1148
+
1149
+ # NOTE: these tests are made in reverse as it is calling the callable that is constrained
1150
+ # (it's lower bound), not its upper bound
1151
+ return false unless o.param_types.assignable?(@param_types)
1152
+ # names are ignored, they are just information
1153
+ # Blocks must be compatible
1154
+ this_block_t = @block_type || PUndefType::DEFAULT
1155
+ that_block_t = o.block_type || PUndefType::DEFAULT
1156
+ that_block_t.assignable?(this_block_t)
1157
+ end
336
1158
  end
337
1159
 
1160
+ # @api public
1161
+ #
338
1162
  class PArrayType < PCollectionType
339
- module ClassModule
340
- def hash
341
- [self.class, self.element_type, self.size_type].hash
1163
+
1164
+ # @api private
1165
+ def callable_args?(callable)
1166
+ param_t = callable.param_types
1167
+ block_t = callable.block_type
1168
+ # does not support calling with a block, but have to check that callable is ok with missing block
1169
+ (param_t.nil? || param_t.assignable?(self)) && (block_t.nil? || block_t.assignable(PUndefType::DEFAULT))
1170
+ end
1171
+
1172
+ def generalize
1173
+ if self == DEFAULT
1174
+ self
1175
+ else
1176
+ PArrayType.new(element_type.nil? ? nil : element_type.generalize)
342
1177
  end
1178
+ end
343
1179
 
344
- def ==(o)
345
- self.class == o.class && self.element_type == o.element_type && self.size_type == o.size_type
1180
+ def instance?(o)
1181
+ return false unless o.is_a?(Array)
1182
+ element_t = element_type
1183
+ return false unless element_t.nil? || o.all? {|element| element_t.instance?(element) }
1184
+ size_t = size_type
1185
+ size_t.nil? || size_t.instance?(o.size)
1186
+ end
1187
+
1188
+ DATA = PArrayType.new(PDataType::DEFAULT, PCollectionType::DEFAULT_SIZE)
1189
+ DEFAULT = PArrayType.new(nil)
1190
+ EMPTY = PArrayType.new(PUnitType::DEFAULT, PCollectionType::ZERO_SIZE)
1191
+
1192
+ protected
1193
+
1194
+ # Array is assignable if o is an Array and o's element type is assignable, or if o is a Tuple
1195
+ # @api private
1196
+ def _assignable?(o)
1197
+ s_entry = element_type
1198
+ if o.is_a?(PTupleType)
1199
+
1200
+ # Tuple of anything can not be assigned (unless array is tuple of anything) - this case
1201
+ # was handled at the top of this method.
1202
+ #
1203
+ return false if s_entry.nil?
1204
+
1205
+ return false unless o.types.all? {|o_element_t| s_entry.assignable?(o_element_t) }
1206
+ o_regular = o.types[0..-2]
1207
+ o_ranged = o.types[-1]
1208
+ o_from, o_to = type_to_range(o.size_type)
1209
+ o_required = o_regular.size + o_from
1210
+
1211
+ # array type may be size constrained
1212
+ size_s = size_type || DEFAULT_SIZE
1213
+ min, max = size_s.range
1214
+ # Tuple with fewer min entries can not be assigned
1215
+ return false if o_required < min
1216
+ # Tuple with more optionally available entries can not be assigned
1217
+ return false if o_regular.size + o_to > max
1218
+ # each tuple type must be assignable to the element type
1219
+ o_required.times do |index|
1220
+ o_entry = tuple_entry_at(o, o_from, o_to, index)
1221
+ return false unless s_entry.assignable?(o_entry)
1222
+ end
1223
+ # ... and so must the last, possibly optional (ranged) type
1224
+ s_entry.assignable?(o_ranged)
1225
+ elsif o.is_a?(PArrayType)
1226
+ super && (s_entry.nil? || s_entry.assignable?(o.element_type))
1227
+ else
1228
+ false
346
1229
  end
347
1230
  end
348
1231
  end
349
1232
 
1233
+ # @api public
1234
+ #
350
1235
  class PHashType < PCollectionType
351
- module ClassModule
352
- def hash
353
- [self.class, key_type, self.element_type, self.size_type].hash
1236
+ attr_accessor :key_type
1237
+
1238
+ def initialize(key_type, value_type, size_type = nil)
1239
+ super(value_type, size_type)
1240
+ @key_type = key_type
1241
+ end
1242
+
1243
+ def generalize
1244
+ if self == DEFAULT || self == EMPTY
1245
+ self
1246
+ else
1247
+ key_t = @key_type
1248
+ key_t = key_t.generalize unless key_t.nil?
1249
+ value_t = element_type
1250
+ value_t = value_t.generalize unless value_t.nil?
1251
+ PHashType.new(key_t, value_t)
354
1252
  end
1253
+ end
355
1254
 
356
- def ==(o)
357
- self.class == o.class &&
358
- key_type == o.key_type &&
359
- self.element_type == o.element_type &&
360
- self.size_type == o.size_type
1255
+ def hash
1256
+ @key_type.hash * 31 + super
1257
+ end
1258
+
1259
+ def instance?(o)
1260
+ return false unless o.is_a?(Hash)
1261
+ key_t = key_type
1262
+ element_t = element_type
1263
+ if (key_t.nil? || o.keys.all? {|key| key_t.instance?(key) }) &&
1264
+ (element_t.nil? || o.values.all? {|value| element_t.instance?(value) })
1265
+ size_t = size_type
1266
+ size_t.nil? || size_t.instance?(o.size)
1267
+ else
1268
+ false
361
1269
  end
1270
+ end
1271
+
1272
+ def ==(o)
1273
+ super && @key_type == o.key_type
1274
+ end
1275
+
1276
+ def is_the_empty_hash?
1277
+ self == EMPTY
1278
+ end
362
1279
 
363
- def is_the_empty_hash?
364
- size_type.is_a?(PIntegerType) && size_type.from == 0 && size_type.to == 0 && key_type.is_a?(PUndefType) && element_type.is_a?(PUndefType)
1280
+ DEFAULT = PHashType.new(nil, nil)
1281
+ DATA = PHashType.new(PScalarType::DEFAULT, PDataType::DEFAULT, DEFAULT_SIZE)
1282
+ EMPTY = PHashType.new(PUndefType::DEFAULT, PUndefType::DEFAULT, PIntegerType.new(0, 0))
1283
+
1284
+ protected
1285
+
1286
+ # Hash is assignable if o is a Hash and o's key and element types are assignable
1287
+ # @api private
1288
+ def _assignable?(o)
1289
+ case o
1290
+ when PHashType
1291
+ size_s = size_type
1292
+ return true if (size_s.nil? || size_s.from == 0) && o.is_the_empty_hash?
1293
+ return false unless (key_type.nil? || key_type.assignable?(o.key_type)) && (element_type.nil? || element_type.assignable?(o.element_type))
1294
+ super
1295
+ when PStructType
1296
+ # hash must accept String as key type
1297
+ # hash must accept all value types
1298
+ # hash must accept the size of the struct
1299
+ o_elements = o.elements
1300
+ (size_type || DEFAULT_SIZE).instance?(o_elements.size) &&
1301
+ o_elements.all? {|e| (key_type.nil? || key_type.instance?(e.name)) && (element_type.nil? || element_type.assignable?(e.value_type)) }
1302
+ else
1303
+ false
365
1304
  end
366
1305
  end
367
1306
  end
368
1307
 
369
- class PRuntimeType < PAnyType
370
- module ClassModule
371
- def hash
372
- [self.class, runtime, runtime_type_name].hash
1308
+ # A flexible type describing an any? of other types
1309
+ # @api public
1310
+ #
1311
+ class PVariantType < PAnyType
1312
+ include Enumerable
1313
+
1314
+ attr_reader :types
1315
+
1316
+ def initialize(types)
1317
+ @types = types.freeze
1318
+ end
1319
+
1320
+ def each
1321
+ if block_given?
1322
+ types.each { |t| yield t }
1323
+ else
1324
+ types.to_enum
373
1325
  end
1326
+ end
1327
+
1328
+ def generalize
1329
+ (self == DEFAULT || self == DATA) ? self : PVariantType.new(@types.map {|t| t.generalize})
1330
+ end
1331
+
1332
+ def hash
1333
+ @types.hash
1334
+ end
1335
+
1336
+ def instance?(o)
1337
+ # instance of variant if o is instance? of any of variant's types
1338
+ @types.any? { |type| type.instance?(o) }
1339
+ end
1340
+
1341
+ def kind_of_callable?(optional = true)
1342
+ @types.all? { |type| type.kind_of_callable?(optional) }
1343
+ end
1344
+
1345
+ def ==(o)
1346
+ # TODO: This special case doesn't look like it belongs here
1347
+ self.class == o.class && (@types | o.types).size == @types.size ||
1348
+ o.class == PDataType && self == DATA
1349
+ end
374
1350
 
375
- def ==(o)
376
- self.class == o.class && runtime == o.runtime && runtime_type_name == o.runtime_type_name
1351
+ # Variant compatible with the Data type.
1352
+ DATA = PVariantType.new([PHashType::DATA, PArrayType::DATA, PScalarType::DEFAULT, PUndefType::DEFAULT, PTupleType::DATA])
1353
+
1354
+ DEFAULT = PVariantType.new([])
1355
+
1356
+ protected
1357
+
1358
+ # @api private
1359
+ def _assignable?(o)
1360
+ # Data is a specific variant
1361
+ o = DATA if o.is_a?(PDataType)
1362
+ if o.is_a?(PVariantType)
1363
+ # A variant is assignable if all of its options are assignable to one of this type's options
1364
+ return true if self == o
1365
+ o.types.all? do |other|
1366
+ # if the other is a Variant, all of its options, but be assignable to one of this type's options
1367
+ other = other.is_a?(PDataType) ? DATA : other
1368
+ if other.is_a?(PVariantType)
1369
+ assignable?(other)
1370
+ else
1371
+ types.any? {|option_t| option_t.assignable?(other) }
1372
+ end
1373
+ end
1374
+ else
1375
+ # A variant is assignable if o is assignable to any of its types
1376
+ types.any? { |option_t| option_t.assignable?(o) }
377
1377
  end
378
1378
  end
379
1379
  end
380
1380
 
1381
+ # @api public
1382
+ #
1383
+ class PRuntimeType < PAnyType
1384
+ attr_reader :runtime, :runtime_type_name
1385
+
1386
+ def initialize(runtime, runtime_type_name = nil)
1387
+ @runtime = runtime
1388
+ @runtime_type_name = runtime_type_name
1389
+ end
1390
+
1391
+ def hash
1392
+ @runtime.hash * 31 + @runtime_type_name.hash
1393
+ end
1394
+
1395
+ def ==(o)
1396
+ self.class == o.class && @runtime == o.runtime && @runtime_type_name == o.runtime_type_name
1397
+ end
1398
+
1399
+ def instance?(o)
1400
+ assignable?(TypeCalculator.infer(o))
1401
+ end
1402
+
1403
+ DEFAULT = PRuntimeType.new(nil)
1404
+
1405
+ protected
1406
+
1407
+ # Assignable if o's has the same runtime and the runtime name resolves to
1408
+ # a class that is the same or subclass of t1's resolved runtime type name
1409
+ # @api private
1410
+ def _assignable?(o)
1411
+ return false unless o.is_a?(PRuntimeType)
1412
+ return false unless @runtime == o.runtime
1413
+ return true if @runtime_type_name.nil? # t1 is wider
1414
+ return false if o.runtime_type_name.nil? # t1 not nil, so o can not be wider
1415
+
1416
+ # NOTE: This only supports Ruby, must change when/if the set of runtimes is expanded
1417
+ c1 = class_from_string(@runtime_type_name)
1418
+ c2 = class_from_string(o.runtime_type_name)
1419
+ return false unless c1.is_a?(Module) && c2.is_a?(Module)
1420
+ !!(c2 <= c1)
1421
+ end
1422
+ end
1423
+
1424
+ # Abstract representation of a type that can be placed in a Catalog.
1425
+ # @api public
1426
+ #
1427
+ class PCatalogEntryType < PAnyType
1428
+
1429
+ DEFAULT = PCatalogEntryType.new
1430
+
1431
+ def instance?(o)
1432
+ assignable?(TypeCalculator.infer(o))
1433
+ end
1434
+
1435
+ protected
1436
+ # @api private
1437
+ def _assignable?(o)
1438
+ o.is_a?(PCatalogEntryType)
1439
+ end
1440
+ end
1441
+
1442
+ # Represents a (host-) class in the Puppet Language.
1443
+ # @api public
1444
+ #
381
1445
  class PHostClassType < PCatalogEntryType
382
- module ClassModule
383
- def hash
384
- [self.class, class_name].hash
385
- end
386
- def ==(o)
387
- self.class == o.class && class_name == o.class_name
388
- end
1446
+ attr_reader :class_name
1447
+
1448
+ def initialize(class_name)
1449
+ @class_name = class_name
1450
+ end
1451
+
1452
+ def hash
1453
+ 11 * @class_name.hash
1454
+ end
1455
+ def ==(o)
1456
+ self.class == o.class && @class_name == o.class_name
1457
+ end
1458
+
1459
+ DEFAULT = PHostClassType.new(nil)
1460
+
1461
+ protected
1462
+
1463
+ # @api private
1464
+ def _assignable?(o)
1465
+ return false unless o.is_a?(PHostClassType)
1466
+ # Class = Class[name}, Class[name] != Class
1467
+ return true if @class_name.nil?
1468
+ # Class[name] = Class[name]
1469
+ @class_name == o.class_name
389
1470
  end
390
1471
  end
391
1472
 
1473
+ # Represents a Resource Type in the Puppet Language
1474
+ # @api public
1475
+ #
392
1476
  class PResourceType < PCatalogEntryType
393
- module ClassModule
394
- def hash
395
- [self.class, type_name, title].hash
396
- end
397
- def ==(o)
398
- self.class == o.class && type_name == o.type_name && title == o.title
399
- end
1477
+ attr_reader :type_name, :title
1478
+
1479
+ def initialize(type_name, title = nil)
1480
+ @type_name = type_name
1481
+ @title = title
1482
+ end
1483
+
1484
+ def hash
1485
+ @type_name.hash * 31 + @title.hash
1486
+ end
1487
+
1488
+ def ==(o)
1489
+ self.class == o.class && @type_name == o.type_name && @title == o.title
1490
+ end
1491
+
1492
+ DEFAULT = PResourceType.new(nil)
1493
+
1494
+ protected
1495
+
1496
+ # @api private
1497
+ def _assignable?(o)
1498
+ return false unless o.is_a?(PResourceType)
1499
+ return true if @type_name.nil?
1500
+ return false if @type_name != o.type_name
1501
+ return true if @title.nil?
1502
+ @title == o.title
400
1503
  end
401
1504
  end
402
1505
 
1506
+ # Represents a type that accept PUndefType instead of the type parameter
1507
+ # required_type - is a short hand for Variant[T, Undef]
1508
+ # @api public
1509
+ #
403
1510
  class POptionalType < PAnyType
404
- module ClassModule
405
- def hash
406
- [self.class, optional_type].hash
407
- end
1511
+ attr_reader :optional_type
1512
+
1513
+ def initialize(optional_type)
1514
+ @optional_type = optional_type
1515
+ end
1516
+
1517
+ def generalize
1518
+ @optional_type.nil? ? self : PType.new(@optional_type.generalize)
1519
+ end
1520
+
1521
+ def hash
1522
+ 7 * @optional_type.hash
1523
+ end
1524
+
1525
+ def kind_of_callable?(optional=true)
1526
+ optional && !@optional_type.nil? && @optional_type.kind_of_callable?(optional)
1527
+ end
1528
+
1529
+ def ==(o)
1530
+ self.class == o.class && @optional_type == o.optional_type
1531
+ end
1532
+
1533
+ def instance?(o)
1534
+ PUndefType::DEFAULT.instance?(o) || (!optional_type.nil? && optional_type.instance?(o))
1535
+ end
408
1536
 
409
- def ==(o)
410
- self.class == o.class && optional_type == o.optional_type
1537
+ DEFAULT = POptionalType.new(nil)
1538
+
1539
+ protected
1540
+
1541
+ # @api private
1542
+ def _assignable?(o)
1543
+ return true if o.is_a?(PUndefType)
1544
+ return true if @optional_type.nil?
1545
+ if o.is_a?(POptionalType)
1546
+ @optional_type.assignable?(o.optional_type)
1547
+ else
1548
+ @optional_type.assignable?(o)
411
1549
  end
412
1550
  end
413
1551
  end
414
1552
  end
415
1553
  end
1554
+