puppet-strings 2.2.0 → 2.3.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 (88) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile +14 -5
  4. data/JSON.md +41 -11
  5. data/README.md +66 -7
  6. data/Rakefile +99 -29
  7. data/lib/puppet-strings/json.rb +2 -0
  8. data/lib/puppet-strings/markdown.rb +2 -0
  9. data/lib/puppet-strings/markdown/data_type.rb +18 -0
  10. data/lib/puppet-strings/markdown/data_types.rb +41 -0
  11. data/lib/puppet-strings/markdown/function.rb +2 -2
  12. data/lib/puppet-strings/markdown/table_of_contents.rb +1 -0
  13. data/lib/puppet-strings/markdown/templates/data_type.erb +78 -0
  14. data/lib/puppet-strings/tasks/generate.rb +3 -2
  15. data/lib/puppet-strings/version.rb +1 -1
  16. data/lib/puppet-strings/yard.rb +10 -0
  17. data/lib/puppet-strings/yard/code_objects.rb +2 -0
  18. data/lib/puppet-strings/yard/code_objects/class.rb +1 -1
  19. data/lib/puppet-strings/yard/code_objects/data_type.rb +80 -0
  20. data/lib/puppet-strings/yard/code_objects/data_type_alias.rb +58 -0
  21. data/lib/puppet-strings/yard/code_objects/defined_type.rb +1 -1
  22. data/lib/puppet-strings/yard/code_objects/function.rb +3 -3
  23. data/lib/puppet-strings/yard/code_objects/plan.rb +1 -1
  24. data/lib/puppet-strings/yard/handlers.rb +2 -0
  25. data/lib/puppet-strings/yard/handlers/puppet/data_type_alias_handler.rb +24 -0
  26. data/lib/puppet-strings/yard/handlers/ruby/base.rb +2 -2
  27. data/lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb +236 -0
  28. data/lib/puppet-strings/yard/handlers/ruby/function_handler.rb +1 -3
  29. data/lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb +2 -2
  30. data/lib/puppet-strings/yard/handlers/ruby/type_base.rb +5 -6
  31. data/lib/puppet-strings/yard/parsers/json/parser.rb +1 -1
  32. data/lib/puppet-strings/yard/parsers/puppet/parser.rb +14 -7
  33. data/lib/puppet-strings/yard/parsers/puppet/statement.rb +25 -0
  34. data/lib/puppet-strings/yard/tags/overload_tag.rb +1 -1
  35. data/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_data_type.erb +10 -0
  36. data/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb +9 -0
  37. data/lib/puppet-strings/yard/templates/default/layout/html/objects.erb +2 -0
  38. data/lib/puppet-strings/yard/templates/default/layout/html/setup.rb +18 -1
  39. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/box_info.erb +10 -0
  40. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/header.erb +1 -0
  41. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/note.erb +6 -0
  42. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/overview.erb +6 -0
  43. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/setup.rb +5 -0
  44. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/source.erb +12 -0
  45. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/summary.erb +4 -0
  46. data/lib/puppet-strings/yard/templates/default/puppet_data_type/html/todo.erb +6 -0
  47. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/alias_of.erb +10 -0
  48. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/box_info.erb +10 -0
  49. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/header.erb +1 -0
  50. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/note.erb +6 -0
  51. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/overview.erb +6 -0
  52. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/setup.rb +17 -0
  53. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/source.erb +12 -0
  54. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/summary.erb +4 -0
  55. data/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/todo.erb +6 -0
  56. data/lib/puppet-strings/yard/templates/default/tags/setup.rb +1 -0
  57. data/lib/puppet/face/strings.rb +3 -3
  58. data/spec/acceptance/emit_json_options_spec.rb +69 -0
  59. data/spec/acceptance/generate_markdown_spec.rb +13 -15
  60. data/spec/acceptance/running_strings_generate_spec.rb +78 -0
  61. data/spec/fixtures/acceptance/modules/test/metadata.json +5 -1
  62. data/spec/fixtures/acceptance/modules/test/types/elephant.pp +2 -0
  63. data/spec/fixtures/unit/markdown/output_with_data_types.md +553 -0
  64. data/spec/spec_helper.rb +3 -0
  65. data/spec/spec_helper_acceptance.rb +52 -22
  66. data/spec/spec_helper_acceptance_local.rb +10 -0
  67. data/spec/unit/puppet-strings/describe_spec.rb +7 -7
  68. data/spec/unit/puppet-strings/json_spec.rb +23 -4
  69. data/spec/unit/puppet-strings/markdown/base_spec.rb +3 -3
  70. data/spec/unit/puppet-strings/markdown_spec.rb +84 -23
  71. data/spec/unit/puppet-strings/yard/code_objects/task_spec.rb +1 -1
  72. data/spec/unit/puppet-strings/yard/handlers/json/task_handler_spec.rb +4 -4
  73. data/spec/unit/puppet-strings/yard/handlers/puppet/class_handler_spec.rb +8 -8
  74. data/spec/unit/puppet-strings/yard/handlers/puppet/data_type_alias_handler_spec.rb +65 -0
  75. data/spec/unit/puppet-strings/yard/handlers/puppet/defined_type_handler_spec.rb +8 -8
  76. data/spec/unit/puppet-strings/yard/handlers/puppet/function_handler_spec.rb +13 -13
  77. data/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb +232 -0
  78. data/spec/unit/puppet-strings/yard/handlers/ruby/function_handler_spec.rb +36 -19
  79. data/spec/unit/puppet-strings/yard/handlers/ruby/provider_handler_spec.rb +26 -7
  80. data/spec/unit/puppet-strings/yard/handlers/ruby/rsapi_handler_spec.rb +7 -7
  81. data/spec/unit/puppet-strings/yard/handlers/ruby/type_handler_spec.rb +26 -10
  82. data/spec/unit/puppet-strings/yard/parsers/json/task_statement_spec.rb +2 -2
  83. data/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb +42 -0
  84. data/spec/unit/puppet-strings/yard/util_spec.rb +1 -1
  85. metadata +35 -7
  86. data/spec/acceptance/emit_json_options.rb +0 -71
  87. data/spec/acceptance/lib/util.rb +0 -163
  88. data/spec/acceptance/running_strings_generate.rb +0 -54
