puppet-lint-param_comment-check 0.1.5 → 0.1.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 637cfc1953d7f93cd5a8d160e90d7abeaf93efd0a1eafbf651dca61259fb6668
4
- data.tar.gz: 7d74686774590de42d926b2e1a952330a1613e2b3724a8aac531d5003d3916a8
3
+ metadata.gz: 1ecd8b3c79ba841bf497a02bf7c635255479ce777ccd1d74a02938a6aea16e56
4
+ data.tar.gz: 54fd7284713d765083cb0834a3ef42f44e149ebbb8c16753a9251369a96a298a
5
5
  SHA512:
6
- metadata.gz: d67851be5623ec31c85ff025c13420e8535915d7f9df8d6e8c153df4e7f51c3874253a5dcdf87b30ccab4841a31501f91ab98989d40e30717ede4317dd55da18
7
- data.tar.gz: f47b461b2b56d68e9792be6c8da580f4f4222960364ef165d72fe867007e0a2335adcffe5898b978c386141c0b374c10228f9a7257971fbd11374b765666f2f5
6
+ metadata.gz: 6a44d786af696714854f1252d8ec33a40682080becac84e5b3e1f7ab7cf78c7f14022f8096965a7df8c8c8bd841febcb9580f065258943fc45ee6ef7f493933b
7
+ data.tar.gz: 5f2bdc6cc3bd83d359f6b350c703897a3be79edb695ecaaacf44b4afb94cbda7427c0ed536834f45ee5f35f401cd9828b6612660815e16aa70f131105ec0c38f
@@ -1,15 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../puppet-lint-param_comment-check/param_workflow'
4
3
  require_relative '../../puppet-lint-param_comment-check/param_comments'
5
-
6
- # The empty data of a parameter
7
- EMPTY_PARAM = {
8
- name: '',
9
- type: '',
10
- has_default: false,
11
- default: ''
12
- }.freeze
4
+ require_relative '../../puppet-lint-param_comment-check/param'
13
5
 
14
6
  # Find the header comments for a class or a defined type
15
7
  #
@@ -28,44 +20,13 @@ def get_comments(tokens, token_start)
28
20
  comments.reject { |comment| comment.type == :NEWLINE }.reverse
29
21
  end
30
22
 
31
- # Analyze a parameter token
32
- #
33
- # @param token The token to analyze
34
- # @param current_param the data object for the currently analyzed parameter
35
- def analyze_param_token(token, current_param)
36
- # noinspection RubyCaseWithoutElseBlockInspection
37
- case token.type
38
- when :VARIABLE
39
- current_param[:name] = token.value
40
- when :CLASSREF, :TYPE
41
- current_param[:type] = token.value
42
- when :EQUALS
43
- current_param[:has_default] = true
44
- current_param[:default] = token.next_token.value
45
- end
46
- current_param
47
- end
48
-
49
23
  # Analyze the parameters of a class or a defined type
50
24
  #
51
25
  # @param param_tokens The parameter tokens to analyze
52
- def analyze_params(param_tokens) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
53
- params = []
54
- current_param = EMPTY_PARAM.dup
55
- brackets = 0
56
- param_tokens.reject { |token| %i[WHITESPACE NEWLINE INDENT].include? token.type }.each do |token|
57
- brackets += 1 if %i[LBRACK LBRACE].include? token.type
58
- brackets -= 1 if %i[RBRACK RBRACE].include? token.type
59
- next unless brackets.zero?
60
-
61
- current_param = analyze_param_token(token, current_param) unless token.type == :COMMA
62
- if token.type == :COMMA
63
- params.append(current_param)
64
- current_param = EMPTY_PARAM.dup
65
- end
66
- end
67
- params.append(current_param) unless current_param[:name] == ''
68
- params
26
+ def analyze_params(param_tokens)
27
+ param_workflow = Param.new
28
+ param_workflow.process(param_tokens)
29
+ param_workflow.params
69
30
  end
70
31
 
