openvox-strings 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +407 -0
  3. data/LICENSE +177 -0
  4. data/README.md +116 -0
  5. data/lib/openvox-strings/describe.rb +75 -0
  6. data/lib/openvox-strings/json.rb +33 -0
  7. data/lib/openvox-strings/markdown/base.rb +236 -0
  8. data/lib/openvox-strings/markdown/data_type.rb +39 -0
  9. data/lib/openvox-strings/markdown/defined_type.rb +20 -0
  10. data/lib/openvox-strings/markdown/function.rb +59 -0
  11. data/lib/openvox-strings/markdown/helpers.rb +21 -0
  12. data/lib/openvox-strings/markdown/puppet_class.rb +20 -0
  13. data/lib/openvox-strings/markdown/puppet_plan.rb +20 -0
  14. data/lib/openvox-strings/markdown/puppet_task.rb +29 -0
  15. data/lib/openvox-strings/markdown/resource_type.rb +56 -0
  16. data/lib/openvox-strings/markdown/templates/classes_and_defines.erb +94 -0
  17. data/lib/openvox-strings/markdown/templates/data_type.erb +101 -0
  18. data/lib/openvox-strings/markdown/templates/data_type_function.erb +67 -0
  19. data/lib/openvox-strings/markdown/templates/function.erb +106 -0
  20. data/lib/openvox-strings/markdown/templates/puppet_task.erb +28 -0
  21. data/lib/openvox-strings/markdown/templates/resource_type.erb +156 -0
  22. data/lib/openvox-strings/markdown/templates/table_of_contents.erb +26 -0
  23. data/lib/openvox-strings/markdown.rb +81 -0
  24. data/lib/openvox-strings/monkey_patches/display_object_command.rb +16 -0
  25. data/lib/openvox-strings/tasks/generate.rb +54 -0
  26. data/lib/openvox-strings/tasks/gh_pages.rb +72 -0
  27. data/lib/openvox-strings/tasks/validate.rb +42 -0
  28. data/lib/openvox-strings/tasks.rb +14 -0
  29. data/lib/openvox-strings/version.rb +5 -0
  30. data/lib/openvox-strings/yard/code_objects/base.rb +16 -0
  31. data/lib/openvox-strings/yard/code_objects/class.rb +60 -0
  32. data/lib/openvox-strings/yard/code_objects/data_type.rb +102 -0
  33. data/lib/openvox-strings/yard/code_objects/data_type_alias.rb +60 -0
  34. data/lib/openvox-strings/yard/code_objects/defined_type.rb +59 -0
  35. data/lib/openvox-strings/yard/code_objects/function.rb +106 -0
  36. data/lib/openvox-strings/yard/code_objects/group.rb +33 -0
  37. data/lib/openvox-strings/yard/code_objects/plan.rb +59 -0
  38. data/lib/openvox-strings/yard/code_objects/provider.rb +98 -0
  39. data/lib/openvox-strings/yard/code_objects/task.rb +69 -0
  40. data/lib/openvox-strings/yard/code_objects/type.rb +196 -0
  41. data/lib/openvox-strings/yard/code_objects.rb +14 -0
  42. data/lib/openvox-strings/yard/handlers/helpers.rb +10 -0
  43. data/lib/openvox-strings/yard/handlers/json/base.rb +8 -0
  44. data/lib/openvox-strings/yard/handlers/json/task_handler.rb +34 -0
  45. data/lib/openvox-strings/yard/handlers/puppet/base.rb +52 -0
  46. data/lib/openvox-strings/yard/handlers/puppet/class_handler.rb +29 -0
  47. data/lib/openvox-strings/yard/handlers/puppet/data_type_alias_handler.rb +26 -0
  48. data/lib/openvox-strings/yard/handlers/puppet/defined_type_handler.rb +29 -0
  49. data/lib/openvox-strings/yard/handlers/puppet/function_handler.rb +54 -0
  50. data/lib/openvox-strings/yard/handlers/puppet/plan_handler.rb +29 -0
  51. data/lib/openvox-strings/yard/handlers/ruby/base.rb +55 -0
  52. data/lib/openvox-strings/yard/handlers/ruby/data_type_handler.rb +411 -0
  53. data/lib/openvox-strings/yard/handlers/ruby/function_handler.rb +386 -0
  54. data/lib/openvox-strings/yard/handlers/ruby/provider_handler.rb +127 -0
  55. data/lib/openvox-strings/yard/handlers/ruby/rsapi_handler.rb +157 -0
  56. data/lib/openvox-strings/yard/handlers/ruby/type_base.rb +146 -0
  57. data/lib/openvox-strings/yard/handlers/ruby/type_extras_handler.rb +65 -0
  58. data/lib/openvox-strings/yard/handlers/ruby/type_handler.rb +105 -0
  59. data/lib/openvox-strings/yard/handlers.rb +28 -0
  60. data/lib/openvox-strings/yard/parsers/json/parser.rb +38 -0
  61. data/lib/openvox-strings/yard/parsers/json/task_statement.rb +37 -0
  62. data/lib/openvox-strings/yard/parsers/puppet/parser.rb +89 -0
  63. data/lib/openvox-strings/yard/parsers/puppet/statement.rb +182 -0
  64. data/lib/openvox-strings/yard/parsers.rb +14 -0
  65. data/lib/openvox-strings/yard/tags/enum_tag.rb +13 -0
  66. data/lib/openvox-strings/yard/tags/factory.rb +18 -0
  67. data/lib/openvox-strings/yard/tags/overload_tag.rb +112 -0
  68. data/lib/openvox-strings/yard/tags/parameter_directive.rb +25 -0
  69. data/lib/openvox-strings/yard/tags/property_directive.rb +25 -0
  70. data/lib/openvox-strings/yard/tags/summary_tag.rb +10 -0
  71. data/lib/openvox-strings/yard/tags.rb +11 -0
  72. data/lib/openvox-strings/yard/templates/default/fulldoc/html/css/common.css +8 -0
  73. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_class.erb +9 -0
  74. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_data_type.erb +10 -0
  75. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_defined_type.erb +9 -0
  76. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_function.erb +10 -0
  77. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_plan.erb +9 -0
  78. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_provider.erb +10 -0
  79. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_task.erb +9 -0
  80. data/lib/openvox-strings/yard/templates/default/fulldoc/html/full_list_puppet_type.erb +9 -0
  81. data/lib/openvox-strings/yard/templates/default/fulldoc/html/setup.rb +93 -0
  82. data/lib/openvox-strings/yard/templates/default/layout/html/footer.erb +3 -0
  83. data/lib/openvox-strings/yard/templates/default/layout/html/objects.erb +37 -0
  84. data/lib/openvox-strings/yard/templates/default/layout/html/setup.rb +231 -0
  85. data/lib/openvox-strings/yard/templates/default/puppet_class/html/box_info.erb +26 -0
  86. data/lib/openvox-strings/yard/templates/default/puppet_class/html/deprecated.erb +6 -0
  87. data/lib/openvox-strings/yard/templates/default/puppet_class/html/header.erb +1 -0
  88. data/lib/openvox-strings/yard/templates/default/puppet_class/html/note.erb +6 -0
  89. data/lib/openvox-strings/yard/templates/default/puppet_class/html/overview.erb +6 -0
  90. data/lib/openvox-strings/yard/templates/default/puppet_class/html/setup.rb +16 -0
  91. data/lib/openvox-strings/yard/templates/default/puppet_class/html/source.erb +12 -0
  92. data/lib/openvox-strings/yard/templates/default/puppet_class/html/summary.erb +4 -0
  93. data/lib/openvox-strings/yard/templates/default/puppet_class/html/todo.erb +6 -0
  94. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/box_info.erb +10 -0
  95. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/deprecated.erb +6 -0
  96. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/header.erb +1 -0
  97. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/method_details_list.erb +6 -0
  98. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/note.erb +6 -0
  99. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/overview.erb +6 -0
  100. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/setup.rb +15 -0
  101. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/source.erb +12 -0
  102. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/summary.erb +4 -0
  103. data/lib/openvox-strings/yard/templates/default/puppet_data_type/html/todo.erb +6 -0
  104. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/alias_of.erb +10 -0
  105. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/box_info.erb +10 -0
  106. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/deprecated.erb +6 -0
  107. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/header.erb +1 -0
  108. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/note.erb +6 -0
  109. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/overview.erb +6 -0
  110. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/setup.rb +19 -0
  111. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/source.erb +12 -0
  112. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/summary.erb +4 -0
  113. data/lib/openvox-strings/yard/templates/default/puppet_data_type_alias/html/todo.erb +6 -0
  114. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/box_info.erb +10 -0
  115. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/deprecated.erb +6 -0
  116. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/header.erb +1 -0
  117. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/note.erb +6 -0
  118. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/overview.erb +6 -0
  119. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/setup.rb +7 -0
  120. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/source.erb +12 -0
  121. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/summary.erb +4 -0
  122. data/lib/openvox-strings/yard/templates/default/puppet_defined_type/html/todo.erb +6 -0
  123. data/lib/openvox-strings/yard/templates/default/puppet_function/html/box_info.erb +14 -0
  124. data/lib/openvox-strings/yard/templates/default/puppet_function/html/deprecated.erb +6 -0
  125. data/lib/openvox-strings/yard/templates/default/puppet_function/html/header.erb +1 -0
  126. data/lib/openvox-strings/yard/templates/default/puppet_function/html/note.erb +6 -0
  127. data/lib/openvox-strings/yard/templates/default/puppet_function/html/overview.erb +18 -0
  128. data/lib/openvox-strings/yard/templates/default/puppet_function/html/setup.rb +7 -0
  129. data/lib/openvox-strings/yard/templates/default/puppet_function/html/source.erb +12 -0
  130. data/lib/openvox-strings/yard/templates/default/puppet_function/html/summary.erb +4 -0
  131. data/lib/openvox-strings/yard/templates/default/puppet_function/html/todo.erb +6 -0
  132. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/box_info.erb +10 -0
  133. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/deprecated.erb +6 -0
  134. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/header.erb +1 -0
  135. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/note.erb +6 -0
  136. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/overview.erb +6 -0
  137. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/setup.rb +13 -0
  138. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/source.erb +12 -0
  139. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/summary.erb +4 -0
  140. data/lib/openvox-strings/yard/templates/default/puppet_plan/html/todo.erb +6 -0
  141. data/lib/openvox-strings/yard/templates/default/puppet_provider/html/box_info.erb +14 -0
  142. data/lib/openvox-strings/yard/templates/default/puppet_provider/html/collection.erb +17 -0
  143. data/lib/openvox-strings/yard/templates/default/puppet_provider/html/features.erb +12 -0
  144. data/lib/openvox-strings/yard/templates/default/puppet_provider/html/header.erb +1 -0
  145. data/lib/openvox-strings/yard/templates/default/puppet_provider/html/overview.erb +6 -0
  146. data/lib/openvox-strings/yard/templates/default/puppet_provider/html/setup.rb +31 -0
  147. data/lib/openvox-strings/yard/templates/default/puppet_provider/html/summary.erb +4 -0
  148. data/lib/openvox-strings/yard/templates/default/puppet_task/html/box_info.erb +9 -0
  149. data/lib/openvox-strings/yard/templates/default/puppet_task/html/header.erb +1 -0
  150. data/lib/openvox-strings/yard/templates/default/puppet_task/html/input.erb +5 -0
  151. data/lib/openvox-strings/yard/templates/default/puppet_task/html/overview.erb +6 -0
  152. data/lib/openvox-strings/yard/templates/default/puppet_task/html/parameters.erb +16 -0
  153. data/lib/openvox-strings/yard/templates/default/puppet_task/html/setup.rb +24 -0
  154. data/lib/openvox-strings/yard/templates/default/puppet_task/html/supports_noop.erb +3 -0
  155. data/lib/openvox-strings/yard/templates/default/puppet_type/html/box_info.erb +20 -0
  156. data/lib/openvox-strings/yard/templates/default/puppet_type/html/deprecated.erb +6 -0
  157. data/lib/openvox-strings/yard/templates/default/puppet_type/html/features.erb +13 -0
  158. data/lib/openvox-strings/yard/templates/default/puppet_type/html/header.erb +1 -0
  159. data/lib/openvox-strings/yard/templates/default/puppet_type/html/note.erb +6 -0
  160. data/lib/openvox-strings/yard/templates/default/puppet_type/html/overview.erb +6 -0
  161. data/lib/openvox-strings/yard/templates/default/puppet_type/html/parameters.erb +35 -0
  162. data/lib/openvox-strings/yard/templates/default/puppet_type/html/setup.rb +36 -0
  163. data/lib/openvox-strings/yard/templates/default/puppet_type/html/summary.erb +4 -0
  164. data/lib/openvox-strings/yard/templates/default/puppet_type/html/todo.erb +6 -0
  165. data/lib/openvox-strings/yard/templates/default/tags/html/enum.erb +17 -0
  166. data/lib/openvox-strings/yard/templates/default/tags/html/puppet_overload.erb +12 -0
  167. data/lib/openvox-strings/yard/templates/default/tags/setup.rb +20 -0
  168. data/lib/openvox-strings/yard/util.rb +87 -0
  169. data/lib/openvox-strings/yard.rb +132 -0
  170. data/lib/openvox-strings.rb +88 -0
  171. data/lib/puppet/application/strings.rb +7 -0
  172. data/lib/puppet/face/strings.rb +185 -0
  173. data/lib/puppet/feature/rgen.rb +5 -0
  174. data/lib/puppet/feature/yard.rb +5 -0
  175. metadata +263 -0