@@ -30,11 +30,11 @@ module PuppetStrings::Markdown
30
30
  end
31
31
  end
32
32
 
33
- def error_type(r)
33
+ def error_type(r) # rubocop:disable Naming/UncommunicativeMethodParamName
34
34
  "`#{r.split(' ')[0]}`"
35
35
  end
36
36
 
37
- def error_text(r)
37
+ def error_text(r) # rubocop:disable Naming/UncommunicativeMethodParamName
38
38
  "#{r.split(' ').drop(1).join(' ')}"
39
39
  end
40
40
  end
@@ -7,6 +7,7 @@ module PuppetStrings::Markdown
7
7
  PuppetStrings::Markdown::DefinedTypes,
8
8
  PuppetStrings::Markdown::ResourceTypes,
9
9
  PuppetStrings::Markdown::Functions,
10
+ PuppetStrings::Markdown::DataTypes,
10
11
  PuppetStrings::Markdown::PuppetTasks,
11
12
  PuppetStrings::Markdown::PuppetPlans].each do |r|
12
13
  toc = r.toc_info
@@ -0,0 +1,78 @@
1
+ ### <%= name %>
2
+
3
+ <% if text -%>
4
+ <%= text %>
5
+ <% elsif summary -%>
6
+ <%= summary %>
7
+ <% else -%>
8
+ <%= "The #{name} data type." %>
9
+ <% end -%>
10
+
11
+ <% if todo -%>
12
+ * **TODO** <%= todo %>
13
+
14
+ <% end -%>
15
+ <% if note -%>
16
+ * **Note** <%= note %>
17
+
18
+ <% end -%>
19
+ <% if since -%>
20
+ * **Since** <%= since %>
21
+
22
+ <% end -%>
23
+ <% if see -%>
24
+ * **See also**
25
+ <% see.each do |sa| -%>
26
+ <% if sa[:name] -%>
27
+ <%= sa[:name] %>
28
+ <% end -%>
29
+ <% if sa[:text] -%>
30
+ <%= sa[:text] %>
31
+ <% end -%>
32
+ <% end -%>
33
+
34
+ <% end -%>
35
+ <% if examples -%>
36
+ #### Examples
37
+
38
+ <% examples.each do |eg| -%>
39
+ ##### <%= eg[:name] %>
40
+
41
+ ```puppet
42
+ <%= eg[:text] %>
43
+ ```
44
+
45
+ <% end -%>
46
+ <% end -%>
47
+ <% if alias_of -%>
48
+ Alias of `<%= alias_of %>`
49
+
50
+ <% end -%>
51
+ <% if params -%>
52
+ #### Parameters
53
+
54
+ The following parameters are available in the `<%= name %>` <%= @type %>.
55
+
56
+ <% params.each do |param| -%>
57
+ ##### `<%= param[:name] %>`
58
+
59
+ <% if param[:types] -%>
60
+ Data type: `<%= param[:types].join(', ') -%>`
61
+
62
+ <% end -%>
63
+ <%= param[:text] %>
64
+
65
+ <% if options_for_param(param[:name]) -%>
66
+ Options:
67
+
68
+ <% options_for_param(param[:name]).each do |o| -%>
69
+ * **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %>
70
+ <% end -%>
71
+
72
+ <% end -%>
73
+ <% if defaults && defaults[param[:name]] -%>
74
+ Default value: <%= value_string(defaults[param[:name]]) %>
75
+
76
+ <% end -%>
77
+ <% end -%>
78
+ <% end -%>
@@ -33,11 +33,12 @@ namespace :strings do
33
33
  end
