puppet-strings 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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