@@ -0,0 +1,386 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openvox-strings/yard/handlers/helpers'
4
+ require 'openvox-strings/yard/handlers/ruby/base'
5
+ require 'openvox-strings/yard/code_objects'
6
+ require 'openvox-strings/yard/util'
7
+
8
+ # Implements the handler for Puppet functions written in Ruby.
9
+ class OpenvoxStrings::Yard::Handlers::Ruby::FunctionHandler < OpenvoxStrings::Yard::Handlers::Ruby::Base
10
+ # Represents the list of Puppet 4.x function API methods to support.
11
+ DISPATCH_METHOD_NAMES = %w[
12
+ param
13
+ required_param
14
+ optional_param
15
+ repeated_param
16
+ optional_repeated_param
17
+ required_repeated_param
18
+ block_param
19
+ required_block_param
20
+ optional_block_param
21
+ return_type
22
+ ].freeze
23
+
24
+ namespace_only
25
+ handles method_call(:create_function)
26
+ handles method_call(:newfunction)
27
+
28
+ process do
29
+ # Only accept calls to Puppet::Functions (4.x) or Puppet::Parser::Functions (3.x)
30
+ # When `newfunction` is separated from the Puppet::Parser::Functions module name by a
31
+ # newline, YARD ignores the namespace and uses `newfunction` as the source of the
32
+ # first statement.
33
+ return unless statement.count > 1
34
+
35
+ module_name = statement[0].source
36
+ return unless ['Puppet::Functions', 'Puppet::Parser::Functions', 'newfunction'].include?(module_name)
37
+
38
+ # Create and register the function object
39
+ is_3x = ['Puppet::Parser::Functions', 'newfunction'].include?(module_name)
40
+ object = OpenvoxStrings::Yard::CodeObjects::Function.new(
41
+ get_name(statement, 'Puppet::Functions.create_function'),
42
+ is_3x ? OpenvoxStrings::Yard::CodeObjects::Function::RUBY_3X : OpenvoxStrings::Yard::CodeObjects::Function::RUBY_4X
43
+ )
44
+ object.source = statement
45
+ register object
46
+
47
+ # For 3x, parse the doc parameter for the docstring
48
+ # This must be done after the `register` call above because `register` always uses the statement's docstring
49
+ if is_3x
50
+ docstring = get_3x_docstring(object.name)
51
+ register_docstring(object, docstring, nil) if docstring
52
+
53
+ # Default any typeless param tag to 'Any'
54
+ object.tags(:param).each do |tag|
55
+ tag.types = ['Any'] unless tag.types && !tag.types.empty?
56
+ end
57
+
58
+ # Populate the parameters and the return tag
59
+ object.parameters = object.tags(:param).map { |p| [p.name, nil] }
60
+ add_return_tag(object, statement.file, statement.line)
61
+ else
62
+ # For 4x, auto generate tags based on dispatch docstrings
63
+ add_tags(object)
64
+ end
65
+
66
+ # Mark the function as public if it doesn't already have an api tag
67
+ object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
68
+
69
+ # Warn if a summary longer than 140 characters was provided
70
+ OpenvoxStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary
71
+ end
72
+
73
+ private
74
+
75
+ def add_tags(object)
76
+ log.warn "Missing documentation for Puppet function '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty?
77
+
78
+ unless object.tags(:param).empty?
79
+ log.warn "The docstring for Puppet 4.x function '#{object.name}' " \
80
+ "contains @param tags near #{object.file}:#{object.line}: parameter " \
81
+ 'documentation should be made on the dispatch call.'
82
+ end
83
+
84
+ unless object.tags(:return).empty?
85
+ log.warn "The docstring for Puppet 4.x function '#{object.name}' " \
86
+ "contains @return tags near #{object.file}:#{object.line}: return " \
87
+ 'value documentation should be made on the dispatch call.'
88
+ end
89
+
90
+ unless object.tags(:overload).empty?
91
+ log.warn "The docstring for Puppet 4.x function '#{object.name}' " \
92
+ "contains @overload tags near #{object.file}:#{object.line}: overload " \
93
+ 'tags are automatically generated from the dispatch calls.'
94
+ end
95
+
96
+ # Delete any existing param/return/overload tags
97
+ object.docstring.delete_tags(:param)
98
+ object.docstring.delete_tags(:return)
99
+ object.docstring.delete_tags(:overload)
100
+
101
+ block = statement.block
102
+ return unless block && block.count >= 2
103
+
104
+ # Get the unqualified name of the Puppet function
105
+ unqualified_name = object.name.to_s.split('::').last
106
+
107
+ # Walk the block statements looking for dispatch calls and methods with the same name as the Puppet function
108
+ default = nil
109
+ block[1].children.each do |node|
110
+ if node.is_a?(YARD::Parser::Ruby::MethodCallNode)
111
+ add_overload_tag(object, node)
112
+ elsif node.is_a?(YARD::Parser::Ruby::MethodDefinitionNode)
113
+ default = node if node.method_name && node.method_name.source == unqualified_name
114
+ end
115
+ end
116
+
117
+ # Create an overload for the default method if there is one
118
+ overloads = object.tags(:overload)
119
+ if overloads.empty? && default
120
+ add_method_overload(object, default)
121
+ overloads = object.tags(:overload)
122
+ end
123
+
124
+ # If there's only one overload, move the tags to the object itself
125
+ return unless overloads.length == 1
126
+
127
+ overload = overloads.first
128
+ object.parameters = overload.parameters
129
+ object.add_tag(*overload.tags)
130
+ object.docstring.delete_tags(:overload)
131
+ end
132
+
133
+ def add_overload_tag(object, node)
134
+ # Look for a call to a dispatch method with a block
135
+ return unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) &&
136
+ node.method_name &&
137
+ node.method_name.source == 'dispatch' &&
138
+ node.parameters(false).count == 1 &&
139
+ node.block &&
140
+ node.block.count >= 2
141
+
142
+ overload_tag = OpenvoxStrings::Yard::Tags::OverloadTag.new(object.name, node.docstring || '')
143
+ param_tags = overload_tag.tags(:param)
144
+
145
+ block = nil
146
+ node.block[1].children.each do |child|
147
+ next unless child.is_a?(YARD::Parser::Ruby::MethodCallNode) && child.method_name
148
+
149
+ method_name = child.method_name.source
150
+ next unless DISPATCH_METHOD_NAMES.include?(method_name)
151
+
152
+ if method_name == 'return_type'
153
+ # Add a return tag if missing
154
+ overload_tag.add_tag YARD::Tags::Tag.new(:return, '', 'Any') if overload_tag.tag(:return).nil?
155
+
156
+ overload_tag.tag(:return).types = [node_as_string(child.parameters[0])]
157
+ next
158
+ end
159
+
160
+ # Check for block
161
+ if method_name.include?('block')
162
+ if block
163
+ log.warn "A duplicate block parameter was found for Puppet function '#{object.name}' at #{child.file}:#{child.line}."
164
+ next
165
+ end
166
+
167
+ # Store the block; needs to be appended last
168
+ block = child
169
+ next
170
+ end
171
+
172
+ # Ensure two parameters to parameter definition
173
+ parameters = child.parameters(false)
174
+ unless parameters.count == 2
175
+ log.warn "Expected 2 arguments to '#{method_name}' call at #{child.file}:#{child.line}: parameter information may not be correct."
176
+ next
177
+ end
178
+
179
+ add_param_tag(
180
+ overload_tag,
181
+ param_tags,
182
+ node_as_string(parameters[1]),
183
+ child.file,
184
+ child.line,
185
+ node_as_string(parameters[0]),
186
+ nil, # TODO: determine default from corresponding Ruby method signature?
187
+ method_name.include?('optional'),
188
+ method_name.include?('repeated')
189
+ )
190
+ end
191
+
192
+ # Handle the block parameter after others so it appears last in the list
193
+ if block
194
+ parameters = block.parameters(false)
195
+ if parameters.empty?
196
+ name = 'block'
197
+ type = 'Callable'
198
+ elsif parameters.count == 1
199
+ name = node_as_string(parameters[0])
200
+ type = 'Callable'
201
+ elsif parameters.count == 2
202
+ type = node_as_string(parameters[0])
203
+ name = node_as_string(parameters[1])
204
+ else
205
+ log.warn "Unexpected number of arguments to block definition at #{block.file}:#{block.line}."
206
+ end
207
+
208
+ if name && type
209
+ add_param_tag(
210
+ overload_tag,
211
+ param_tags,
212
+ name,
213
+ block.file,
214
+ block.line,
215
+ type,
216
+ nil, # TODO: determine default from corresponding Ruby method signature?
217
+ block.method_name.source.include?('optional'),
218
+ false, # Not repeated
219
+ true # Is block
220
+ )
221
+ end
222
+ end
223
+
224
+ # Add a return tag if missing
225
+ add_return_tag(overload_tag, node.file, node.line)
226
+
227
+ # Validate that tags have parameters
228
+ validate_overload(overload_tag, node.file, node.line)
229
+
230
+ object.add_tag overload_tag
231
+ end
232
+
233
+ def add_method_overload(object, node)
234
+ overload_tag = OpenvoxStrings::Yard::Tags::OverloadTag.new(object.name, node.docstring || '')
235
+ param_tags = overload_tag.tags(:param)
236
+
237
+ parameters = node.parameters
238
+
239
+ # Populate the required parameters
240
+ params = parameters.unnamed_required_params
241
+ params&.each do |parameter|
242
+ add_param_tag(
243
+ overload_tag,
244
+ param_tags,
245
+ parameter.source,
246
+ parameter.file,
247
+ parameter.line
248
+ )
249
+ end
250
+
251
+ # Populate the optional parameters
252
+ params = parameters.unnamed_optional_params
253
+ params&.each do |parameter|
254
+ add_param_tag(
255
+ overload_tag,
256
+ param_tags,
257
+ parameter[0].source,
258
+ parameter.file,
259
+ parameter.line,
260
+ nil,
261
+ parameter[1].source,
262
+ true
263
+ )
264
+ end
265
+
266
+ # Populate the splat parameter
267
+ param = parameters.splat_param
268
+ if param
269
+ add_param_tag(
270
+ overload_tag,
271
+ param_tags,
272
+ param.source,
273
+ param.file,
274
+ param.line,
275
+ nil,
276
+ nil,
277
+ false,
278
+ true
279
+ )
280
+ end
281
+
282
+ # Populate the block parameter
283
+ param = parameters.block_param
284
+ if param
285
+ add_param_tag(
286
+ overload_tag,
287
+ param_tags,
288
+ param.source,
289
+ param.file,
290
+ param.line,
291
+ nil,
292
+ nil,
293
+ false,
294
+ false,
295
+ true
296
+ )
297
+ end
298
+
299
+ # Add a return tag if missing
300
+ add_return_tag(overload_tag, node.file, node.line)
301
+
302
+ # Validate that tags have parameters
303
+ validate_overload(overload_tag, node.file, node.line)
304
+
305
+ object.add_tag overload_tag
306
+ end
307
+
308
+ def add_param_tag(object, tags, name, file, line, type = nil, default = nil, optional = false, repeated = false, block = false)
309
+ tag = tags.find { |t| t.name == name } if tags
310
+ log.warn "Missing @param tag for parameter '#{name}' near #{file}:#{line}." unless tag || object.docstring.all.empty?
311
+
312
+ if type && tag && tag.types && !tag.types.empty?
313
+ log.warn "The @param tag for parameter '#{name}' should not contain a " \
314
+ "type specification near #{file}:#{line}: ignoring in favor of " \
315
+ 'dispatch type information.'
316
+ end
317
+
318
+ if repeated
319
+ name = "*#{name}"
320
+ elsif block
321
+ name = "&#{name}"
322
+ end
323
+
324
+ type ||= tag&.types ? tag.type : 'Any'
325
+ type = "Optional[#{type}]" if optional
326
+
327
+ object.parameters << [name, to_puppet_literal(default)]
328
+
329
+ if tag
330
+ tag.name = name
331
+ tag.types = [type]
332
+ else
333
+ object.add_tag YARD::Tags::Tag.new(:param, '', type, name)
334
+ end
335
+ end
336
+
337
+ def add_return_tag(object, file, line)
338
+ tag = object.tag(:return)
339
+ if tag
340
+ tag.types = ['Any'] unless tag.types
341
+ return
342
+ end
343
+ log.warn "Missing @return tag near #{file}:#{line}."
344
+ object.add_tag YARD::Tags::Tag.new(:return, '', 'Any')
345
+ end
346
+
347
+ def validate_overload(overload, file, line)
348
+ # Validate that tags have matching parameters
349
+ overload.tags(:param).each do |tag|
350
+ next if overload.parameters.find { |p| tag.name == p[0] }
351
+
352
+ log.warn "The @param tag for parameter '#{tag.name}' has no matching parameter at #{file}:#{line}."
353
+ end
354
+ end
355
+
356
+ def get_3x_docstring(name)
357
+ parameters = statement.parameters(false)
358
+ if parameters.count >= 2
359
+ parameters[1].each do |kvp|
360
+ next unless kvp.count == 2
361
+ next unless node_as_string(kvp[0]) == 'doc'
362
+
363
+ docstring = node_as_string(kvp[1])
364
+
365
+ log.error "Failed to parse docstring for 3.x Puppet function '#{name}' near #{statement.file}:#{statement.line}." and return nil unless docstring
366
+
367
+ return OpenvoxStrings::Yard::Util.scrub_string(docstring)
368
+ end
369
+ end
370
+
371
+ # Log a warning for missing docstring
372
+ log.warn "Missing documentation for Puppet function '#{name}' at #{statement.file}:#{statement.line}."
373
+ nil
374
+ end
375
+
376
+ def to_puppet_literal(literal)
377
+ case literal
378
+ when 'nil'
379
+ 'undef'
380
+ when ':default'
381
+ 'default'
382
+ else
383
+ literal
384
+ end
385
+ end
386
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openvox-strings/yard/handlers/helpers'
4
+ require 'openvox-strings/yard/handlers/ruby/base'
5
+ require 'openvox-strings/yard/code_objects'
6
+ require 'openvox-strings/yard/util'
7
+
8
+ # Implements the handler for Puppet providers written in Ruby.
9
+ class OpenvoxStrings::Yard::Handlers::Ruby::ProviderHandler < OpenvoxStrings::Yard::Handlers::Ruby::Base
10
+ namespace_only
11
+ handles method_call(:provide)
12
+
13
+ process do
14
+ return unless statement.count >= 2
15
+
16
+ # Check that provide is being called on Puppet::Type.type(<name>)
17
+ type_call = statement[0]
18
+ return unless type_call.is_a?(YARD::Parser::Ruby::MethodCallNode) && type_call.count >= 3
19
+ return unless type_call[0].source == 'Puppet::Type'
20
+ return unless type_call[2].source == 'type'
21
+
22
+ # Extract the type name
23
+ type_call_parameters = type_call.parameters(false)
24
+ return unless type_call_parameters.count >= 1
25
+
26
+ type_name = node_as_string(type_call_parameters.first)
27
+ raise YARD::Parser::UndocumentableError, "Could not determine the resource type name for the provider defined at #{statement.file}:#{statement.line}." unless type_name
28
+
29
+ # Register the object
30
+ object = OpenvoxStrings::Yard::CodeObjects::Provider.new(type_name, get_name(statement, "'provide'"))
31
+ register object
32
+
33
+ # Extract the docstring
34
+ register_provider_docstring object
35
+
36
+ # Populate the provider data
37
+ populate_provider_data object
38
+
39
+ # Mark the provider as public if it doesn't already have an api tag
40
+ object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
41
+
42
+ # Warn if a summary longer than 140 characters was provided
43
+ OpenvoxStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary
44
+ end
45
+
46
+ private
47
+
48
+ def register_provider_docstring(object)
49
+ # Walk the tree searching for assignments or calls to desc/doc=
50
+ statement.traverse do |child|
51
+ if child.type == :assign
52
+ ivar = child.jump(:ivar)
53
+ next unless ivar != child && ivar.source == '@doc'
54
+
55
+ docstring = node_as_string(child[1])
56
+ log.error "Failed to parse docstring for Puppet provider '#{object.name}' (resource type '#{object.type_name}') near #{child.file}:#{child.line}." and return nil unless docstring
57
+
58
+ register_docstring(object, OpenvoxStrings::Yard::Util.scrub_string(docstring), nil)
59
+ return nil
60
+ elsif child.is_a?(YARD::Parser::Ruby::MethodCallNode)
61
+ # Look for a call to a dispatch method with a block
62
+ next unless
63
+ child.method_name &&
64
+ ['desc', 'doc='].include?(child.method_name.source) &&
65
+ child.parameters(false).count == 1
66
+
67
+ docstring = node_as_string(child.parameters[0])
68
+ log.error "Failed to parse docstring for Puppet provider '#{object.name}' (resource type '#{object.type_name}') near #{child.file}:#{child.line}." and return nil unless docstring
69
+
70
+ register_docstring(object, OpenvoxStrings::Yard::Util.scrub_string(docstring), nil)
71
+ return nil
72
+ end
73
+ end
74
+ log.warn "Missing a description for Puppet provider '#{object.name}' (resource type '#{object.type_name}') at #{statement.file}:#{statement.line}."
75
+ end
76
+
77
+ def populate_provider_data(object)
78
+ # Traverse the block looking for confines/defaults/commands
79
+ block = statement.block
80
+ return unless block && block.count >= 2
81
+
82
+ block[1].children.each do |node|
83
+ next unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) && node.method_name
84
+
85
+ method_name = node.method_name.source
86
+ parameters = node.parameters(false)
87
+
88
+ if method_name == 'confine'
89
+ # Add a confine to the object
90
+ next unless parameters.count >= 1
91
+
92
+ parameters[0].each do |kvp|
93
+ next unless kvp.count == 2
94
+
95
+ object.add_confine(node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source)
96
+ end
97
+ elsif %w[has_feature has_features].include?(method_name)
98
+ # Add the features to the object
99
+ parameters.each do |parameter|
100
+ object.add_feature(node_as_string(parameter) || parameter.source)
101
+ end
102
+ elsif method_name == 'defaultfor'
103
+ # Add a default to the object
104
+ next unless parameters.count >= 1
105
+
106
+ # Some defaultfor statements contain multiple constraints.
107
+ parameters.each do |kvps|
108
+ next unless kvps.count >= 1
109
+
110
+ defaultfor = kvps.map do |kvp|
111
+ [node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source]
112
+ end
113
+ object.add_default(defaultfor)
114
+ end
115
+ elsif method_name == 'commands'
116
+ # Add the commands to the object
117
+ next unless parameters.count >= 1
118
+
119
+ parameters[0].each do |kvp|
120
+ next unless kvp.count == 2
121
+
122
+ object.add_command(node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source)
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openvox-strings/yard/handlers/helpers'
4
+ require 'openvox-strings/yard/handlers/ruby/base'
5
+ require 'openvox-strings/yard/code_objects'
6
+ require 'openvox-strings/yard/util'
7
+
8
+ # Implements the handler for Puppet resource types written in Ruby.
9
+ class OpenvoxStrings::Yard::Handlers::Ruby::RsapiHandler < OpenvoxStrings::Yard::Handlers::Ruby::Base
10
+ # The default docstring when ensurable is used without given a docstring.
11
+ DEFAULT_ENSURABLE_DOCSTRING = 'The basic property that the resource should be in.'
12
+
13
+ namespace_only
14
+ handles method_call(:register_type)
15
+
16
+ process do
17
+ # Only accept calls to Puppet::ResourceApi
18
+ return unless statement.count > 1
19
+
20
+ module_name = statement[0].source
21
+ return unless ['Puppet::ResourceApi'].include? module_name
22
+
23
+ schema = extract_schema
24
+
25
+ # puts "Schema: #{schema.inspect}"
26
+
27
+ object = OpenvoxStrings::Yard::CodeObjects::Type.new(schema['name'])
28
+ register object
29
+
30
+ docstring = schema['docs']
31
+ if docstring
32
+ register_docstring(object, OpenvoxStrings::Yard::Util.scrub_string(docstring.to_s), nil)
33
+ else
34
+ log.warn "Missing a description for Puppet resource type '#{object.name}' at #{statement.file}:#{statement.line}."
35
+ end
36
+
37
+ # Populate the parameters/properties/features to the type
38
+ populate_type_data(object, schema)
39
+
40
+ # Mark the type as public if it doesn't already have an api tag
41
+ object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
42
+
43
+ # Warn if a summary longer than 140 characters was provided
44
+ OpenvoxStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary
45
+ end
46
+
47
+ private
48
+
49
+ def raise_parse_error(msg, location = statement)
50
+ raise YARD::Parser::UndocumentableError, "#{msg} at #{location.file}:#{location.line}."
51
+ end
52
+
53
+ # check that the params of the register_type call are key/value pairs.
54
+ def kv_arg_list?(params)
55
+ params.type == :list &&
56
+ params.children.count.positive? &&
57
+ params.children.first.type == :list &&
58
+ params.children.first.children.count.positive? &&
59
+ statement.parameters.children.first.children.first.type == :assoc
60
+ end
61
+
62
+ def extract_schema
63
+ raise_parse_error('Expected list of key/value pairs as argument') unless kv_arg_list?(statement.parameters)
64
+ hash_from_node(statement.parameters.children.first)
65
+ end
66
+
67
+ def value_from_node(node)
68
+ return nil unless node
69
+
70
+ # puts "value from #{node.inspect}"
71
+
72
+ case node.type
73
+ when :int
74
+ node.source.to_i
75
+ when :hash
76
+ hash_from_node(node)
77
+ when :array
78
+ array_from_node(node)
79
+ when :var_ref
80
+ var_ref_from_node(node)
81
+ when :symbol, :symbol_literal, :label, :dyna_symbol, :string_literal, :regexp_literal
82
+ node_as_string(node)
83
+ else
84
+ raise_parse_error("unexpected construct #{node.type}")
85
+ end
86
+ end
87
+
88
+ def array_from_node(node)
89
+ return nil unless node
90
+
91
+ node.children.map do |assoc|
92
+ value_from_node(assoc.children[0])
93
+ end
94
+ end
95
+
96
+ def hash_from_node(node)
97
+ return nil unless node
98
+
99
+ # puts "hash from #{node.inspect}"
100
+
101
+ kv_pairs = node.children.map do |assoc|
102
+ [value_from_node(assoc.children[0]), value_from_node(assoc.children[1])]
103
+ end
104
+ kv_pairs.to_h
105
+ end
106
+
107
+ def var_ref_from_node(node)
108
+ return nil unless node
109
+
110
+ # puts "var_ref from #{node.inspect}"
111
+
112
+ if node.children.first.type == :kw
113
+ case node.children.first.source
114
+ when 'false'
115
+ return false
116
+ when 'true'
117
+ return true
118
+ when 'nil'
119
+ return nil
120
+ else
121
+ raise_parse_error("unexpected keyword '#{node.children.first.source}'")
122
+ end
123
+ end
124
+ raise_parse_error('unexpected variable')
125
+ end
126
+
127
+ def populate_type_data(object, schema)
128
+ return if schema['attributes'].nil?
129
+
130
+ schema['attributes'].each do |name, definition|
131
+ # puts "Processing #{name}: #{definition.inspect}"
132
+ if %w[parameter namevar].include? definition['behaviour']
133
+ object.add_parameter(create_parameter(name, definition))
134
+ else
135
+ object.add_property(create_property(name, definition))
136
+ end
137
+ end
138
+ end
139
+
140
+ def create_parameter(name, definition)
141
+ parameter = OpenvoxStrings::Yard::CodeObjects::Type::Parameter.new(name, definition['desc'])
142
+ set_values(definition, parameter)
143
+ parameter
144
+ end
145
+
146
+ def create_property(name, definition)
147
+ property = OpenvoxStrings::Yard::CodeObjects::Type::Property.new(name, definition['desc'])
148
+ set_values(definition, property)
149
+ property
150
+ end
151
+
152
+ def set_values(definition, object)
153
+ object.data_type = definition['type'] if definition.key? 'type'
154
+ object.default = definition['default'] if definition.key? 'default'
155
+ object.isnamevar = definition.key?('behaviour') && definition['behaviour'] == 'namevar'
156
+ end
157
+ end