34
34
  end
35
35
  end
36
+ # rubocop:enable Style/PreferredHashMethods
36
37
 
37
- [:json,:markdown].each { |format| parse_format_option(args, options, format) }
38
+ %i[json markdown].each { |format| parse_format_option(args, options, format) }
38
39
 
39
40
  warn('yard_args behavior is a little dodgy, use at your own risk') if args[:yard_args]
40
- options[:yard_args] = args[:yard_args].split if args.has_key? :yard_args
41
+ options[:yard_args] = args[:yard_args].split if args.key? :yard_args
41
42
 
42
43
  PuppetStrings.generate(patterns, options)
43
44
  end
@@ -1,3 +1,3 @@
1
1
  module PuppetStrings
2
- VERSION = '2.2.0'.freeze
2
+ VERSION = '2.3.0'.freeze
3
3
  end
@@ -46,6 +46,8 @@ class YARD::CLI::Yardoc
46
46
  :module,
47
47
  :class,
48
48
  :puppet_class,
49
+ :puppet_data_type,
50
+ :puppet_data_type_alias,
49
51
  :puppet_defined_type,
50
52
  :puppet_type,
51
53
  :puppet_provider,
@@ -64,6 +66,14 @@ class YARD::CLI::Stats
64
66
  output 'Puppet Classes', *type_statistics_all(:puppet_class)
65
67
  end
66
68
 
69
+ def stats_for_puppet_data_types
70
+ output 'Puppet Data Types', *type_statistics_all(:puppet_data_type)
71
+ end
72
+
73
+ def stats_for_puppet_data_type_aliases
74
+ output 'Puppet Data Type Aliases', *type_statistics_all(:puppet_data_type_alias)
75
+ end
76
+
67
77
  def stats_for_puppet_defined_types
68
78
  output 'Puppet Defined Types', *type_statistics_all(:puppet_defined_type)
69
79
  end
@@ -1,6 +1,8 @@
1
1
  # The module for custom YARD code objects.
2
2
  module PuppetStrings::Yard::CodeObjects
3
3
  require 'puppet-strings/yard/code_objects/class'
4
+ require 'puppet-strings/yard/code_objects/data_type'
5
+ require 'puppet-strings/yard/code_objects/data_type_alias'
4
6
  require 'puppet-strings/yard/code_objects/defined_type'
