puppet-strings 2.3.0 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +102 -4
- data/COMMITTERS.md +17 -17
- data/CONTRIBUTING.md +37 -7
- data/README.md +17 -12
- data/lib/puppet-strings.rb +5 -3
- data/lib/puppet-strings/describe.rb +2 -0
- data/lib/puppet-strings/json.rb +2 -0
- data/lib/puppet-strings/markdown.rb +12 -10
- data/lib/puppet-strings/markdown/base.rb +30 -3
- data/lib/puppet-strings/markdown/data_type.rb +18 -0
- data/lib/puppet-strings/markdown/data_types.rb +3 -1
- data/lib/puppet-strings/markdown/defined_type.rb +2 -0
- data/lib/puppet-strings/markdown/defined_types.rb +3 -1
- data/lib/puppet-strings/markdown/function.rb +9 -7
- data/lib/puppet-strings/markdown/functions.rb +3 -1
- data/lib/puppet-strings/markdown/puppet_class.rb +2 -0
- data/lib/puppet-strings/markdown/puppet_classes.rb +3 -1
- data/lib/puppet-strings/markdown/puppet_plan.rb +2 -0
- data/lib/puppet-strings/markdown/puppet_plans.rb +3 -1
- data/lib/puppet-strings/markdown/puppet_task.rb +2 -0
- data/lib/puppet-strings/markdown/puppet_tasks.rb +3 -1
- data/lib/puppet-strings/markdown/resource_type.rb +21 -2
- data/lib/puppet-strings/markdown/resource_types.rb +3 -1
- data/lib/puppet-strings/markdown/table_of_contents.rb +3 -1
- data/lib/puppet-strings/markdown/templates/classes_and_defines.erb +18 -6
- data/lib/puppet-strings/markdown/templates/data_type.erb +30 -7
- data/lib/puppet-strings/markdown/templates/data_type_function.erb +67 -0
- data/lib/puppet-strings/markdown/templates/function.erb +10 -1
- data/lib/puppet-strings/markdown/templates/puppet_task.erb +1 -1
- data/lib/puppet-strings/markdown/templates/resource_type.erb +35 -13
- data/lib/puppet-strings/markdown/templates/table_of_contents.erb +6 -6
- data/lib/puppet-strings/monkey_patches/display_object_command.rb +2 -0
- data/lib/puppet-strings/tasks.rb +2 -0
- data/lib/puppet-strings/tasks/generate.rb +2 -0
- data/lib/puppet-strings/tasks/gh_pages.rb +3 -0
- data/lib/puppet-strings/version.rb +3 -1
- data/lib/puppet-strings/yard.rb +9 -0
- data/lib/puppet-strings/yard/code_objects.rb +2 -0
- data/lib/puppet-strings/yard/code_objects/base.rb +2 -0
- data/lib/puppet-strings/yard/code_objects/class.rb +4 -2
- data/lib/puppet-strings/yard/code_objects/data_type.rb +30 -8
- data/lib/puppet-strings/yard/code_objects/data_type_alias.rb +2 -0
- data/lib/puppet-strings/yard/code_objects/defined_type.rb +4 -2
- data/lib/puppet-strings/yard/code_objects/function.rb +8 -5
- data/lib/puppet-strings/yard/code_objects/group.rb +3 -0
- data/lib/puppet-strings/yard/code_objects/plan.rb +4 -2
- data/lib/puppet-strings/yard/code_objects/provider.rb +6 -0
- data/lib/puppet-strings/yard/code_objects/task.rb +3 -1
- data/lib/puppet-strings/yard/code_objects/type.rb +49 -5
- data/lib/puppet-strings/yard/handlers.rb +2 -0
- data/lib/puppet-strings/yard/handlers/helpers.rb +2 -0
- data/lib/puppet-strings/yard/handlers/json/base.rb +2 -0
- data/lib/puppet-strings/yard/handlers/json/task_handler.rb +2 -0
- data/lib/puppet-strings/yard/handlers/puppet/base.rb +3 -0
- data/lib/puppet-strings/yard/handlers/puppet/class_handler.rb +2 -0
- data/lib/puppet-strings/yard/handlers/puppet/data_type_alias_handler.rb +2 -0
- data/lib/puppet-strings/yard/handlers/puppet/defined_type_handler.rb +2 -0
- data/lib/puppet-strings/yard/handlers/puppet/function_handler.rb +3 -1
- data/lib/puppet-strings/yard/handlers/puppet/plan_handler.rb +2 -0
- data/lib/puppet-strings/yard/handlers/ruby/base.rb +5 -0
- data/lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb +225 -52
- data/lib/puppet-strings/yard/handlers/ruby/function_handler.rb +9 -7
- data/lib/puppet-strings/yard/handlers/ruby/provider_handler.rb +13 -0
- data/lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb +4 -1
- data/lib/puppet-strings/yard/handlers/ruby/type_base.rb +20 -6
- data/lib/puppet-strings/yard/handlers/ruby/type_extras_handler.rb +6 -3
- data/lib/puppet-strings/yard/handlers/ruby/type_handler.rb +18 -1
- data/lib/puppet-strings/yard/parsers.rb +2 -0
- data/lib/puppet-strings/yard/parsers/json/parser.rb +2 -0
- data/lib/puppet-strings/yard/parsers/json/task_statement.rb +2 -0
- data/lib/puppet-strings/yard/parsers/puppet/parser.rb +18 -14
- data/lib/puppet-strings/yard/parsers/puppet/statement.rb +4 -0
- data/lib/puppet-strings/yard/tags.rb +4 -0
- data/lib/puppet-strings/yard/tags/enum_tag.rb +14 -0
- data/lib/puppet-strings/yard/tags/factory.rb +18 -0
- data/lib/puppet-strings/yard/tags/overload_tag.rb +4 -1
- data/lib/puppet-strings/yard/tags/parameter_directive.rb +5 -4
- data/lib/puppet-strings/yard/tags/property_directive.rb +5 -4
- data/lib/puppet-strings/yard/tags/summary_tag.rb +2 -0
- data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/method_details_list.erb +6 -0
- data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/setup.rb +9 -1
- data/lib/puppet-strings/yard/templates/default/puppet_function/html/setup.rb +1 -1
- data/lib/puppet-strings/yard/templates/default/puppet_type/html/setup.rb +3 -1
- data/lib/puppet-strings/yard/templates/default/tags/html/enum.erb +17 -0
- data/lib/puppet-strings/yard/templates/default/tags/setup.rb +6 -0
- data/lib/puppet-strings/yard/util.rb +7 -4
- data/lib/puppet/application/strings.rb +2 -0
- data/lib/puppet/face/strings.rb +4 -1
- data/lib/puppet/feature/rgen.rb +2 -0
- data/lib/puppet/feature/yard.rb +2 -0
- metadata +14 -51
- data/Gemfile +0 -47
- data/HISTORY.md +0 -218
- data/JSON.md +0 -832
- data/Rakefile +0 -168
- data/codecov.yml +0 -3
- data/misc/ANNOUNCEMENT_TEMPLATE.md +0 -40
- data/spec/acceptance/emit_json_options_spec.rb +0 -69
- data/spec/acceptance/generate_markdown_spec.rb +0 -47
- data/spec/acceptance/running_strings_generate_spec.rb +0 -78
- data/spec/fixtures/acceptance/modules/test/functions/add.pp +0 -9
- data/spec/fixtures/acceptance/modules/test/lib/puppet/functions/4x_function.rb +0 -5
- data/spec/fixtures/acceptance/modules/test/lib/puppet/parser/functions/function3x.rb +0 -2
- data/spec/fixtures/acceptance/modules/test/lib/puppet/provider/server/linux.rb +0 -9
- data/spec/fixtures/acceptance/modules/test/lib/puppet/type/database.rb +0 -15
- data/spec/fixtures/acceptance/modules/test/manifests/init.pp +0 -27
- data/spec/fixtures/acceptance/modules/test/manifests/triple_nested_classes.pp +0 -27
- data/spec/fixtures/acceptance/modules/test/metadata.json +0 -10
- data/spec/fixtures/acceptance/modules/test/types/elephant.pp +0 -2
- data/spec/fixtures/unit/markdown/output.md +0 -508
- data/spec/fixtures/unit/markdown/output_with_data_types.md +0 -553
- data/spec/fixtures/unit/markdown/output_with_plan.md +0 -542
- data/spec/spec_helper.rb +0 -49
- data/spec/spec_helper_acceptance.rb +0 -58
- data/spec/spec_helper_acceptance_local.rb +0 -10
- data/spec/unit/puppet-strings/describe_spec.rb +0 -141
- data/spec/unit/puppet-strings/json_spec.rb +0 -302
- data/spec/unit/puppet-strings/markdown/base_spec.rb +0 -146
- data/spec/unit/puppet-strings/markdown_spec.rb +0 -357
- data/spec/unit/puppet-strings/yard/code_objects/task_spec.rb +0 -92
- data/spec/unit/puppet-strings/yard/handlers/json/task_handler_spec.rb +0 -116
- data/spec/unit/puppet-strings/yard/handlers/puppet/class_handler_spec.rb +0 -217
- data/spec/unit/puppet-strings/yard/handlers/puppet/data_type_alias_handler_spec.rb +0 -65
- data/spec/unit/puppet-strings/yard/handlers/puppet/defined_type_handler_spec.rb +0 -231
- data/spec/unit/puppet-strings/yard/handlers/puppet/function_handler_spec.rb +0 -315
- data/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb +0 -232
- data/spec/unit/puppet-strings/yard/handlers/ruby/function_handler_spec.rb +0 -746
- data/spec/unit/puppet-strings/yard/handlers/ruby/provider_handler_spec.rb +0 -158
- data/spec/unit/puppet-strings/yard/handlers/ruby/rsapi_handler_spec.rb +0 -235
- data/spec/unit/puppet-strings/yard/handlers/ruby/type_handler_spec.rb +0 -311
- data/spec/unit/puppet-strings/yard/parsers/json/parser_spec.rb +0 -72
- data/spec/unit/puppet-strings/yard/parsers/json/task_statement_spec.rb +0 -56
- data/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb +0 -251
- data/spec/unit/puppet-strings/yard/util_spec.rb +0 -48
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/code_objects/group'
|
2
4
|
|
3
5
|
# Implements the group for Puppet functions.
|
@@ -61,11 +63,12 @@ class PuppetStrings::Yard::CodeObjects::Function < PuppetStrings::Yard::CodeObje
|
|
61
63
|
# @return [String] Returns the Puppet signature of the function.
|
62
64
|
def signature
|
63
65
|
return '' if self.has_tag? :overload
|
66
|
+
|
64
67
|
tags = self.tags(:param)
|
65
68
|
args = @parameters.map do |parameter|
|
66
69
|
name, default = parameter
|
67
70
|
tag = tags.find { |t| t.name == name } if tags
|
68
|
-
type = tag
|
71
|
+
type = tag&.types ? "#{tag.type} " : 'Any '
|
69
72
|
prefix = "#{name[0]}" if name.start_with?('*', '&')
|
70
73
|
name = name[1..-1] if prefix
|
71
74
|
default = " = #{default}" if default
|
@@ -88,16 +91,16 @@ class PuppetStrings::Yard::CodeObjects::Function < PuppetStrings::Yard::CodeObje
|
|
88
91
|
if self.has_tag? :overload
|
89
92
|
# loop over overloads and append onto the signatures array
|
90
93
|
self.tags(:overload).each do |o|
|
91
|
-
hash[:signatures] << { :signature => o.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(o.docstring, %i[param option return example]) }
|
94
|
+
hash[:signatures] << { :signature => o.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(o.docstring, %i[param option enum return example]) }
|
92
95
|
end
|
93
96
|
else
|
94
|
-
hash[:signatures] << { :signature => self.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(docstring, %i[param option return example]) }
|
97
|
+
hash[:signatures] << { :signature => self.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(docstring, %i[param option enum return example]) }
|
95
98
|
end
|
96
99
|
|
97
100
|
hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
|
98
101
|
defaults = Hash[*parameters.reject{ |p| p[1].nil? }.flatten]
|
99
|
-
hash[:defaults] = defaults unless defaults.empty?
|
100
|
-
hash[:source] = source unless source
|
102
|
+
hash[:defaults] = defaults unless defaults.nil? || defaults.empty?
|
103
|
+
hash[:source] = source unless source.nil? || source.empty?
|
101
104
|
hash
|
102
105
|
end
|
103
106
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/code_objects/base'
|
2
4
|
|
3
5
|
# Implements the base class for "groups".
|
@@ -10,6 +12,7 @@ class PuppetStrings::Yard::CodeObjects::Group < PuppetStrings::Yard::CodeObjects
|
|
10
12
|
def self.instance(key)
|
11
13
|
instance = P(:root, key)
|
12
14
|
return instance unless instance.is_a?(YARD::CodeObjects::Proxy)
|
15
|
+
|
13
16
|
instance = self.new(:root, key)
|
14
17
|
instance.visibility = :hidden
|
15
18
|
P(:root).children << instance
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/code_objects/group'
|
2
4
|
|
3
5
|
class PuppetStrings::Yard::CodeObjects::Plans < PuppetStrings::Yard::CodeObjects::Group
|
@@ -49,8 +51,8 @@ class PuppetStrings::Yard::CodeObjects::Plan < PuppetStrings::Yard::CodeObjects:
|
|
49
51
|
hash[:line] = line
|
50
52
|
hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
|
51
53
|
defaults = Hash[*parameters.reject{ |p| p[1].nil? }.flatten]
|
52
|
-
hash[:defaults] = defaults unless defaults.empty?
|
53
|
-
hash[:source] = source unless source
|
54
|
+
hash[:defaults] = defaults unless defaults.nil? || defaults.empty?
|
55
|
+
hash[:source] = source unless source.nil? || source.empty?
|
54
56
|
hash
|
55
57
|
end
|
56
58
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/code_objects/group'
|
2
4
|
|
3
5
|
# Implements the group for Puppet providers.
|
@@ -42,6 +44,7 @@ class PuppetStrings::Yard::CodeObjects::Provider < PuppetStrings::Yard::CodeObje
|
|
42
44
|
# @return [void]
|
43
45
|
def add_confine(key, value)
|
44
46
|
return unless key && value
|
47
|
+
|
45
48
|
@confines ||= {}
|
46
49
|
@confines[key] = value
|
47
50
|
end
|
@@ -51,6 +54,7 @@ class PuppetStrings::Yard::CodeObjects::Provider < PuppetStrings::Yard::CodeObje
|
|
51
54
|
# @return [void]
|
52
55
|
def add_feature(feature)
|
53
56
|
return unless feature
|
57
|
+
|
54
58
|
@features ||= []
|
55
59
|
@features << feature
|
56
60
|
end
|
@@ -60,6 +64,7 @@ class PuppetStrings::Yard::CodeObjects::Provider < PuppetStrings::Yard::CodeObje
|
|
60
64
|
# @return [void]
|
61
65
|
def add_default(constraints)
|
62
66
|
return unless constraints
|
67
|
+
|
63
68
|
@defaults ||= []
|
64
69
|
@defaults << constraints
|
65
70
|
end
|
@@ -70,6 +75,7 @@ class PuppetStrings::Yard::CodeObjects::Provider < PuppetStrings::Yard::CodeObje
|
|
70
75
|
# @return [void]
|
71
76
|
def add_command(key, value)
|
72
77
|
return unless key && value
|
78
|
+
|
73
79
|
@commands ||= {}
|
74
80
|
@commands[key] = value
|
75
81
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/code_objects/group'
|
2
4
|
|
3
5
|
# Implements the group for Puppet tasks.
|
@@ -43,7 +45,7 @@ class PuppetStrings::Yard::CodeObjects::Task < PuppetStrings::Yard::CodeObjects:
|
|
43
45
|
|
44
46
|
def parameters
|
45
47
|
parameters = []
|
46
|
-
statement.
|
48
|
+
statement.parameters.each do |name,props|
|
47
49
|
parameters.push({ name: name.to_s,
|
48
50
|
tag_name: 'param',
|
49
51
|
text: props['description'] || "",
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/code_objects/group'
|
2
4
|
require 'puppet-strings/yard/util'
|
3
5
|
|
@@ -73,6 +75,9 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects:
|
|
73
75
|
class Property < Parameter
|
74
76
|
end
|
75
77
|
|
78
|
+
class Check < Parameter
|
79
|
+
end
|
80
|
+
|
76
81
|
# Represents a resource type feature.
|
77
82
|
class Feature
|
78
83
|
attr_reader :name, :docstring
|
@@ -95,7 +100,7 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects:
|
|
95
100
|
end
|
96
101
|
end
|
97
102
|
|
98
|
-
attr_reader :properties, :
|
103
|
+
attr_reader :properties, :features, :checks
|
99
104
|
|
100
105
|
# Initializes a new resource type.
|
101
106
|
# @param [String] name The resource type name.
|
@@ -134,17 +139,56 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects:
|
|
134
139
|
@features << feature
|
135
140
|
end
|
136
141
|
|
142
|
+
# Adds a check to the resource type.
|
143
|
+
# @param [PuppetStrings::Yard::CodeObjects::Type::Check] check The check to add.
|
144
|
+
# @return [void]
|
145
|
+
def add_check(check)
|
146
|
+
@checks ||= []
|
147
|
+
@checks << check
|
148
|
+
end
|
149
|
+
|
150
|
+
def parameters
|
151
|
+
# just return params if there are no providers
|
152
|
+
return @parameters if providers.empty?
|
153
|
+
|
154
|
+
# return existing params if we have already added provider
|
155
|
+
return @parameters if @parameters.any? { |p| p.name == 'provider' }
|
156
|
+
|
157
|
+
provider_param = Parameter.new(
|
158
|
+
'provider',
|
159
|
+
"The specific backend to use for this `#{self.name.to_s}` resource. You will seldom need " + \
|
160
|
+
"to specify this --- Puppet will usually discover the appropriate provider for your platform."
|
161
|
+
)
|
162
|
+
|
163
|
+
@parameters << provider_param
|
164
|
+
end
|
165
|
+
|
166
|
+
# Not sure if this is where this belongs or if providers should only be resolved at
|
167
|
+
# render-time. For now, this should re-resolve on every call.
|
168
|
+
# may be able to memoize this
|
169
|
+
def providers
|
170
|
+
providers = YARD::Registry.all("puppet_providers_#{name}".intern)
|
171
|
+
return providers if providers.empty?
|
172
|
+
|
173
|
+
providers.first.children
|
174
|
+
end
|
175
|
+
|
137
176
|
# Converts the code object to a hash representation.
|
138
177
|
# @return [Hash] Returns a hash representation of the code object.
|
139
178
|
def to_hash
|
140
179
|
hash = {}
|
180
|
+
|
141
181
|
hash[:name] = name
|
142
182
|
hash[:file] = file
|
143
183
|
hash[:line] = line
|
144
|
-
|
145
|
-
hash[:
|
146
|
-
hash[:
|
147
|
-
hash[:
|
184
|
+
|
185
|
+
hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
|
186
|
+
hash[:properties] = properties.sort_by { |p| p.name }.map(&:to_hash) if properties && !properties.empty?
|
187
|
+
hash[:parameters] = parameters.sort_by { |p| p.name }.map(&:to_hash) if parameters && !parameters.empty?
|
188
|
+
hash[:checks] = checks.sort_by { |c| c.name }.map(&:to_hash) if checks && !checks.empty?
|
189
|
+
hash[:features] = features.sort_by { |f| f.name }.map(&:to_hash) if features && !features.empty?
|
190
|
+
hash[:providers] = providers.sort_by { |p| p.name }.map(&:to_hash) if providers && !providers.empty?
|
191
|
+
|
148
192
|
hash
|
149
193
|
end
|
150
194
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Implements the base handler for Puppet language handlers.
|
2
4
|
class PuppetStrings::Yard::Handlers::Puppet::Base < YARD::Handlers::Base
|
3
5
|
# Determine sif the handler handles the given statement.
|
@@ -17,6 +19,7 @@ class PuppetStrings::Yard::Handlers::Puppet::Base < YARD::Handlers::Base
|
|
17
19
|
tags = object.tags(:param)
|
18
20
|
tags.each do |tag|
|
19
21
|
next if statement.parameters.find { |p| tag.name == p.name }
|
22
|
+
|
20
23
|
log.warn "The @param tag for parameter '#{tag.name}' has no matching parameter at #{statement.file}:#{statement.line}." unless tag.name == 'name' || tag.name == 'title'
|
21
24
|
end
|
22
25
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/handlers/helpers'
|
2
4
|
require 'puppet-strings/yard/handlers/puppet/base'
|
3
5
|
require 'puppet-strings/yard/parsers'
|
@@ -37,7 +39,7 @@ class PuppetStrings::Yard::Handlers::Puppet::FunctionHandler < PuppetStrings::Ya
|
|
37
39
|
def add_return_tag(object, type=nil)
|
38
40
|
tag = object.tag(:return)
|
39
41
|
if tag
|
40
|
-
if (type && tag.types.first) && (type != tag.types.first)
|
42
|
+
if (type && tag.types && tag.types.first) && (type != tag.types.first)
|
41
43
|
log.warn "Documented return type does not match return type in function definition near #{statement.file}:#{statement.line}."
|
42
44
|
end
|
43
45
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'ripper'
|
2
4
|
|
3
5
|
# Implements the base handler for Ruby language handlers.
|
@@ -12,6 +14,7 @@ class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base
|
|
12
14
|
# @return [String] Returns a string representation of the node or nil if a string representation was not possible.
|
13
15
|
def node_as_string(node)
|
14
16
|
return nil unless node
|
17
|
+
|
15
18
|
case node.type
|
16
19
|
when :symbol, :symbol_literal
|
17
20
|
node.source[1..-1]
|
@@ -42,8 +45,10 @@ class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base
|
|
42
45
|
def get_name(statementobject, statementtype)
|
43
46
|
parameters = statementobject.parameters(false)
|
44
47
|
raise YARD::Parser::UndocumentableError, "Expected at least one parameter to #{statementtype} at #{statementobject.file}:#{statementobject.line}." if parameters.empty?
|
48
|
+
|
45
49
|
name = node_as_string(parameters.first)
|
46
50
|
raise YARD::Parser::UndocumentableError, "Expected a symbol or string literal for first parameter but found '#{parameters.first.type}' at #{statement.file}:#{statement.line}." unless name
|
51
|
+
|
47
52
|
name
|
48
53
|
end
|
49
54
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet-strings/yard/handlers/helpers'
|
2
4
|
require 'puppet-strings/yard/handlers/ruby/base'
|
3
5
|
require 'puppet-strings/yard/code_objects'
|
@@ -10,16 +12,21 @@ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard
|
|
10
12
|
|
11
13
|
process do
|
12
14
|
return unless statement.count > 1
|
15
|
+
|
13
16
|
ruby_module_name = statement[0].source
|
14
17
|
return unless ruby_module_name == 'Puppet::DataTypes' || ruby_module_name == 'DataTypes' # rubocop:disable Style/MultipleComparison This reads better
|
15
|
-
object = get_datatype_yard_object(get_name(statement, 'Puppet::DataTypes.create_type'))
|
16
18
|
|
17
|
-
|
19
|
+
object = get_datatype_yard_object(get_name(statement, 'Puppet::DataTypes.create_type'))
|
20
|
+
# Extract the interface definition
|
21
|
+
type_interface = extract_data_type_interface
|
22
|
+
actual_params = extract_params(type_interface)
|
23
|
+
actual_funcs = extract_functions(object, type_interface)
|
18
24
|
|
19
25
|
# Mark the data type as public if it doesn't already have an api tag
|
20
26
|
object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
|
21
27
|
|
22
|
-
|
28
|
+
validate_param_tags!(object, actual_params)
|
29
|
+
validate_methods!(object, actual_funcs)
|
23
30
|
|
24
31
|
# Set the default values for all parameters
|
25
32
|
actual_params.each { |name, data| object.set_parameter_default(name, data[:default]) }
|
@@ -49,38 +56,64 @@ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard
|
|
49
56
|
object
|
50
57
|
end
|
51
58
|
|
52
|
-
|
53
|
-
|
54
|
-
# Traverse the block looking for interface
|
59
|
+
# @return [Hash{Object => Object}] The Puppet DataType interface definition as a ruby Hash
|
60
|
+
def extract_data_type_interface
|
55
61
|
block = statement.block
|
56
|
-
return unless block
|
57
|
-
|
58
|
-
|
59
|
-
|
62
|
+
return {} unless block
|
63
|
+
|
64
|
+
# Declare the parsed interface outside of the closure
|
65
|
+
parsed_interface = nil
|
66
|
+
|
67
|
+
# Recursively traverse the block looking for the first valid 'interface' call
|
68
|
+
interface_node = find_ruby_ast_node(block, true) do |node|
|
69
|
+
next false unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) &&
|
70
|
+
node.method_name &&
|
71
|
+
node.method_name.source == 'interface'
|
60
72
|
|
61
|
-
method_name = node.method_name.source
|
62
73
|
parameters = node.parameters(false)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
74
|
+
next false unless parameters.count >= 1
|
75
|
+
|
76
|
+
interface_string = node_as_string(parameters[0])
|
77
|
+
next false unless interface_string
|
78
|
+
|
79
|
+
begin
|
67
80
|
# Ref - https://github.com/puppetlabs/puppet/blob/ba4d1a1aba0095d3c70b98fea5c67434a4876a61/lib/puppet/datatypes.rb#L159
|
68
81
|
parsed_interface = Puppet::Pops::Parser::EvaluatingParser.new.parse_string("{ #{interface_string} }").body
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
#
|
73
|
-
# We need to convert the LiteralHash into a conventional ruby hash of strings. The
|
74
|
-
# LazyLiteralEvaluator does this by traversing the AST tree can converting objects to strings
|
75
|
-
# where possible and ignoring object types which cannot (thus the 'Lazy' name)
|
76
|
-
#
|
77
|
-
# Once we have it as a standard ruby hash we can then look at the keys and populate the YARD
|
78
|
-
# Code object with the correct attributes etc.
|
79
|
-
literal_eval = LazyLiteralEvaluator.new
|
80
|
-
populate_data_type_params_from_literal_hash!(literal_eval.literal(parsed_interface), params)
|
82
|
+
rescue Puppet::Error => e
|
83
|
+
log.warn "Invalid datatype definition at #{statement.file}:#{statement.line}: #{e.basic_message}"
|
84
|
+
next false
|
81
85
|
end
|
86
|
+
!parsed_interface.nil?
|
82
87
|
end
|
83
|
-
|
88
|
+
|
89
|
+
# Now that we parsed the Puppet code (as a string) into a LiteralHash PCore type (Puppet AST),
|
90
|
+
# We need to convert the LiteralHash into a conventional ruby hash of strings. The
|
91
|
+
# LazyLiteralEvaluator does this by traversing the AST tree can converting objects to strings
|
92
|
+
# where possible and ignoring object types which cannot (thus the 'Lazy' name)
|
93
|
+
literal_eval = LazyLiteralEvaluator.new
|
94
|
+
literal_eval.literal(parsed_interface)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Find the first Ruby AST node within an AST Tree, optionally recursively. Returns nil of none could be found
|
98
|
+
#
|
99
|
+
# @param [YARD::Parser::Ruby::AstNode] ast_node The root AST node object to inspect
|
100
|
+
# @param [Boolean] recurse Whether to search the tree recursively. Defaults to false
|
101
|
+
# @yieldparam [YARD::Parser::Ruby::AstNode] ast_node The AST Node that should be checked
|
102
|
+
# @yieldreturn [Boolean] Whether the node was what was searched for
|
103
|
+
# @return [YARD::Parser::Ruby::AstNode, nil]
|
104
|
+
def find_ruby_ast_node(ast_node, recurse = false, &block)
|
105
|
+
raise ArgumentError, 'find_ruby_ast_node requires a block' unless block_given?
|
106
|
+
|
107
|
+
is_found = yield ast_node
|
108
|
+
return ast_node if is_found
|
109
|
+
|
110
|
+
if ast_node.respond_to?(:children)
|
111
|
+
ast_node.children.each do |child_node|
|
112
|
+
child_found = find_ruby_ast_node(child_node, recurse, &block)
|
113
|
+
return child_found unless child_found.nil?
|
114
|
+
end
|
115
|
+
end
|
116
|
+
nil
|
84
117
|
end
|
85
118
|
|
86
119
|
# Lazily evaluates a Pops object, ignoring any objects that cannot
|
@@ -103,7 +136,7 @@ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard
|
|
103
136
|
# Anything else is ignored
|
104
137
|
class LazyLiteralEvaluator
|
105
138
|
def initialize
|
106
|
-
@literal_visitor
|
139
|
+
@literal_visitor = ::Puppet::Pops::Visitor.new(self, "literal", 0, 0)
|
107
140
|
end
|
108
141
|
|
109
142
|
def literal(ast)
|
@@ -111,68 +144,72 @@ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard
|
|
111
144
|
end
|
112
145
|
|
113
146
|
# ----- The following methods are different/additions from the original Literal_evaluator
|
114
|
-
def literal_Object(o)
|
147
|
+
def literal_Object(o)
|
115
148
|
# Ignore any other object types
|
116
149
|
end
|
117
150
|
|
118
|
-
def literal_AccessExpression(o)
|
151
|
+
def literal_AccessExpression(o)
|
119
152
|
# Extract the raw text of the Access Expression
|
120
153
|
::Puppet::Pops::Adapters::SourcePosAdapter.adapt(o).extract_text
|
121
154
|
end
|
122
155
|
|
123
|
-
def literal_QualifiedReference(o)
|
156
|
+
def literal_QualifiedReference(o)
|
124
157
|
# Extract the raw text of the Qualified Reference
|
125
158
|
::Puppet::Pops::Adapters::SourcePosAdapter.adapt(o).extract_text
|
126
159
|
end
|
127
160
|
|
128
161
|
# ----- The following methods are the same as the original Literal_evaluator
|
129
|
-
def literal_Factory(o)
|
162
|
+
def literal_Factory(o)
|
130
163
|
literal(o.model)
|
131
164
|
end
|
132
165
|
|
133
|
-
def literal_Program(o)
|
166
|
+
def literal_Program(o)
|
134
167
|
literal(o.body)
|
135
168
|
end
|
136
169
|
|
137
|
-
def literal_LiteralString(o)
|
170
|
+
def literal_LiteralString(o)
|
138
171
|
o.value
|
139
172
|
end
|
140
173
|
|
141
|
-
def literal_QualifiedName(o)
|
174
|
+
def literal_QualifiedName(o)
|
142
175
|
o.value
|
143
176
|
end
|
144
177
|
|
145
|
-
def literal_LiteralNumber(o)
|
178
|
+
def literal_LiteralNumber(o)
|
146
179
|
o.value
|
147
180
|
end
|
148
181
|
|
149
|
-
def
|
182
|
+
def literal_UnaryMinusExpression(o)
|
183
|
+
-1 * literal(o.expr)
|
184
|
+
end
|
185
|
+
|
186
|
+
def literal_LiteralBoolean(o)
|
150
187
|
o.value
|
151
188
|
end
|
152
189
|
|
153
|
-
def literal_LiteralUndef(o)
|
190
|
+
def literal_LiteralUndef(o)
|
154
191
|
nil
|
155
192
|
end
|
156
193
|
|
157
|
-
def literal_LiteralDefault(o)
|
194
|
+
def literal_LiteralDefault(o)
|
158
195
|
:default
|
159
196
|
end
|
160
197
|
|
161
|
-
def literal_LiteralRegularExpression(o)
|
198
|
+
def literal_LiteralRegularExpression(o)
|
162
199
|
o.value
|
163
200
|
end
|
164
201
|
|
165
|
-
def literal_ConcatenatedString(o)
|
202
|
+
def literal_ConcatenatedString(o)
|
166
203
|
# use double quoted string value if there is no interpolation
|
167
204
|
throw :not_literal unless o.segments.size == 1 && o.segments[0].is_a?(Model::LiteralString)
|
168
205
|
o.segments[0].value
|
169
206
|
end
|
170
207
|
|
171
|
-
def literal_LiteralList(o)
|
172
|
-
o.values.map {|v| literal(v) }
|
208
|
+
def literal_LiteralList(o)
|
209
|
+
o.values.map { |v| literal(v) }
|
173
210
|
end
|
174
211
|
|
175
|
-
def literal_LiteralHash(o)
|
212
|
+
def literal_LiteralHash(o)
|
176
213
|
o.entries.reduce({}) do |result, entry|
|
177
214
|
result[literal(entry.key)] = literal(entry.value)
|
178
215
|
result
|
@@ -180,27 +217,58 @@ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard
|
|
180
217
|
end
|
181
218
|
end
|
182
219
|
|
183
|
-
|
184
|
-
|
220
|
+
# Extracts the datatype attributes from a Puppet Data Type interface hash.
|
221
|
+
# Returns a Hash with a :types key (Array of data types for the parameter) and :default key (The default value of the parameter)
|
222
|
+
# @return Hash[Symbol => Hash] The Datatype Attributes as a hash
|
223
|
+
def extract_params(hash)
|
224
|
+
params_hash = {}
|
185
225
|
# Exit early if there are no entries in the hash
|
186
|
-
return if hash['attributes'].nil? || hash['attributes'].
|
226
|
+
return params_hash if hash.nil? || hash['attributes'].nil? || hash['attributes'].empty?
|
187
227
|
|
188
228
|
hash['attributes'].each do |key, value|
|
189
229
|
data_type = nil
|
190
230
|
default = nil
|
191
|
-
|
192
|
-
when String
|
231
|
+
if value.is_a?(String)
|
193
232
|
data_type = value
|
194
|
-
|
233
|
+
elsif value.is_a?(Hash)
|
195
234
|
data_type = value['type'] unless value['type'].nil?
|
196
235
|
default = value['value'] unless value['value'].nil?
|
197
236
|
end
|
198
237
|
data_type = [data_type] unless data_type.nil? || data_type.is_a?(Array)
|
199
238
|
params_hash[key] = { :types => data_type, :default => default }
|
200
239
|
end
|
240
|
+
|
241
|
+
params_hash
|
242
|
+
end
|
243
|
+
|
244
|
+
# Extracts the datatype functions from a Puppet Data Type interface hash.
|
245
|
+
# Returns a Hash with a :param_types key (Array of types for each parameter) and :return_type key (The return type of the function)
|
246
|
+
# @return Hash[Symbol => Hash] The Datatype Attributes as a hash
|
247
|
+
def extract_functions(object, hash)
|
248
|
+
funcs_hash = {}
|
249
|
+
# Exit early if there are no entries in the hash
|
250
|
+
return funcs_hash if hash.nil? || hash['functions'].nil? || hash['functions'].empty?
|
251
|
+
|
252
|
+
hash['functions'].each do |key, func_type|
|
253
|
+
func_hash = { :param_types => [], :return_type => nil }
|
254
|
+
begin
|
255
|
+
callable_type = Puppet::Pops::Types::TypeParser.singleton.parse(func_type)
|
256
|
+
if callable_type.is_a?(Puppet::Pops::Types::PCallableType)
|
257
|
+
func_hash[:param_types] = callable_type.param_types.map { |pt| pt.to_s }
|
258
|
+
func_hash[:return_type] = callable_type.return_type.to_s
|
259
|
+
else
|
260
|
+
log.warn "The function definition for '#{key}' near #{object.file}:#{object.line} is not a Callable type"
|
261
|
+
end
|
262
|
+
rescue Puppet::ParseError => e
|
263
|
+
log.warn "Unable to parse the function definition for '#{key}' near #{object.file}:#{object.line}. #{e}"
|
264
|
+
end
|
265
|
+
funcs_hash[key] = func_hash
|
266
|
+
end
|
267
|
+
funcs_hash
|
201
268
|
end
|
202
269
|
|
203
|
-
|
270
|
+
# Validates and automatically fixes yard @param tags for the data type
|
271
|
+
def validate_param_tags!(object, actual_params_hash)
|
204
272
|
actual_param_names = actual_params_hash.keys
|
205
273
|
tagged_param_names = object.tags(:param).map(&:name)
|
206
274
|
# Log any errors
|
@@ -215,8 +283,10 @@ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard
|
|
215
283
|
# Find param tags with a type that is different from the actual definition
|
216
284
|
object.tags(:param).reject { |tag| tag.types.nil? }.each do |tag|
|
217
285
|
next if actual_params_hash[tag.name].nil?
|
286
|
+
|
218
287
|
actual_data_type = actual_params_hash[tag.name][:types]
|
219
288
|
next if actual_data_type.nil?
|
289
|
+
|
220
290
|
log.warn "The @param tag for '#{tag.name}' has a different type definition than the actual attribute near #{object.file}:#{object.line}." if tag.types != actual_data_type
|
221
291
|
end
|
222
292
|
|
@@ -230,7 +300,110 @@ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard
|
|
230
300
|
# Set the type in the param tag
|
231
301
|
object.tags(:param).each do |tag|
|
232
302
|
next if actual_params_hash[tag.name].nil?
|
303
|
+
|
233
304
|
tag.types = actual_params_hash[tag.name][:types]
|
234
305
|
end
|
235
306
|
end
|
307
|
+
|
308
|
+
# Validates and automatically fixes yard @method! tags for the data type
|
309
|
+
def validate_methods!(object, actual_functions_hash)
|
310
|
+
actual_func_names = actual_functions_hash.keys
|
311
|
+
tagged_func_names = object.meths.map { |meth| meth.name.to_s }
|
312
|
+
|
313
|
+
# Log any errors
|
314
|
+
# Find functions which are not documented
|
315
|
+
(actual_func_names - tagged_func_names).each do |item|
|
316
|
+
log.warn "Missing @!method tag for function '#{item}' near #{object.file}:#{object.line}."
|
317
|
+
end
|
318
|
+
# Find functions which are not defined
|
319
|
+
(tagged_func_names - actual_func_names).each do |item|
|
320
|
+
log.warn "The @!method tag for '#{item}' has no matching function definition near #{object.file}:#{object.line}."
|
321
|
+
end
|
322
|
+
# Functions with the wrong return type
|
323
|
+
object.meths.each do |meth|
|
324
|
+
next unless actual_func_names.include?(meth.name.to_s)
|
325
|
+
|
326
|
+
return_tag = meth.docstring.tag(:return)
|
327
|
+
next if return_tag.nil?
|
328
|
+
|
329
|
+
actual_return_types = [actual_functions_hash[meth.name.to_s][:return_type]]
|
330
|
+
next if return_tag.types == actual_return_types
|
331
|
+
|
332
|
+
log.warn "The @return tag for '#{meth.name}' has a different type definition than the actual function near #{object.file}:#{object.line}. Expected #{actual_return_types}"
|
333
|
+
return_tag.types = actual_return_types
|
334
|
+
end
|
335
|
+
|
336
|
+
# Automatically fix missing methods
|
337
|
+
(actual_func_names - tagged_func_names).each do |name|
|
338
|
+
object.add_function(name, actual_functions_hash[name][:return_type], actual_functions_hash[name][:param_types])
|
339
|
+
end
|
340
|
+
# Remove extra methods. Can't use `meths` as that's a derived property
|
341
|
+
object.children.reject! { |child| child.is_a?(YARD::CodeObjects::MethodObject) && !actual_func_names.include?(child.name.to_s) }
|
342
|
+
|
343
|
+
# Add the return type for the methods if missing
|
344
|
+
object.meths.each do |meth|
|
345
|
+
next unless meth.docstring.tag(:return).nil?
|
346
|
+
|
347
|
+
meth.docstring.add_tag(YARD::Tags::Tag.new(:return, '', actual_functions_hash[meth.name.to_s][:return_type]))
|
348
|
+
end
|
349
|
+
|
350
|
+
# Sync the method properties and add the return type for the methods if missing
|
351
|
+
object.meths.each do |meth|
|
352
|
+
validate_function_method!(object, meth, actual_functions_hash[meth.name.to_s])
|
353
|
+
next unless meth.docstring.tag(:return).nil?
|
354
|
+
|
355
|
+
meth.docstring.add_tag(YARD::Tags::Tag.new(:return, '', actual_functions_hash[meth.name.to_s][:return_type]))
|
356
|
+
end
|
357
|
+
|
358
|
+
# The default meth.signature assumes ruby invocation (e.g. def meth(...)) but this doesn't make sense for a
|
359
|
+
# Puppet Data Type function invocation. So instead we derive a signature from the method definition.
|
360
|
+
object.meths.each do |meth|
|
361
|
+
params = ''
|
362
|
+
unless meth.docstring.tags(:param).empty?
|
363
|
+
params += '(' + meth.docstring.tags(:param).map { |t| t.name }.join(', ') + ')'
|
364
|
+
end
|
365
|
+
meth.signature = "#{object.name}.#{meth.name}" + params
|
366
|
+
end
|
367
|
+
|
368
|
+
nil
|
369
|
+
end
|
370
|
+
|
371
|
+
# Validates and automatically fixes a single yard @method!
|
372
|
+
# Used by the validate_methods! method.
|
373
|
+
def validate_function_method!(object, meth, actual_function)
|
374
|
+
# Remove extra params
|
375
|
+
if meth.docstring.tags(:param).count > actual_function[:param_types].count
|
376
|
+
index = 0
|
377
|
+
meth.docstring.delete_tag_if do |tag|
|
378
|
+
if tag.tag_name == 'param'
|
379
|
+
index += 1
|
380
|
+
if index > actual_function[:param_types].count
|
381
|
+
log.warn "The @param tag for '#{tag.name}' should not exist for function '#{meth.name}' that is defined near #{object.file}:#{object.line}. Expected only #{actual_function[:param_types].count} parameter/s"
|
382
|
+
true
|
383
|
+
else
|
384
|
+
false
|
385
|
+
end
|
386
|
+
else
|
387
|
+
false
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Add missing params
|
393
|
+
if meth.docstring.tags(:param).count < actual_function[:param_types].count
|
394
|
+
start = meth.docstring.tags(:param).count + 1
|
395
|
+
(start..actual_function[:param_types].count).each do |index| # Using 1-based index here instead of usual zero
|
396
|
+
meth.add_tag(YARD::Tags::Tag.new(:param, '', actual_function[:param_types][index - 1], "param#{index}"))
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# Ensure the parameter types are correct
|
401
|
+
meth.docstring.tags(:param).each_with_index do |tag, index|
|
402
|
+
actual_types = [actual_function[:param_types][index]]
|
403
|
+
if tag.types != actual_types
|
404
|
+
log.warn "The @param tag for '#{tag.name}' for function '#{meth.name}' has a different type definition than the actual function near #{object.file}:#{object.line}. Expected #{actual_types}"
|
405
|
+
tag.types = actual_types
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
236
409
|
end
|