71
32
  # Find, which parameters in the long list are missing in the short list and return their names
@@ -143,10 +104,14 @@ PuppetLint.new_check(:param_comment) do # rubocop:disable Metrics/BlockLength
143
104
  end
144
105
 
145
106
  # Check class or defined type indexes
146
- def check_indexes(indexes)
107
+ def check_indexes(indexes) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
147
108
  indexes.each do |index|
148
109
  comments = get_comments(tokens, index[:start])
149
- params = analyze_params(index[:param_tokens])
110
+ begin
111
+ params = analyze_params(index[:param_tokens])
112
+ rescue InvalidTokenForState, InvalidDefaultForOptional => e
113
+ return warn(e.message, e.token.line, e.token.column)
114
+ end
150
115
  return false unless check_comments(comments)
151
116
  return false unless check_parameters_count(params)
152
117
 
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'param_workflow'
4
+
5
+ PARAM_TYPE_ENUM = {
6
+ mandatory: 1,
7
+ with_default: 2,
8
+ optional: 3
9
+ }.freeze
10
+
11
+ # The empty data of a parameter
12
+ EMPTY_PARAM = {
13
+ name: '',
14
+ type: '',
15
+ default: [],
16
+ param_type: PARAM_TYPE_ENUM[:mandatory]
17
+ }.freeze
18
+
19
+ # Comment received in an invalid state
20
+ class InvalidTokenForState < StandardError
21
+ def initialize(token, state)
22
+ @token = token
23
+ @state = state
24
+ super "Can not process the token '#{@token.value.strip}' in the state #{@state}"
25
+ end
26
+
27
+ attr_reader :token
28
+ end
29
+
30
+ # An optional parameter does not have "undef" as the default
31
+ class InvalidDefaultForOptional < StandardError
32
+ def initialize(token, default_value)
33
+ @token = token
34
+ super "Invalid value '#{default_value}' for an parameter of type Optional. undef is required"
35
+ end
36
+
37
+ attr_reader :token
38
+ end
39
+
40
+ # A helper to analyze parameter comments using the ParamWorkflow fsm
41
+ class Param
42
+ def initialize
43
+ @workflow = ParamWorkflow.new(self)
44
+
45
+ reset
46
+ end
47
+
48
+ def reset
49
+ @params = []
50
+ @in_default = false
51
+ @default_tokens = []
52
+ @in_type = false
53
+ @type_tokens = []
54
+ @current_param = EMPTY_PARAM.dup
55
+ @current_token = nil
56
+ @workflow.restore!(:start)
57
+ end
58
+
59
+ # Walk through every parameter and transition the workflow fsm accordingly
60
+ #
61
+ # @param tokens A list of parameter tokens
62
+ def process(tokens) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
63
+ reset
64
+ brackets = 0
65
+ tokens.reject { |token| %i[NEWLINE INDENT].include? token.type }.each do |token| # rubocop:disable Metrics/BlockLength
66
+ @current_token = token
67
+ case token.type
68
+ when :TYPE
69
+ if @in_default
70
+ @default_tokens.append(token)
71
+ next
72
+ end
73
+ @workflow.got_type unless @in_type
74
+ @in_type = true
75
+ @type_tokens.append(token)
76
+ when :VARIABLE
77
+ @workflow.got_name(token, @type_tokens) unless @in_default
78
+ @in_type = false unless @in_default
79
+ @type_tokens = [] unless @in_default
80
+ @default_tokens.append(token) if @in_default
81
+ when :EQUALS
82
+ @in_default = true
83
+ when :COMMA
84
+ @workflow.got_end(@default_tokens) unless @in_type || brackets.positive?
85
+ @default_tokens = [] unless @in_type && brackets.positive?
86
+ @in_default = false unless @in_type && brackets.positive?
87
+ @type_tokens.append(token) if @in_type
88
+ when :LBRACE, :LBRACK, :LPAREN
89
+ brackets += 1
90
+ @type_tokens.append(token) if @in_type
91
+ @default_tokens.append(token) if @in_default
92
+ when :RBRACE, :RBRACK, :RPAREN
93
+ brackets -= 1
94
+ @type_tokens.append(token) if @in_type
95
+ @default_tokens.append(token) if @in_default
96
+ else
97
+ @type_tokens.append(token) if @in_type
98
+ @default_tokens.append(token) if @in_default
99
+ end
100
+ end
101
+ @workflow.got_end(@default_tokens) unless @workflow.current == :start
102
+ end
103
+
104
+ def got_name_trigger(_, token, type_tokens)
105
+ @current_param[:type] = type_tokens.map(&:value).join('')
106
+ if !@type_tokens.empty? && @type_tokens[0].value == 'OPTIONAL'
107
+ @current_param[:param_type] = PARAM_TYPE_ENUM[:optional]
108
+ end
109
+ @current_param[:name] = token.value
110
+ end
111
+
112
+ def got_end_trigger(_, default_tokens) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
113
+ raise InvalidDefaultForOptional if @current_param[:param_type] == PARAM_TYPE_ENUM[:optional] &&
114
+ !default_tokens.empty? &&
115
+ default_tokens[0].value != 'undef'
116
+
117
+ @current_param[:default] = @default_tokens.map(&:value).join('') unless @default_tokens.empty?
118
+ @current_param[:param_type] = PARAM_TYPE_ENUM[:with_default] unless
119
+ @current_param[:param_type] == PARAM_TYPE_ENUM[:optional] || default_tokens.empty?
120
+ @params.append(@current_param)
121
+ @current_param = EMPTY_PARAM.dup
122
+ @in_default, @in_type = false
123
+ end
124
+
125
+ # Called when an invalid state transition would happen
126
+ def invalid_state
127
+ raise InvalidTokenForState.new(@current_token, @workflow.current)
128
+ end
129
+
130
+ # The list of analyzed parameters in the comments
131
+ attr_reader :params
132
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'param_comments_workflow'
4
+
3
5
  # The empty data of a parameter