5
7
  require 'puppet-strings/yard/code_objects/type'
6
8
  require 'puppet-strings/yard/code_objects/provider'
@@ -51,7 +51,7 @@ class PuppetStrings::Yard::CodeObjects::Class < PuppetStrings::Yard::CodeObjects
51
51
  hash[:line] = line
52
52
  hash[:inherits] = statement.parent_class if statement.parent_class
53
53
  hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
54
- defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
54
+ defaults = Hash[*parameters.reject{ |p| p[1].nil? }.flatten]
55
55
  hash[:defaults] = defaults unless defaults.empty?
56
56
  hash[:source] = source unless source && source.empty?
57
57
  hash
@@ -0,0 +1,80 @@
1
+ require 'puppet-strings/yard/code_objects/group'
2
+ require 'puppet-strings/yard/util'
3
+
4
+ # Implements the group for Puppet DataTypes.
5
+ class PuppetStrings::Yard::CodeObjects::DataTypes < PuppetStrings::Yard::CodeObjects::Group
6
+ # Gets the singleton instance of the group.
7
+ # @return Returns the singleton instance of the group.
8
+ def self.instance
9
+ super(:puppet_data_types)
10
+ end
11
+
12
+ # Gets the display name of the group.
13
+ # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
14
+ # @return [String] Returns the display name of the group.
15
+ def name(prefix = false)
16
+ 'Puppet Data Types'
17
+ end
18
+ end
19
+
20
+ # Implements the Puppet DataType code object.
21
+ class PuppetStrings::Yard::CodeObjects::DataType < PuppetStrings::Yard::CodeObjects::Base
22
+ # Initializes a Puppet class code object.
23
+ # @param [String] The name of the Data Type
24
+ # @return [void]
25
+ def initialize(name)
26
+ super(PuppetStrings::Yard::CodeObjects::DataTypes.instance, name)
27
+ @parameters = []
28
+ @defaults = {}
29
+ end
30
+
31
+ # Gets the type of the code object.
32
+ # @return Returns the type of the code object.
33
+ def type
34
+ :puppet_data_type
35
+ end
36
+
37
+ # Gets the source of the code object.
38
+ # @return Returns the source of the code object.
39
+ def source
40
+ # Not implemented, but would be nice!
41
+ nil
42
+ end
43
+
44
+ def parameter_exist?(name)
45
+ !docstring.tags(:param).find { |item| item.name == name }.nil?
46
+ end
47
+
48
+ def add_parameter(name, type, default)
49
+ tag = docstring.tags(:param).find { |item| item.name == name }
50
+ if tag.nil?
51
+ tag = YARD::Tags::Tag.new(:param, '', nil, name)
52
+ docstring.add_tag(tag)
53
+ end
54
+ type = [type] unless type.is_a?(Array)
55
+ tag.types = type if tag.types.nil?
56
+ set_parameter_default(name, default)
57
+ end
58
+
59
+ def set_parameter_default(param_name, default)
60
+ defaults.delete(param_name)
61
+ defaults[param_name] = default unless default.nil?
62
+ end
63
+
64
+ def parameters
65
+ docstring.tags(:param).map { |tag| [tag.name, defaults[tag.name]] }
66
+ end
67
+
68
+ # Converts the code object to a hash representation.
69
+ # @return [Hash] Returns a hash representation of the code object.
70
+ def to_hash
71
+ hash = {}
72
+ hash[:name] = name
73
+ hash[:file] = file
74
+ hash[:line] = line
75
+ hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
76
+ hash[:defaults] = defaults unless defaults.empty?
77
+ hash[:source] = source unless source && source.empty?
78
+ hash
79
+ end
80
+ end
@@ -0,0 +1,58 @@
1
+ require 'puppet-strings/yard/code_objects/group'
2
+ require 'puppet-strings/yard/util'
3
+
4
+ # Implements the group for Puppet DataTypeAliases.
5
+ class PuppetStrings::Yard::CodeObjects::DataTypeAliases < PuppetStrings::Yard::CodeObjects::Group
6
+ # Gets the singleton instance of the group.
7
+ # @return Returns the singleton instance of the group.
8
+ def self.instance
9
+ super(:puppet_data_type_aliases)
10
+ end
11
+
12
+ # Gets the display name of the group.
13
+ # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
14
+ # @return [String] Returns the display name of the group.
15
+ def name(prefix = false)
16
+ 'Puppet Data Type Aliases'
17
+ end
18
+ end
19
+
20
+ # Implements the Puppet DataTypeAlias code object.
21
+ class PuppetStrings::Yard::CodeObjects::DataTypeAlias < PuppetStrings::Yard::CodeObjects::Base
22
+ attr_reader :statement
23
+ attr_accessor :alias_of
24
+
25
+ # Initializes a Puppet data type alias code object.
26
+ # @param [PuppetStrings::Parsers::DataTypeAliasStatement] statement The data type alias statement that was parsed.
27
+ # @return [void]
28
+ def initialize(statement)
29
+ @statement = statement
30
+ @alias_of = statement.alias_of
31
+ super(PuppetStrings::Yard::CodeObjects::DataTypeAliases.instance, statement.name)
32
+ end
33
+
34
+ # Gets the type of the code object.
35
+ # @return Returns the type of the code object.
36
+ def type
37
+ :puppet_data_type_alias
38
+ end
39
+
40
+ # Gets the source of the code object.
41
+ # @return Returns the source of the code object.
42
+ def source
43
+ # Not implemented, but would be nice!
44
+ nil
45
+ end
46
+
47
+ # Converts the code object to a hash representation.
48
+ # @return [Hash] Returns a hash representation of the code object.
49
+ def to_hash
50
+ hash = {}
51
+ hash[:name] = name
52
+ hash[:file] = file
53
+ hash[:line] = line
54
+ hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
55
+ hash[:alias_of] = alias_of
56
+ hash
57
+ end
58
+ end
@@ -50,7 +50,7 @@ class PuppetStrings::Yard::CodeObjects::DefinedType < PuppetStrings::Yard::CodeO
50
50
  hash[:file] = file
