puppet-strings 0.4.0 → 0.99.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +122 -0
  3. data/COMMITTERS.md +185 -0
  4. data/CONTRIBUTING.md +89 -0
  5. data/Gemfile +38 -0
  6. data/JSON.md +511 -0
  7. data/LICENSE +13 -0
  8. data/README.md +416 -0
  9. data/Rakefile +49 -0
  10. data/lib/puppet-strings.rb +63 -0
  11. data/lib/puppet-strings/json.rb +49 -0
  12. data/lib/puppet-strings/tasks.rb +10 -0
  13. data/lib/puppet-strings/tasks/generate.rb +23 -0
  14. data/lib/puppet-strings/tasks/gh_pages.rb +43 -0
  15. data/lib/puppet-strings/yard.rb +96 -0
  16. data/lib/puppet-strings/yard/code_objects.rb +8 -0
  17. data/lib/puppet-strings/yard/code_objects/base.rb +14 -0
  18. data/lib/puppet-strings/yard/code_objects/class.rb +59 -0
  19. data/lib/puppet-strings/yard/code_objects/defined_type.rb +58 -0
  20. data/lib/puppet-strings/yard/code_objects/function.rb +93 -0
  21. data/lib/puppet-strings/yard/code_objects/group.rb +30 -0
  22. data/lib/puppet-strings/yard/code_objects/provider.rb +93 -0
  23. data/lib/puppet-strings/yard/code_objects/type.rb +146 -0
  24. data/lib/puppet-strings/yard/handlers.rb +16 -0
  25. data/lib/puppet-strings/yard/handlers/puppet/base.rb +44 -0
  26. data/lib/puppet-strings/yard/handlers/puppet/class_handler.rb +23 -0
  27. data/lib/puppet-strings/yard/handlers/puppet/defined_type_handler.rb +23 -0
  28. data/lib/puppet-strings/yard/handlers/puppet/function_handler.rb +42 -0
  29. data/lib/puppet-strings/yard/handlers/ruby/base.rb +38 -0
  30. data/lib/puppet-strings/yard/handlers/ruby/function_handler.rb +357 -0
  31. data/lib/puppet-strings/yard/handlers/ruby/provider_handler.rb +113 -0
  32. data/lib/puppet-strings/yard/handlers/ruby/type_handler.rb +194 -0
  33. data/lib/puppet-strings/yard/parsers.rb +7 -0
  34. data/lib/puppet-strings/yard/parsers/puppet/parser.rb +70 -0
  35. data/lib/puppet-strings/yard/parsers/puppet/statement.rb +146 -0
  36. data/lib/puppet-strings/yard/tags.rb +6 -0
  37. data/lib/puppet-strings/yard/tags/overload_tag.rb +109 -0
  38. data/lib/puppet-strings/yard/tags/parameter_directive.rb +24 -0
  39. data/lib/puppet-strings/yard/tags/property_directive.rb +24 -0
  40. data/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_class.erb +9 -0
  41. data/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_defined_type.erb +9 -0
  42. data/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_function.erb +10 -0
  43. data/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_provider.erb +10 -0
  44. data/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_type.erb +9 -0
  45. data/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb +64 -0
  46. data/lib/puppet-strings/yard/templates/default/layout/html/objects.erb +35 -0
  47. data/lib/puppet-strings/yard/templates/default/layout/html/setup.rb +172 -0
  48. data/lib/puppet-strings/yard/templates/default/puppet_class/html/box_info.erb +26 -0
  49. data/lib/puppet-strings/yard/templates/default/puppet_class/html/header.erb +1 -0
  50. data/lib/puppet-strings/yard/templates/default/puppet_class/html/overview.erb +6 -0
  51. data/lib/puppet-strings/yard/templates/default/puppet_class/html/setup.rb +14 -0
  52. data/lib/puppet-strings/yard/templates/default/puppet_class/html/source.erb +12 -0
  53. data/lib/puppet-strings/yard/templates/default/puppet_defined_type/html/box_info.erb +10 -0
  54. data/lib/puppet-strings/yard/templates/default/puppet_defined_type/html/header.erb +1 -0
  55. data/lib/puppet-strings/yard/templates/default/puppet_defined_type/html/overview.erb +6 -0
  56. data/lib/puppet-strings/yard/templates/default/puppet_defined_type/html/setup.rb +5 -0
  57. data/lib/puppet-strings/yard/templates/default/puppet_defined_type/html/source.erb +12 -0
  58. data/lib/puppet-strings/yard/templates/default/puppet_function/html/box_info.erb +14 -0
  59. data/lib/puppet-strings/yard/templates/default/puppet_function/html/header.erb +1 -0
  60. data/lib/puppet-strings/yard/templates/default/puppet_function/html/overview.erb +18 -0
  61. data/lib/puppet-strings/yard/templates/default/puppet_function/html/setup.rb +5 -0
  62. data/lib/puppet-strings/yard/templates/default/puppet_function/html/source.erb +12 -0
  63. data/lib/puppet-strings/yard/templates/default/puppet_provider/html/box_info.erb +14 -0
  64. data/lib/puppet-strings/yard/templates/default/puppet_provider/html/collection.erb +10 -0
  65. data/lib/puppet-strings/yard/templates/default/puppet_provider/html/features.erb +12 -0
  66. data/lib/puppet-strings/yard/templates/default/puppet_provider/html/header.erb +1 -0
  67. data/lib/puppet-strings/yard/templates/default/puppet_provider/html/overview.erb +6 -0
  68. data/lib/puppet-strings/yard/templates/default/puppet_provider/html/setup.rb +29 -0
  69. data/lib/puppet-strings/yard/templates/default/puppet_type/html/box_info.erb +20 -0
  70. data/lib/puppet-strings/yard/templates/default/puppet_type/html/features.erb +13 -0
  71. data/lib/puppet-strings/yard/templates/default/puppet_type/html/header.erb +1 -0
  72. data/lib/puppet-strings/yard/templates/default/puppet_type/html/overview.erb +6 -0
  73. data/lib/puppet-strings/yard/templates/default/puppet_type/html/parameters.erb +35 -0
  74. data/lib/puppet-strings/yard/templates/default/puppet_type/html/setup.rb +32 -0
  75. data/lib/puppet-strings/yard/templates/default/tags/html/puppet_overload.erb +12 -0
  76. data/lib/puppet-strings/yard/templates/default/tags/setup.rb +15 -0
  77. data/lib/puppet/application/strings.rb +1 -0
  78. data/lib/puppet/face/strings.rb +80 -39
  79. data/spec/acceptance/emit_json_options.rb +41 -0
  80. data/spec/acceptance/lib/util.rb +15 -0
  81. data/spec/acceptance/running_strings_generate.rb +54 -0
  82. data/spec/fixtures/acceptance/modules/test/functions/add.pp +9 -0
  83. data/spec/fixtures/acceptance/modules/test/lib/puppet/functions/4x_function.rb +5 -0
  84. data/spec/fixtures/acceptance/modules/test/lib/puppet/parser/functions/function3x.rb +2 -0
  85. data/spec/fixtures/acceptance/modules/test/lib/puppet/provider/server/linux.rb +9 -0
  86. data/spec/fixtures/acceptance/modules/test/lib/puppet/type/database.rb +15 -0
  87. data/spec/fixtures/acceptance/modules/test/manifests/init.pp +27 -0
  88. data/spec/fixtures/acceptance/modules/test/manifests/triple_nested_classes.pp +27 -0
  89. data/spec/fixtures/acceptance/modules/test/metadata.json +6 -0
  90. data/spec/fixtures/unit/json/output.json +348 -0
  91. data/spec/fixtures/unit/json/output_without_puppet_function.json +301 -0
  92. data/spec/spec_helper.rb +21 -0
  93. data/spec/spec_helper_acceptance.rb +27 -0
  94. data/spec/unit/puppet-strings/json_spec.rb +136 -0
  95. data/spec/unit/puppet-strings/yard/handlers/puppet/class_handler_spec.rb +155 -0
  96. data/spec/unit/puppet-strings/yard/handlers/puppet/defined_type_handler_spec.rb +155 -0
  97. data/spec/unit/puppet-strings/yard/handlers/puppet/function_handler_spec.rb +169 -0
  98. data/spec/unit/puppet-strings/yard/handlers/ruby/function_handler_spec.rb +613 -0
  99. data/spec/unit/puppet-strings/yard/handlers/ruby/provider_handler_spec.rb +90 -0
  100. data/spec/unit/puppet-strings/yard/handlers/ruby/type_handler_spec.rb +214 -0
  101. data/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb +171 -0
  102. metadata +115 -92
  103. data/lib/puppet-strings/rake_tasks.rb +0 -18
  104. data/lib/puppet_x/puppetlabs/strings.rb +0 -64
  105. data/lib/puppet_x/puppetlabs/strings/actions.rb +0 -92
  106. data/lib/puppet_x/puppetlabs/strings/pops/yard_statement.rb +0 -79
  107. data/lib/puppet_x/puppetlabs/strings/pops/yard_transformer.rb +0 -47
  108. data/lib/puppet_x/puppetlabs/strings/util.rb +0 -65
  109. data/lib/puppet_x/puppetlabs/strings/yard/code_objects/defined_type_object.rb +0 -33
  110. data/lib/puppet_x/puppetlabs/strings/yard/code_objects/host_class_object.rb +0 -22
  111. data/lib/puppet_x/puppetlabs/strings/yard/code_objects/method_object.rb +0 -62
  112. data/lib/puppet_x/puppetlabs/strings/yard/code_objects/provider_object.rb +0 -24
  113. data/lib/puppet_x/puppetlabs/strings/yard/code_objects/puppet_namespace_object.rb +0 -48
  114. data/lib/puppet_x/puppetlabs/strings/yard/code_objects/type_object.rb +0 -42
  115. data/lib/puppet_x/puppetlabs/strings/yard/core_ext/yard.rb +0 -40
  116. data/lib/puppet_x/puppetlabs/strings/yard/handlers/base.rb +0 -13
  117. data/lib/puppet_x/puppetlabs/strings/yard/handlers/defined_type_handler.rb +0 -31
  118. data/lib/puppet_x/puppetlabs/strings/yard/handlers/heredoc_helper.rb +0 -80
  119. data/lib/puppet_x/puppetlabs/strings/yard/handlers/host_class_handler.rb +0 -42
  120. data/lib/puppet_x/puppetlabs/strings/yard/handlers/provider_handler.rb +0 -95
  121. data/lib/puppet_x/puppetlabs/strings/yard/handlers/puppet_3x_function_handler.rb +0 -54
  122. data/lib/puppet_x/puppetlabs/strings/yard/handlers/puppet_4x_function_handler.rb +0 -234
  123. data/lib/puppet_x/puppetlabs/strings/yard/handlers/type_handler.rb +0 -295
  124. data/lib/puppet_x/puppetlabs/strings/yard/json_registry_store.rb +0 -85
  125. data/lib/puppet_x/puppetlabs/strings/yard/monkey_patches.rb +0 -68
  126. data/lib/puppet_x/puppetlabs/strings/yard/parser.rb +0 -30
  127. data/lib/puppet_x/puppetlabs/strings/yard/tags/directives.rb +0 -9
  128. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/html/docstring.erb +0 -34
  129. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/html/header.erb +0 -5
  130. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/html/parameter_details.erb +0 -6
  131. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/html/setup.rb +0 -1
  132. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/setup.rb +0 -49
  133. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_class.erb +0 -2
  134. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_puppet_manifest.erb +0 -1
  135. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_puppet_plugin.erb +0 -21
  136. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_puppet_provider.erb +0 -1
  137. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_puppet_type.erb +0 -1
  138. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/setup.rb +0 -82
  139. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/html/box_info.erb +0 -22
  140. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/html/setup.rb +0 -1
  141. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/html/subclasses.erb +0 -4
  142. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/setup.rb +0 -21
  143. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/html_helper.rb +0 -139
  144. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/layout/html/setup.rb +0 -18
  145. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/method_details/html/header.erb +0 -17
  146. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/method_details/setup.rb +0 -21
  147. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/method_details/text/header.erb +0 -2
  148. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/command_details.erb +0 -8
  149. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/confine_details.erb +0 -10
  150. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/default_details.erb +0 -10
  151. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/docstring.erb +0 -34
  152. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/feature_details.erb +0 -10
  153. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/header.erb +0 -5
  154. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/setup.rb +0 -1
  155. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/setup.rb +0 -50
  156. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/html/box_info.erb +0 -11
  157. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/html/header.erb +0 -5
  158. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/html/method_details_list.erb +0 -53
  159. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/html/method_summary.erb +0 -20
  160. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/html/setup.rb +0 -1
  161. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/setup.rb +0 -91
  162. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/template_helper.rb +0 -192
  163. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/docstring.erb +0 -34
  164. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/header.erb +0 -5
  165. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/parameter_details.erb +0 -12
  166. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/provider_details.erb +0 -10
  167. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/setup.rb +0 -1
  168. data/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/setup.rb +0 -55