4
6
  EMPTY_PARAM_COMMENT = {
5
7
  name: '',
@@ -56,7 +58,7 @@ end
56
58
  # A helper to analyze parameter comments using the ParamWorkflow fsm
57
59
  class ParamComments
58
60
  def initialize
59
- @workflow = ParamWorkflow.new(self)
61
+ @workflow = ParamCommentsWorkflow.new(self)
60
62
 
61
63
  reset
62
64
  end
@@ -73,7 +75,7 @@ class ParamComments
73
75
  # Walk through every comment and transition the workflow fsm accordingly
74
76
  #
75
77
  # @param comments A list of Comment tokens appearing before the class/defined type header
76
- def process(comments) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
78
+ def process(comments) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/AbcSize
77
79
  reset
78
80
  @current_comment = PuppetLint::Lexer::Token.new(:COMMENT, '', 1, 1)
79
81
  comments.each do |comment|
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'finite_machine'
4
+
5
+ # A finite state machine working through the expected parameter comments
6
+ class ParamCommentsWorkflow < FiniteMachine::Definition
7
+ initial :start
8
+
9
+ event :got_header, from: :start, to: :awaiting_description
10
+ event :got_header, from: :awaiting_header, to: :awaiting_description
11
+ event :got_description, from: :awaiting_description, to: :awaiting_separator
12
+ event :got_separator, from: :awaiting_separator, to: :awaiting_header
13
+
14
+ # for multi-line descriptions
15
+ event :got_description, from: :awaiting_separator, to: :awaiting_separator
16
+
17
+ # handling options
18
+ event :got_option_header, from: :awaiting_separator, to: :awaiting_option_description
19
+ event :got_option_description, from: :awaiting_option_description, to: :awaiting_separator
20
+
21
+ # for separators inside descriptions
22
+ event :got_description, from: :awaiting_header, to: :awaiting_separator
23
+ event :got_option_description, from: :awaiting_separator, to: :awaiting_separator
24
+
25
+ on_before(:got_header) { |event, comment| target.got_header_trigger(event, comment) }
26
+ on_before(:got_description) { |event, comment| target.got_description_trigger(event, comment) }
27
+ on_before(:got_option_description) { |event, comment| target.got_description_trigger(event, comment) }
28
+ on_before(:got_option_header) { |event, comment| target.got_option_header_trigger(event, comment) }
29
+
30
+ handle FiniteMachine::InvalidStateError, with: -> { target.invalid_state }
31
+ end
@@ -2,30 +2,22 @@
2
2
 
3
3
  require 'finite_machine'
4
4
 
5
- # A finite state machine working through the expected parameter comments
5
+ # A finite state machine working through the expected parameter tokens
6
6
  class ParamWorkflow < FiniteMachine::Definition
7
7
  initial :start
8
8
 
9
- event :got_header, from: :start, to: :awaiting_description
10
- event :got_header, from: :awaiting_header, to: :awaiting_description
11
- event :got_description, from: :awaiting_description, to: :awaiting_separator
12
- event :got_separator, from: :awaiting_separator, to: :awaiting_header
9
+ event :got_type, from: :start, to: :awaiting_name
10
+ event :got_name, from: :awaiting_name, to: :awaiting_default
13
11
 
14
- # for multi-line descriptions
15
- event :got_description, from: :awaiting_separator, to: :awaiting_separator
12
+ # For mandatory parameters
13
+ event :got_end, from: :awaiting_name, to: :start
14
+ event :got_end, from: :awaiting_default, to: :start
16
15
 
17
- # handling options
18
- event :got_option_header, from: :awaiting_separator, to: :awaiting_option_description
19
- event :got_option_description, from: :awaiting_option_description, to: :awaiting_separator
16
+ # For typeless parameters
17
+ event :got_name, from: :start, to: :awaiting_default
20
18
 
21
- # for separators inside descriptions
22
- event :got_description, from: :awaiting_header, to: :awaiting_separator
23
- event :got_option_description, from: :awaiting_separator, to: :awaiting_separator
24
-
25
- on_before(:got_header) { |event, comment| target.got_header_trigger(event, comment) }
26
- on_before(:got_description) { |event, comment| target.got_description_trigger(event, comment) }
27
- on_before(:got_option_description) { |event, comment| target.got_description_trigger(event, comment) }
28
- on_before(:got_option_header) { |event, comment| target.got_option_header_trigger(event, comment) }
19
+ on_before(:got_name) { |event, token, type_tokens| target.got_name_trigger(event, token, type_tokens) }
20
+ on_before(:got_end) { |event, default_tokens| target.got_end_trigger(event, default_tokens) }
29
21
 
30
22
  handle FiniteMachine::InvalidStateError, with: -> { target.invalid_state }
31
23
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require_relative '../../spec_helper'
4
4
 
5
+ # rubocop:disable Metrics/BlockLength
5
6
  describe 'param_comment' do
6
7
  context 'valid code' do
7
8
  let(:code) do
@@ -153,6 +154,26 @@ describe 'param_comment' do
153
154
  end
154
155
  end
155
156
 
157
+ context 'valid code with parentheses in the parameters' do
158
+ let(:code) do
159
+ <<~CODE
160
+ # @summary
161
+ # some class
162
+ #
163
+ # @param mandatory
164
+ # A mandatory parameter
165
+ # with two lines
166
+ class my_class (
167
+ String $mandatory = join([0,1,2], ','),
168
+ ) {}
169
+ CODE
170
+ end
171
+
172
+ it 'should not detect any problems' do
173
+ expect(problems).to have(0).problems
174
+ end
175
+ end
176
+
156
177
  context 'code with missing parameter comment' do
157
178
  let(:code) do
158
179
  <<~CODE
@@ -255,9 +276,11 @@ describe 'param_comment' do
255
276
  end
256
277
 
257
278
  it 'should create a warning' do
258
- expect(problems).to contain_warning('Can not process the comment \'@param withdefault\' in the state awaiting_separator')
259
- .on_line(3)
260
- .in_column(1)
279
+ expect(problems).to contain_warning(
280
+ 'Can not process the comment \'@param withdefault\' in the state awaiting_separator'
281
+ )
282
+ .on_line(3)
283
+ .in_column(1)
261
284
  end
262
285
  end
263
286
 
@@ -276,9 +299,11 @@ describe 'param_comment' do
276
299
  end
277
300
 
278
301
  it 'should create a warning' do
279
- expect(problems).to contain_warning('Invalid param or hash option header: @param mandatory A mandatory parameter')
280
- .on_line(1)
281
- .in_column(1)
302
+ expect(problems).to contain_warning(
303
+ 'Invalid param or hash option header: @param mandatory A mandatory parameter'
304
+ )
305
+ .on_line(1)
306
+ .in_column(1)
282
307
  end
283
308
  end
284
309
 
@@ -321,9 +346,11 @@ describe 'param_comment' do
321
346
  end
322
347
 
323
348
  it 'should create a warning' do
324
- expect(problems).to contain_warning('Option references wrong hash @option mandatry [Boolean] :some_option')
325
- .on_line(3)
326
- .in_column(1)
349
+ expect(problems).to contain_warning(
350
+ 'Option references wrong hash @option mandatry [Boolean] :some_option'
351
+ )
352
+ .on_line(3)
353
+ .in_column(1)
327
354
  end
328
355
  end
329
356
 
@@ -347,10 +374,10 @@ describe 'param_comment' do
347
374
 
348
375
  it 'should create a warning' do
349
376
  expect(problems).to contain_warning(
350
- 'Can not process the comment \'@option mandatory [Boolean] :some_option\' in the state awaiting_header'
351
- )
352
- .on_line(4)
353
- .in_column(1)
377
+ 'Can not process the comment \'@option mandatory [Boolean] :some_option\' in the state awaiting_header'
378
+ )
379
+ .on_line(4)
380
+ .in_column(1)
354
381
  end