51
51
  hash[:line] = line
52
52
  hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
53
- defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
53
+ defaults = Hash[*parameters.reject{ |p| p[1].nil? }.flatten]
54
54
  hash[:defaults] = defaults unless defaults.empty?
55
55
  hash[:source] = source unless source && source.empty?
56
56
  hash
@@ -88,14 +88,14 @@ class PuppetStrings::Yard::CodeObjects::Function < PuppetStrings::Yard::CodeObje
88
88
  if self.has_tag? :overload
89
89
  # loop over overloads and append onto the signatures array
90
90
  self.tags(:overload).each do |o|
91
- hash[:signatures] << { :signature => o.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(o.docstring, [:param, :option, :return, :example]) }
91
+ hash[:signatures] << { :signature => o.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(o.docstring, %i[param option return example]) }
92
92
  end
93
93
  else
94
- hash[:signatures] << { :signature => self.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(docstring, [:param, :option, :return, :example]) }
94
+ hash[:signatures] << { :signature => self.signature, :docstring => PuppetStrings::Yard::Util.docstring_to_hash(docstring, %i[param option return example]) }
95
95
  end
96
96
 
97
97
  hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
98
- defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
98
+ defaults = Hash[*parameters.reject{ |p| p[1].nil? }.flatten]
99
99
  hash[:defaults] = defaults unless defaults.empty?
100
100
  hash[:source] = source unless source && source.empty?
101
101
  hash
@@ -48,7 +48,7 @@ class PuppetStrings::Yard::CodeObjects::Plan < PuppetStrings::Yard::CodeObjects:
48
48
  hash[:file] = file
49
49
  hash[:line] = line
50
50
  hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
51
- defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
51
+ defaults = Hash[*parameters.reject{ |p| p[1].nil? }.flatten]
52
52
  hash[:defaults] = defaults unless defaults.empty?
53
53
  hash[:source] = source unless source && source.empty?
54
54
  hash
@@ -2,6 +2,7 @@
2
2
  module PuppetStrings::Yard::Handlers