@@ -1,42 +0,0 @@
1
- class PuppetX::PuppetLabs::Strings::YARD::Handlers::HostClassHandler < PuppetX::PuppetLabs::Strings::YARD::Handlers::Base
2
- handles HostClassDefinition
3
-
4
- process do
5
- obj = HostClassObject.new(:root, statement.pops_obj.name)
6
-
7
- obj.parameters = statement.parameters.map do |a|
8
- param_tuple = [a[0].pops_obj.name]
9
- param_tuple << ( a[1].nil? ? nil : a[1].source )
10
- end
11
- tp = Puppet::Pops::Types::TypeParser.new
12
- param_type_info = {}
13
- statement.pops_obj.parameters.each do |pop_param|
14
- # If the parameter's type expression is nil, default to Any
15
- if pop_param.type_expr == nil
16
- param_type_info[pop_param.name] = Puppet::Pops::Types::TypeFactory.any()
17
- else
18
- begin
19
- # This is a bit of a hack because we were using a method that was previously
20
- # API private. See PDOC-75 for more details
21
- if Puppet::Pops::Types::TypeParser.instance_method(:interpret_any).arity == 2
22
- param_type_info[pop_param.name] = tp.interpret_any(pop_param.type_expr, nil)
23
- else
24
- param_type_info[pop_param.name] = tp.interpret_any(pop_param.type_expr)
25
- end
26
- rescue Puppet::ParseError => e
27
- # If the type could not be interpreted insert a prominent warning
28
- param_type_info[pop_param.name] = "Type Error: #{e.message}"
29
- end
30
- end
31
- end
32
- obj.type_info = [param_type_info]
33
-
34
- statement.pops_obj.tap do |o|
35
- if o.parent_class
36
- obj.parent_class = P(:root, o.parent_class)
37
- end
38
- end
39
-
40
- register obj
41
- end
42
- end
@@ -1,95 +0,0 @@
1
- # Handles `dispatch` calls within a future parser function declaration. For
2
- # now, it just treats any docstring as an `@overlaod` tag and attaches the
3
- # overload to the parent function.
4
- class PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler < YARD::Handlers::Ruby::Base
5
- include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
6
-
7
- handles :command_call, :call
8
-
9
- process do
10
- @heredoc_helper = HereDocHelper.new
11
- # Puppet types always begin with:
12
- # Puppet::Types.newtype...
13
- # Therefore, we match the corresponding trees which look like this:
14
- # s(:call,
15
- # s(:const_path_ref,
16
- # s(:var_ref, s(:const, "Puppet", ...), ...),
17
- # s(:const, "Type", ...),
18
- # You think this is ugly? It's better than the alternative.
19
- return unless statement.children.length > 2
20
- first = statement.children.first.first
21
- return unless (first.source == 'Puppet::Type') ||
22
- (first.type == :var_ref &&
23
- first.source == 'Type') &&
24
- statement[2].source == 'provide'
25
- i = statement.index { |s| YARD::Parser::Ruby::AstNode === s && s.type == :ident && s.source == 'provide' }
26
- provider_name = statement[i+1].jump(:ident).source
27
- type_name = statement.jump(:symbol).first.source
28
-
29
- obj = ProviderObject.new(:root, "#{provider_name}_provider")
30
-
31
- docstring = nil
32
- features = []
33
- commands = []
34
- confines = {}
35
- defaults = {}
36
- do_block = statement.jump(:do_block)
37
- do_block.traverse do |node|
38
- if is_a_func_call_named?('desc', node)
39
- content = node.jump(:tstring_content)
40
- # if we found the string content extract its source
41
- if content != node
42
- # The docstring is either the source stripped of heredoc
43
- # annotations or the raw source.
44
- if @heredoc_helper.is_heredoc?(content.source)
45
- docstring = @heredoc_helper.process_heredoc content.source
46
- else
47
- docstring = content.source
48
- end
49
- end
50
- elsif is_a_func_call_named?('confine', node)
51
- node.traverse do |s|
52
- if s.type == :assoc
53
- k = s.first.jump(:ident).source
54
- v = s[1].first.source
55
- confines[k] = v
56
- end
57
- end
58
- elsif is_a_func_call_named?('has_feature', node)
59
- list = node.jump :list
60
- if list != nil && list != node
61
- features += list.map { |s| s.source if YARD::Parser::Ruby::AstNode === s }.compact
62
- end
63
- elsif is_a_func_call_named?('commands', node)
64
- assoc = node.jump(:assoc)
65
- if assoc && assoc != node
66
- ident = assoc.jump(:ident)
67
- if ident && ident != assoc
68
- commands << ident.source
69
- end
70
- end
71
- elsif is_a_func_call_named?('defaultfor', node)
72
- node.traverse do |s|
73
- if s.type == :assoc
74
- k = s.first.jump(:ident).source
75
- v = s[1].first.source
76
- defaults[k] = v
77
- end
78
- end
79
- end
80
- end
81
- obj.features = features
82
- obj.commands = commands
83
- obj.confines = confines
84
- obj.defaults = defaults
85
- obj.type_name = type_name
86
- obj.header_name = provider_name
87
-
88
- register_docstring(obj, docstring, nil)
89
- register obj
90
- end
91
-
92
- def is_a_func_call_named?(name, node)
93
- (node.type == :fcall || node.type == :command || node.type == :vcall) && node.children.first.source == name
94
- end
95
- end
@@ -1,54 +0,0 @@
1
- require File.join(File.dirname(__FILE__),'./heredoc_helper')
2
-
3
- class PuppetX::PuppetLabs::Strings::YARD::Handlers::Puppet3xFunctionHandler < YARD::Handlers::Ruby::Base
4
- include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
5
-
6
- handles method_call(:newfunction)
7
-
8
- process do
9
- @heredoc_helper = HereDocHelper.new
10
- name, options = @heredoc_helper.process_parameters statement
11
-
12
- obj = MethodObject.new(function_namespace, name)
13
- obj[:puppet_3x_function] = true
14
-
15
- register obj
16
- if options['doc']
17
- register_docstring(obj, options['doc'], nil)
18
- end
19
-
20
- # This has to be done _after_ register_docstring as all tags on the
21
- # object are overwritten by tags parsed out of the docstring.
22
- return_type = options['type']
23
- return_type ||= 'statement' # Default for newfunction
24
- obj.add_tag YARD::Tags::Tag.new(:return, '', return_type)
25
-
26
- # FIXME: This is a hack that allows us to document the Puppet Core which
27
- # uses `--no-transitive-tag api` and then only shows things explicitly
28
- # tagged with `public` or `private` api. This is kind of insane and
29
- # should be fixed upstream.
30
- obj.add_tag YARD::Tags::Tag.new(:api, 'public')
31
- end
32
-
33
- private
34
-
35
- # Returns a {PuppetNamespaceObject} for holding functions. Creates this
36
- # object if necessary.
37
- #
38
- # @return [PuppetNamespaceObject]
39
- def function_namespace
40
- # NOTE: This tricky. If there is ever a Ruby class or module with the
41
- # name ::Puppet3xFunctions, then there will be a clash. Hopefully the name
42
- # is sufficiently uncommon.
43
- obj = P(:root, 'Puppet3xFunctions')
44
- if obj.is_a? Proxy
45
- namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet3xFunctions')
46
- namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
47
-
48
- register namespace_obj
49
- end
50
-
51
- obj
52
- end
53
-
54
- end
@@ -1,234 +0,0 @@
1
- # Handles `dispatch` calls within a future parser function declaration. For
2
- # now, it just treats any docstring as an `@overlaod` tag and attaches the
3
- # overload to the parent function.
4
- class PuppetX::PuppetLabs::Strings::YARD::Handlers::Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
5
- include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
6
-
7
- handles method_call(:dispatch)
8
-
9
- process do
10
- return unless owner.is_a?(MethodObject) && owner['puppet_4x_function']
11
- return unless statement.docstring
12
-
13
- docstring = ::YARD::Docstring.new(statement.docstring, nil)
14
-
15
- # FIXME: This does a wholesale copy of all possible tags. But, we're only
16
- # interested in the @overload tag.
17
- owner.add_tag *docstring.tags
18
- end
19
- end
20
-
21
- class Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
22
- include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
23
-
24
- handles method_call(:create_function)
25
-
26
- # Given a command node which represents code like this:
27
- # param 'Optional[Type]', :value_type
28
- # Extract the type name and type signature and return them as a array.
29
- def extract_type_from_command command
30
- return [] if command.children.length < 2 or command.children[1].children.length < 2
31
- type_specifier = command.children[1]
32
- # the parameter signature is the first child of the specifier and an
33
- # identifier. Jump to the content inside the quotes and convert it to a
34
- # string.
35
- param_signature = type_specifier.children[0].jump(:tstring_content).source
36
- # The parameter name is the second child of the specifier and a symbol.
37
- # convert it to a string.
38
- param_name_ident = type_specifier.jump :ident
39
- return [] if param_name_ident == type_specifier
40
- param_name = param_name_ident.source
41
- [param_name, param_signature]
42
- end
43
-
44
- process do
45
- name = process_parameters
46
-
47
- method_arguments = []
48
-
49
- # To attach the method parameters to the new code object, traverse the
50
- # ruby AST until a node is found which defines a array of parameters.
51
- # Then, traverse the children of the parameters, storing each identifier
52
- # in the array of method arguments.
53
- obj = MethodObject.new(function_namespace, name) do |o|
54
- end
55
-
56
- # The data structure for overload_signatures is an array of hashes. Each
57
- # hash represents the arguments a single function dispatch (aka overload)
58
- # can take.
59
- # overload_signatures = [
60
- # { # First function dispatch arguments
61
- # # argument name, argument type
62
- # 'arg0': 'Variant[String,Array[String]]',
63
- # 'arg1': 'Optional[Type]'
64
- # },
65
- # { # Second function dispatch arguments
66
- # 'arg0': 'Variant[String,Array[String]]',
67
- # 'arg1': 'Optional[Type]',
68
- # 'arg2': 'Any'
69
- # }
70
- # ]
71
- # Note that the order for arguments to a function doesn't actually matter
72
- # because we allow users flexibility when listing their arguments in the
73
- # comments.
74
- overload_signatures = []
75
- statement.traverse do |node|
76
- # Find all of the dispatch methods
77
- if node.type == :ident and node.source == 'dispatch'
78
- command = node.parent
79
- do_block = command.jump :do_block
80
- # If the command doesn't have a do_block we can't extract type info
81
- if do_block == command
82
- next
83
- end
84
- signature = {}
85
- # Iterate through each of the children of the do block and build
86
- # tuples of parameter names and parameter type signatures
87
- do_block.children.first.children.each do |child|
88
- name, type = extract_type_from_command(child)
89
- # This can happen if there is a function or something we aren't
90
- # expecting.
91
- if name != nil and type != nil
92
- signature[name] = type
93
- end
94
- end
95
- overload_signatures <<= signature
96
- end
97
- end
98
-
99
- # If the overload_signatures list is empty because we couldn't find any
100
- # dispatch blocks, then there must be one function named the same as the
101
- # name of the function being created.
102
- if overload_signatures.length == 0
103
- statement.traverse do |node|
104
- # Find the function definition with the same name as the puppet
105
- # function being created.
106
- if (node.type == :def and node.children.first.type == :ident and
107
- node.children.first.source == obj.name.to_s)
108
- signature = {}
109
- # Find its parameters. If they don't exist, fine
110
- params = node.jump :params
111
- break if params == node
112
- params.traverse do |param|
113
- if param.type == :ident
114
- # The parameters of Puppet functions with no defined dispatch are
115
- # as though they are Any type.
116
- signature[param[0]] = 'Any'
117
- end
118
- end
119
- overload_signatures <<= signature
120
- # Now that the parameters have been found, break out of the traversal
121
- break
122
- end
123
- end
124
- end
125
-
126
- # Preserve this type information. We'll need it later when we look
127
- # at the docstring.
128
- obj.type_info = overload_signatures
129
-
130
- # The yard docstring parser expects a list of lists, not a list of lists of
131
- # lists.
132
- obj.parameters = overload_signatures.map { |sig| sig.to_a }.flatten(1)
133
-
134
- obj['puppet_4x_function'] = true
135
-
136
- register obj
137
-
138
- obj.add_tag YARD::Tags::Tag.new(:api, 'public')
139
-
140
- blk = statement.block.children.first
141
- parse_block(blk, :owner => obj)
142
- end
143
-
144
- private
145
-
146
- # Returns a {PuppetNamespaceObject} for holding functions. Creates this
147
- # object if necessary.
148
- #
149
- # @return [PuppetNamespaceObject]
150
- def function_namespace
151
- # NOTE: This tricky. If there is ever a Ruby class or module with the
152
- # name ::Puppet4xFunctions, then there will be a clash. Hopefully the name
153
- # is sufficiently uncommon.
154
- obj = P(:root, 'Puppet4xFunctions')
155
- if obj.is_a? Proxy
156
- namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet4xFunctions')
157
-
158
- register namespace_obj
159
- # FIXME: The docstring has to be cleared. Otherwise, the namespace
160
- # object will be registered using the docstring of the
161
- # `create_function` call that is currently being processed.
162
- #
163
- # Figure out how to properly register the namespace without using the
164
- # function handler object.
165
- register_docstring(namespace_obj, '', nil)
166
- namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
167
- end
168
-
169
- obj
170
- end
171
-
172
- # NOTE: The following methods duplicate functionality from
173
- # Puppet::Util::Reference and Puppet::Parser::Functions.functiondocs
174
- #
175
- # However, implementing this natively in YARD is a good test for the
176
- # feasibility of extracting custom Ruby documentation. In the end, the
177
- # existing approach taken by Puppet::Util::Reference may be the best due to
178
- # the heavy use of metaprogramming in Types and Providers.
179
-
180
- # Extracts the Puppet function name and options hash from the parsed
181
- # definition.
182
- #
183
- # @return [(String, Hash{String => String})]
184
- def process_parameters
185
- # Passing `false` to parameters excludes the block param from the returned
186
- # array.
187
- name, _ = statement.parameters(false).compact
188
-
189
- name = process_element(name)
190
-
191
-
192
- name
193
- end
194
-
195
- # Sometimes the YARD parser returns Heredoc strings that start with `<-`
196
- # instead of `<<-`.
197
- HEREDOC_START = /^<?<-/
198
-
199
- # Turns an entry in the method parameter array into a string.
200
- #
201
- # @param ele [YARD::Parser::Ruby::AstNode]
202
- # @return [String]
203
- def process_element(ele)
204
- ele = ele.jump(:ident, :string_content, :tstring_content)
205
-
206
- case ele.type
207
- when :ident
208
- ele.source
209
- when :string_content, :tstring_content
210
- source = ele.source
211
- if HEREDOC_START.match(source)
212
- process_heredoc(source)
213
- else
214
- source
215
- end
216
- end
217
- end
218
-
219
- # Cleans up and formats Heredoc contents parsed by YARD.
220
- #
221
- # @param source [String]
222
- # @return [String]
223
- def process_heredoc(source)
224
- source = source.lines.to_a
225
-
226
- # YARD adds a line of source context on either side of the Heredoc
227
- # contents.
228
- source.shift
229
- source.pop
230
-
231
- # This utility method normalizes indentation and trims whitespace.
232
- Puppet::Util::Docs.scrub(source.join)
233
- end
234
- end
@@ -1,295 +0,0 @@
1
- # Handles `dispatch` calls within a future parser function declaration. For
2
- # now, it just treats any docstring as an `@overlaod` tag and attaches the
3
- # overload to the parent function.
4
- class PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetTypeHandler < YARD::Handlers::Ruby::Base
5
- include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
6
-
7
- handles :call
8
-
9
- process do
10
- @heredoc_helper = HereDocHelper.new
11
- # Puppet types always begin with:
12
- # Puppet::Types.newtype...
13
- # Therefore, we match the corresponding trees which look like this:
14
- # s(:call,
15
- # s(:const_path_ref,
16
- # s(:var_ref, s(:const, "Puppet", ...), ...),
17
- # s(:const, "Type", ...),
18
- # You think this is ugly? It's better than the alternative.
19
- return unless statement.children.length > 2
20
- first = statement.children.first
21
- return unless (first.type == :const_path_ref and
22
- first.source == 'Puppet::Type') or
23
- (first.type == :var_ref and
24
- first.source == 'Type') and
25
- statement.children[1].source == "newtype"
26
-
27
- # Fetch the docstring for the types. The docstring is the string literal
28
- # assigned to the @doc parameter or absent, like this:
29
- # @doc "docstring goes here"
30
- # We assume that docstrings nodes have the following shape in the source
31
- # code:
32
- # ...
33
- # s(s(:assign,
34
- # s(:..., s(:ivar, "@doc", ...), ...),
35
- # s(:...,
36
- # s(:...,
37
- # s(:tstring_content,
38
- # "Manages files, including their content, etc.", ...
39
- # Initialize the docstring to nil, the default value if we don't find
40
- # anything
41
- docstring = nil
42
- # Walk the tree searching for assignments
43
- statement.traverse do |node|
44
- if node.type == :assign
45
- # Once we have found and assignment, jump to the first ivar
46
- # (the l-value)
47
- # If we can't find an ivar return the node.
48
- ivar = node.jump(:ivar)
49
- # If we found and ivar and its source reads '@doc' then...
50
- if ivar != node and ivar.source == '@doc'
51
- # find the next string content
52
- content = node.jump(:tstring_content)
53
- # if we found the string content extract its source
54
- if content != node
55
- # The docstring is either the source stripped of heredoc
56
- # annotations or the raw source.
57
- if @heredoc_helper.is_heredoc? content.source
58
- docstring = @heredoc_helper.process_heredoc content.source
59
- else
60
- docstring = content.source
61
- end
62
- end
63
- # Since we found the @doc parameter (regardless of whether we
64
- # successfully extracted its source), we're done.
65
- break
66
- # But if we didn't find the ivar loop around again.
67
- else
68
- next
69
- end
70
- end
71
- end
72
-
73
- # The types begin with:
74
- # Puppet::Types.newtype(:symbol)
75
- # Jump to the first identifier (':symbol') after the third argument
76
- # ('(:symbol)') to the current statement
77
- name = statement.children[2].jump(:ident).source
78
- parameter_details = []
79
- property_details = []
80
- features = []
81
- obj = TypeObject.new(:root, name)
82
- obj.parameters = []
83
-
84
- # Find the do block following the Type.
85
- do_block = statement.jump(:do_block)
86
- # traverse the do block's children searching for function calls whose
87
- # identifier is newparam (we're calling the newparam function)
88
- do_block.traverse do |node|
89
- if is_param? node
90
- # The first member of the parameter tuple is the parameter name.
91
- # Find the second identifier node under the fcall tree. The first one
92
- # is 'newparam', the second one is the function name.
93
- # Get its source.
94
- # The second parameter is nil because we cannot infer types for these
95
- # functions. In fact, that's a silly thing to ask because ruby
96
- # types were deprecated with puppet 4 at the same time the type
97
- # system was created.
98
-
99
- # Because of a ripper bug a symbol identifier is sometimes incorrectly parsed as a keyword.
100
- # That is, the symbol `:true` will be represented as s(:symbol s(:kw, true...
101
- param_name = node.children[1].jump(:ident)
102
- if param_name == node.children[1]
103
- param_name = node.children[1].jump(:kw)
104
- end
105
- param_name = param_name.source
106
- obj.parameters << [param_name, nil]
107
- parameter_details << {:name => param_name,
108
- :desc => fetch_description(node), :exists? => true,
109
- :puppet_type => true,
110
- :default => fetch_default(node),
111
- :namevar => is_namevar?(node, param_name, name),
112
- :parameter => true,
113
- :allowed_values => get_parameter_allowed_values(node),
114
- }
115
- elsif is_prop? node
116
- # Because of a ripper bug a symbol identifier is sometimes incorrectly parsed as a keyword.
117
- # That is, the symbol `:true` will be represented as s(:symbol s(:kw, true...
118
- prop_name = node.children[1].jump(:ident)
119
- if prop_name == node.children[1]
120
- prop_name = node.children[1].jump(:kw)
121
- end
122
- prop_name = prop_name.source
123
- property_details << {:name => prop_name,
124
- :desc => fetch_description(node), :exists? => true,
125
- :default => fetch_default(node),
126
- :puppet_type => true,
127
- :property => true,
128
- :allowed_values => get_property_allowed_values(node),
129
- }
130
- elsif is_feature? node
131
- features << get_feature(node)
132
- elsif is_a_func_call_named? 'ensurable', node
133
- # Someone could call the ensurable method and create an ensure
134
- # property. If that happens, they it will be documented twice. Serves
135
- # them right.
136
- property_details << {:name => 'ensure',
137
- :desc => '', :exists? => true,
138
- :default => nil,
139
- :puppet_type => true,
140
- :property => true,
141
- :allowed_values => [],
142
- }
143
- end
144
- end
145
- obj.parameter_details = parameter_details
146
- obj.property_details = property_details
147
- obj.features = features
148
- obj.header_name = name
149
-
150
- register obj
151
- # Register docstring after the object. If the object already has a
152
- # docstring, or more likely has parameters documented with the type
153
- # directive and an empty docstring, we want to override it with the
154
- # docstring we found, assuming we found one.
155
- register_docstring(obj, docstring, nil) if docstring
156
- end
157
-
158
-
159
- # See:
160
- # https://docs.puppetlabs.com/guides/custom_types.html#namevar
161
- # node should be a parameter
162
- def is_namevar? node, param_name, type_name
163
- # Option 1:
164
- # Puppet::Type.newtype(:name) do
165
- # ...
166
- # newparam(:name) do
167
- # ...
168
- # end
169
- if type_name == param_name
170
- return true
171
- end
172
- # Option 2:
173
- # newparam(:path, :namevar => true) do
174
- # ...
175
- # end
176
- if node.children.length >= 2
177
- node.traverse do |s|
178
- if s.type == :assoc and s.jump(:ident).source == 'namevar' and s.jump(:kw).source == 'true'
179
- return true
180
- end
181
- end
182
- end
183
- # Option 3:
184
- # newparam(:path) do
185
- # isnamevar
186
- # ...
187
- # end
188
- do_block = node.jump(:do_block).traverse do |s|
189
- if is_a_func_call_named? 'isnamevar', s
190
- return true
191
- end
192
- end
193
- # Crazy implementations of types may just call #isnamevar directly on the object.
194
- # We don't handle this today.
195
- return false
196
- end
197
-
198
- def is_param? node
199
- is_a_func_call_named? 'newparam', node
200
- end
201
- def is_prop? node
202
- is_a_func_call_named? 'newproperty', node
203
- end
204
-
205
- def is_feature? node
206
- is_a_func_call_named? 'feature', node
207
- end
208
-
209
- def is_a_func_call_named? name, node
210
- (node.type == :fcall or node.type == :command or node.type == :vcall) and node.children.first.source == name
211
- end
212
-
213
- def get_feature node
214
- name = node[1].jump(:ident).source
215
- desc = node[1].jump(:tstring_content).source
216
- methods = []
217
- if node[1].length == 4 and node.children[1][2].jump(:ident).source == 'methods'
218
- arr = node[1][2].jump(:array)
219
- if arr != node[1][2]
220
- arr.traverse do |s|
221
- if s.type == :ident
222
- methods << s.source
223
- end
224
- end
225
- end
226
- end
227
- {
228
- :name => name,
229
- :desc => desc,
230
- :methods => methods != [] ? methods : nil,
231
- }
232
- end
233
-
234
- def get_parameter_allowed_values node
235
- vals = []
236
- node.traverse do |s|
237
- if is_a_func_call_named? 'newvalues', s
238
- list = s.jump(:list)
239
- if list != s
240
- vals += list.map { |item| [item.source] if YARD::Parser::Ruby::AstNode === item }
241
- end
242
- end
243
- end
244
- vals.compact
245
- end
246
-
247
- # Calls to newvalue only apply to properties, according to Dan & Nan's
248
- # "Puppet Types and Providers", page 30.
249
- def get_property_allowed_values node
250
- vals = get_parameter_allowed_values node
251
- node.traverse do |s|
252
- if is_a_func_call_named? 'newvalue', s
253
- required_features = nil
254
- s.traverse do |ss|
255
- if ss.type == :assoc and ss[0].source == ':required_features'
256
- required_features = ss[1].source
257
- end
258
- end
259
- list = s.jump(:list)
260
- if list != s
261
- vals << [list[0].source, required_features].compact
262
- end
263
- end
264
- end
265
- vals
266
- end
267
-
268
- def fetch_default node
269
- do_block = node.jump(:do_block)
270
- do_block.traverse do |s|
271
- if is_a_func_call_named? 'defaultto', s
272
- return s[-1].source
273
- end
274
- end
275
- nil
276
- end
277
-
278
- def fetch_description(fcall)
279
- fcall.traverse do |node|
280
- if is_a_func_call_named? 'desc', node
281
- content = node.jump(:string_content)
282
- if content != node
283
- @heredoc_helper = HereDocHelper.new
284
- if @heredoc_helper.is_heredoc? content.source
285
- docstring = @heredoc_helper.process_heredoc content.source
286
- else
287
- docstring = content.source
288
- end
289
- return docstring
290
- end
291
- end
292
- end
293
- return nil
294
- end
295
- end