355
382
  end
356
383
 
@@ -372,10 +399,10 @@ describe 'param_comment' do
372
399
 
373
400
  it 'should create a warning' do
374
401
  expect(problems).to contain_warning(
375
- 'Invalid param or hash option header: @option mandatory [Boolean] :some_option An option'
376
- )
377
- .on_line(3)
378
- .in_column(1)
402
+ 'Invalid param or hash option header: @option mandatory [Boolean] :some_option An option'
403
+ )
404
+ .on_line(3)
405
+ .in_column(1)
379
406
  end
380
407
  end
381
408
 
@@ -401,10 +428,10 @@ describe 'param_comment' do
401
428
 
402
429
  it 'should create a warning' do
403
430
  expect(problems).to contain_warning(
404
- 'Can not process the comment \'@param second\' in the state awaiting_separator'
405
- )
406
- .on_line(5)
407
- .in_column(1)
431
+ 'Can not process the comment \'@param second\' in the state awaiting_separator'
432
+ )
433
+ .on_line(5)
434
+ .in_column(1)
408
435
  end
409
436
  end
410
437
 
@@ -426,3 +453,4 @@ describe 'param_comment' do
426
453
  end
427
454
  end
428
455
  end
456
+ # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-lint-param_comment-check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Ploeger
@@ -131,7 +131,9 @@ extra_rdoc_files: []
131
131
  files:
132
132
  - LICENSE
133
133
  - README.md
134
+ - lib/puppet-lint-param_comment-check/param.rb
134
135
  - lib/puppet-lint-param_comment-check/param_comments.rb
136
+ - lib/puppet-lint-param_comment-check/param_comments_workflow.rb
135
137
  - lib/puppet-lint-param_comment-check/param_workflow.rb
136
138
  - lib/puppet-lint/plugins/check_param_comment.rb
137
139
  - spec/puppet-lint/plugins/check_param_comment_spec.rb