3
3
  # The module for custom Ruby YARD handlers.
4
4
  module Ruby
5
+ require 'puppet-strings/yard/handlers/ruby/data_type_handler'
5
6
  require 'puppet-strings/yard/handlers/ruby/type_handler'
6
7
  require 'puppet-strings/yard/handlers/ruby/type_extras_handler'
7
8
  require 'puppet-strings/yard/handlers/ruby/rsapi_handler'
@@ -17,6 +18,7 @@ module PuppetStrings::Yard::Handlers
17
18
  # The module for custom Puppet YARD handlers.
18
19
  module Puppet
19
20
  require 'puppet-strings/yard/handlers/puppet/class_handler'
21
+ require 'puppet-strings/yard/handlers/puppet/data_type_alias_handler'
20
22
  require 'puppet-strings/yard/handlers/puppet/defined_type_handler'
21
23
  require 'puppet-strings/yard/handlers/puppet/function_handler'
22
24
  require 'puppet-strings/yard/handlers/puppet/plan_handler'
@@ -0,0 +1,24 @@
1
+ require 'puppet-strings/yard/handlers/helpers'
2
+ require 'puppet-strings/yard/handlers/puppet/base'
3
+ require 'puppet-strings/yard/parsers'
4
+ require 'puppet-strings/yard/code_objects'
5
+
6
+ # Implements the handler for Puppet Data Type Alias.
7
+ class PuppetStrings::Yard::Handlers::Puppet::DataTypeAliasHandler < PuppetStrings::Yard::Handlers::Puppet::Base
8
+ handles PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement
9
+
10
+ process do
11
+ # Register the object
12
+ object = PuppetStrings::Yard::CodeObjects::DataTypeAlias.new(statement)
13
+ register object
14
+
15
+ # Log a warning if missing documentation
16
+ log.warn "Missing documentation for Puppet type alias '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty?
17
+
18
+ # Mark the class as public if it doesn't already have an api tag
19
+ object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
20
+
21
+ # Warn if a summary longer than 140 characters was provided
22
+ PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary
23
+ end
24
+ end
@@ -18,7 +18,8 @@ class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base
18
18
  when :label
19
19
  node.source[0..-2]
20
20
  when :dyna_symbol
21
- node.source
21
+ content = node.jump(:tstring_content)
22
+ content.nil? ? node.source : content.source
22
23
  when :string_literal
23
24
  content = node.jump(:tstring_content)
24
25
  return content.source if content != node
@@ -45,5 +46,4 @@ class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base
45
46
  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
46
47
  name
47
48
  end
48
-
49
49
  end
