puppet-lint-param_comment-check 0.1.5 → 0.1.8

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