@@ -0,0 +1,236 @@
1
+ require 'puppet-strings/yard/handlers/helpers'
2
+ require 'puppet-strings/yard/handlers/ruby/base'
3
+ require 'puppet-strings/yard/code_objects'
4
+ require 'puppet-strings/yard/util'
5
+
6
+ # Implements the handler for Puppet Data Types written in Ruby.
7
+ class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard::Handlers::Ruby::Base
8
+ namespace_only
9
+ handles method_call(:create_type)
10
+
11
+ process do
12
+ return unless statement.count > 1
13
+ ruby_module_name = statement[0].source
14
+ 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
+
17
+ actual_params = extract_params_for_data_type # populate_data_type_data(object)
18
+
19
+ # Mark the data type as public if it doesn't already have an api tag
20
+ object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
21
+
22
+ validate_tags!(object, actual_params)
23
+
24
+ # Set the default values for all parameters
25
+ actual_params.each { |name, data| object.set_parameter_default(name, data[:default]) }
26
+
27
+ # Default any typeless param tag to 'Any'
28
+ object.tags(:param).each do |tag|
29
+ tag.types = ['Any'] unless tag.types && !tag.types.empty?
30
+ end
31
+
32
+ # Warn if a summary longer than 140 characters was provided
33
+ PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary
34
+ end
35
+
36
+ private
37
+
38
+ def get_datatype_yard_object(name)
39
+ # Have to guess the path - if we create the object to get the true path from the code,
40
+ # it also shows up in the .at call - self registering?
41
+ guess_path = "puppet_data_types::#{name}"
42
+ object = YARD::Registry.at(guess_path)
43
+
44
+ return object unless object.nil?
45
+
46
+ # Didn't find, create instead
47
+ object = PuppetStrings::Yard::CodeObjects::DataType.new(name)
48
+ register object
49
+ object
50
+ end
51
+
52
+ def extract_params_for_data_type
53
+ params = {}
54
+ # Traverse the block looking for interface
55
+ block = statement.block
56
+ return unless block && block.count >= 2
57
+ block[1].children.each do |node|
58
+ next unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) &&
59
+ node.method_name
60
+
61
+ method_name = node.method_name.source
62
+ parameters = node.parameters(false)
63
+ if method_name == 'interface'
64
+ next unless parameters.count >= 1
65
+ interface_string = node_as_string(parameters[0])
66
+ next unless interface_string
67
+ # Ref - https://github.com/puppetlabs/puppet/blob/ba4d1a1aba0095d3c70b98fea5c67434a4876a61/lib/puppet/datatypes.rb#L159
68
+ parsed_interface = Puppet::Pops::Parser::EvaluatingParser.new.parse_string("{ #{interface_string} }").body
69
+ next unless parsed_interface
70
+
71
+ # Now that we parsed the Puppet code (as a string) into a LiteralHash PCore type (Puppet AST),
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)
81
+ end
82
+ end
83
+ params
84
+ end
85
+
86
+ # Lazily evaluates a Pops object, ignoring any objects that cannot
87
+ # be converted to a literal value. Based on the Puppet Literal Evaluator
88
+ # Ref - https://github.com/puppetlabs/puppet/blob/ba4d1a1aba0095d3c70b98fea5c67434a4876a61/lib/puppet/pops/evaluator/literal_evaluator.rb
89
+ #
90
+ # Literal values for:
91
+ # String (not containing interpolation)
92
+ # Numbers
93
+ # Booleans
94
+ # Undef (produces nil)
95
+ # Array
96
+ # Hash
97
+ # QualifiedName
98
+ # Default (produced :default)
99
+ # Regular Expression (produces ruby regular expression)
100
+ # QualifiedReference e.g. File, FooBar
101
+ # AccessExpression
102
+ #
103
+ # Anything else is ignored
104
+ class LazyLiteralEvaluator
105
+ def initialize
106
+ @literal_visitor ||= ::Puppet::Pops::Visitor.new(self, "literal", 0, 0)
107
+ end
108
+
109
+ def literal(ast)
110
+ @literal_visitor.visit_this_0(self, ast)
111
+ end
112
+
113
+ # ----- The following methods are different/additions from the original Literal_evaluator
114
+ def literal_Object(o) # rubocop:disable Naming/UncommunicativeMethodParamName
115
+ # Ignore any other object types
116
+ end
117
+
118
+ def literal_AccessExpression(o) # rubocop:disable Naming/UncommunicativeMethodParamName
119
+ # Extract the raw text of the Access Expression
120
+ ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(o).extract_text
121
+ end
122
+
123
+ def literal_QualifiedReference(o) # rubocop:disable Naming/UncommunicativeMethodParamName
124
+ # Extract the raw text of the Qualified Reference
125
+ ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(o).extract_text
126
+ end
127
+
128
+ # ----- The following methods are the same as the original Literal_evaluator
129
+ def literal_Factory(o) # rubocop:disable Naming/UncommunicativeMethodParamName
130
+ literal(o.model)
131
+ end
132
+
133
+ def literal_Program(o) # rubocop:disable Naming/UncommunicativeMethodParamName
134
+ literal(o.body)
135
+ end
136
+
137
+ def literal_LiteralString(o) # rubocop:disable Naming/UncommunicativeMethodParamName
138
+ o.value
139
+ end
140
+
141
+ def literal_QualifiedName(o) # rubocop:disable Naming/UncommunicativeMethodParamName
142
+ o.value
143
+ end
144
+
145
+ def literal_LiteralNumber(o) # rubocop:disable Naming/UncommunicativeMethodParamName
146
+ o.value
147
+ end
148
+
149
+ def literal_LiteralBoolean(o) # rubocop:disable Naming/UncommunicativeMethodParamName
150
+ o.value
151
+ end
152
+
153
+ def literal_LiteralUndef(o) # rubocop:disable Naming/UncommunicativeMethodParamName
154
+ nil
155
+ end
156
+
157
+ def literal_LiteralDefault(o) # rubocop:disable Naming/UncommunicativeMethodParamName
158
+ :default
159
+ end
160
+
161
+ def literal_LiteralRegularExpression(o) # rubocop:disable Naming/UncommunicativeMethodParamName
162
+ o.value
163
+ end
164
+
165
+ def literal_ConcatenatedString(o) # rubocop:disable Naming/UncommunicativeMethodParamName
166
+ # use double quoted string value if there is no interpolation
167
+ throw :not_literal unless o.segments.size == 1 && o.segments[0].is_a?(Model::LiteralString)
168
+ o.segments[0].value
169
+ end
170
+
171
+ def literal_LiteralList(o) # rubocop:disable Naming/UncommunicativeMethodParamName
172
+ o.values.map {|v| literal(v) }
173
+ end
174
+
175
+ def literal_LiteralHash(o) # rubocop:disable Naming/UncommunicativeMethodParamName
176
+ o.entries.reduce({}) do |result, entry|
177
+ result[literal(entry.key)] = literal(entry.value)
178
+ result
179
+ end
180
+ end
181
+ end
182
+
183
+ def populate_data_type_params_from_literal_hash!(hash, params_hash)
184
+ return if hash.nil?
185
+ # Exit early if there are no entries in the hash
186
+ return if hash['attributes'].nil? || hash['attributes'].count.zero?
187
+
188
+ hash['attributes'].each do |key, value|
189
+ data_type = nil
190
+ default = nil
191
+ case value
192
+ when String
193
+ data_type = value
194
+ when Hash
195
+ data_type = value['type'] unless value['type'].nil?
196
+ default = value['value'] unless value['value'].nil?
197
+ end
198
+ data_type = [data_type] unless data_type.nil? || data_type.is_a?(Array)
199
+ params_hash[key] = { :types => data_type, :default => default }
200
+ end
201
+ end
202
+
203
+ def validate_tags!(object, actual_params_hash)
204
+ actual_param_names = actual_params_hash.keys
205
+ tagged_param_names = object.tags(:param).map(&:name)
206
+ # Log any errors
207
+ # Find attributes which are not documented
208
+ (actual_param_names - tagged_param_names).each do |item|
209
+ log.warn "Missing @param tag for attribute '#{item}' near #{object.file}:#{object.line}."
210
+ end
211
+ # Find param tags with no matching attribute
212
+ (tagged_param_names - actual_param_names).each do |item|
213
+ log.warn "The @param tag for '#{item}' has no matching attribute near #{object.file}:#{object.line}."
214
+ end
215
+ # Find param tags with a type that is different from the actual definition
216
+ object.tags(:param).reject { |tag| tag.types.nil? }.each do |tag|
217
+ next if actual_params_hash[tag.name].nil?
218
+ actual_data_type = actual_params_hash[tag.name][:types]
219
+ next if actual_data_type.nil?
220
+ 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
+ end
222
+
223
+ # Automatically fix missing @param tags
224
+ (actual_param_names - tagged_param_names).each do |name|
225
+ object.add_parameter(name, actual_params_hash[name][:types], actual_params_hash[name][:default])
226
+ end
227
+ # Remove extra param tags
228
+ object.docstring.delete_tag_if { |item| item.tag_name == 'param' && !actual_param_names.include?(item.name) }
229
+
230
+ # Set the type in the param tag
231
+ object.tags(:param).each do |tag|
232
+ next if actual_params_hash[tag.name].nil?
233
+ tag.types = actual_params_hash[tag.name][:types]
234
+ end
235
+ end
236
+ end