puppet-lint 0.1.13 → 0.2.0.pre1

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.
@@ -1,49 +1,80 @@
1
1
  class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
2
- if Puppet::PUPPETVERSION !~ /^0\.2/
3
- check 'right_to_left_relationship' do
4
- tokens.select { |r| r.first == :OUT_EDGE }.each do |token|
5
- notify :warning, :message => "right-to-left (<-) relationship", :linenumber => token.last[:line]
6
- end
2
+ # Public: Test the manifest tokens for any right-to-left (<-) chaining
3
+ # operators and record a warning for each instance found.
4
+ #
5
+ # Returns nothing.
6
+ check 'right_to_left_relationship' do
7
+ tokens.select { |r| r.type == :OUT_EDGE }.each do |token|
8
+ notify :warning, {
9
+ :message => 'right-to-left (<-) relationship',
10
+ :linenumber => token.line,
11
+ :column => token.column,
12
+ }
7
13
  end
8
14
  end
9
15
 
16
+ # Public: Test the manifest tokens for any classes or defined types that are
17
+ # not in an appropriately named file for the autoloader to detect and record
18
+ # an error of each instance found.
19
+ #
20
+ # Returns nothing.
10
21
  check 'autoloader_layout' do
11
- unless fullpath == ""
22
+ unless fullpath == ''
12
23
  (class_indexes + defined_type_indexes).each do |class_idx|
13
- title_token = tokens[class_idx[:start]+1]
14
- split_title = title_token.last[:value].split('::')
24
+ class_tokens = tokens[class_idx[:start]..class_idx[:end]]
25
+ title_token = class_tokens[class_tokens.index { |r| r.type == :NAME }]
26
+ split_title = title_token.value.split('::')
27
+ mod = split_title.first
15
28
  if split_title.length > 1
16
- expected_path = "#{split_title.first}/manifests/#{split_title[1..-1].join('/')}.pp"
29
+ expected_path = "#{mod}/manifests/#{split_title[1..-1].join('/')}.pp"
17
30
  else
18
- expected_path = "#{title_token.last[:value]}/manifests/init.pp"
31
+ expected_path = "#{title_token.value}/manifests/init.pp"
19
32
  end
20
33
 
21
34
  unless fullpath.end_with? expected_path
22
- notify :error, :message => "#{title_token.last[:value]} not in autoload module layout", :linenumber => title_token.last[:line]
35
+ notify :error, {
36
+ :message => "#{title_token.value} not in autoload module layout",
37
+ :linenumber => title_token.line,
38
+ :column => title_token.column,
39
+ }
23
40
  end
24
41
  end
25
42
  end
26
43
  end
27
44
 
45
+ # Public: Test the manifest tokens for any parameterised classes or defined
46
+ # types that take parameters and record a warning if there are any optional
47
+ # parameters listed before required parameters.
48
+ #
49
+ # Returns nothing.
28
50
  check 'parameter_order' do
29
51
  (class_indexes + defined_type_indexes).each do |class_idx|
30
52
  token_idx = class_idx[:start]
31
- header_end_idx = tokens[token_idx..-1].index { |r| r.first == :LBRACE }
32
- lparen_idx = tokens[token_idx..(header_end_idx + token_idx)].index { |r| r.first == :LPAREN }
33
- rparen_idx = tokens[token_idx..(header_end_idx + token_idx)].rindex { |r| r.first == :RPAREN }
53
+ header_end_idx = tokens[token_idx..-1].index { |r| r.type == :LBRACE }
54
+ header_tokens = tokens[token_idx..header_end_idx].reject { |r|
55
+ formatting_tokens.include?(r.type)
56
+ }
57
+ lparen_idx = header_tokens.index { |r| r.type == :LPAREN }
58
+ rparen_idx = header_tokens.rindex { |r| r.type == :RPAREN }
34
59
 
35
60
  unless lparen_idx.nil? or rparen_idx.nil?
36
- param_tokens = tokens[lparen_idx..rparen_idx]
61
+ param_tokens = header_tokens[lparen_idx..rparen_idx]
37
62
  param_tokens.each_index do |param_tokens_idx|
38
63
  this_token = param_tokens[param_tokens_idx]
39
64
  next_token = param_tokens[param_tokens_idx+1]
40
65
  prev_token = param_tokens[param_tokens_idx-1]
41
- if this_token.first == :VARIABLE
66
+ if this_token.type == :VARIABLE
42
67
  unless next_token.nil?
43
- if next_token.first == :COMMA or next_token.first == :RPAREN
44
- unless param_tokens[0..param_tokens_idx].rindex { |r| r.first == :EQUALS }.nil?
45
- unless prev_token.nil? or prev_token.first == :EQUALS
46
- notify :warning, :message => "optional parameter listed before required parameter", :linenumber => this_token.last[:line]
68
+ if next_token.type == :COMMA or next_token.type == :RPAREN
69
+ prev_tokens = param_tokens[0..param_tokens_idx]
70
+ unless prev_tokens.rindex { |r| r.type == :EQUALS }.nil?
71
+ unless prev_token.nil? or prev_token.type == :EQUALS
72
+ msg = 'optional parameter listed before required parameter'
73
+ notify :warning, {
74
+ :message => msg,
75
+ :linenumber => this_token.line,
76
+ :column => this_token.column,
77
+ }
47
78
  end
48
79
  end
49
80
  end
@@ -54,57 +85,107 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
54
85
  end
55
86
  end
56
87
 
88
+ # Public: Test the manifest tokens for any classes that inherit across
89
+ # namespaces and record a warning for each instance found.
90
+ #
91
+ # Returns nothing.
57
92
  check 'inherits_across_namespaces' do
58
93
  class_indexes.each do |class_idx|
59
- token_idx = class_idx[:start]
60
- if tokens[token_idx+2].first == :INHERITS
61
- class_name = tokens[token_idx+1].last[:value]
62
- inherited_class = tokens[token_idx+3].last[:value]
94
+ class_tokens = tokens[class_idx[:start]..class_idx[:end]].reject { |r|
95
+ formatting_tokens.include?(r.type)
96
+ }
97
+
98
+ if class_tokens[2].type == :INHERITS
99
+ class_name = class_tokens[1].value
100
+ inherited_class = class_tokens[3].value
63
101
 
64
102
  unless class_name =~ /^#{inherited_class}::/
65
- notify :warning, :message => "class inherits across namespaces", :linenumber => tokens[token_idx].last[:line]
103
+ notify :warning, {
104
+ :message => "class inherits across namespaces",
105
+ :linenumber => class_tokens[3].line,
106
+ :column => class_tokens[3].column,
107
+ }
66
108
  end
67
109
  end
68
110
  end
69
111
  end
70
112
 
113
+ # Public: Test the manifest tokens for any classes or defined types that are
114
+ # defined inside another class.
115
+ #
116
+ # Returns nothing.
71
117
  check 'nested_classes_or_defines' do
72
118
  class_indexes.each do |class_idx|
73
- class_tokens = tokens[class_idx[:start]..class_idx[:end]]
74
- class_tokens[1..-1].each_index do |token_idx|
75
- token = class_tokens[1..-1][token_idx]
76
- next_token = class_tokens[1..-1][token_idx + 1]
77
-
78
- if token.first == :CLASS
79
- if next_token.first != :LBRACE
80
- notify :warning, :message => "class defined inside a class", :linenumber => token.last[:line]
119
+ # Skip the first token so that we don't pick up the first :CLASS
120
+ class_tokens = tokens[class_idx[:start]+1..class_idx[:end]].reject { |r|
121
+ formatting_tokens.include?(r.type)
122
+ }
123
+
124
+ class_tokens.each_index do |token_idx|
125
+ token = class_tokens[token_idx]
126
+ next_token = class_tokens[token_idx + 1]
127
+
128
+ if token.type == :CLASS
129
+ if next_token.type != :LBRACE
130
+ notify :warning, {
131
+ :message => "class defined inside a class",
132
+ :linenumber => token.line,
133
+ :column => token.column,
134
+ }
81
135
  end
82
136
  end
83
137
 
84
- if token.first == :DEFINE
85
- notify :warning, :message => "define defined inside a class", :linenumber => token.last[:line]
138
+ if token.type == :DEFINE
139
+ notify :warning, {
140
+ :message => "define defined inside a class",
141
+ :linenumber => token.line,
142
+ :column => token.column,
143
+ }
86
144
  end
87
145
  end
88
146
  end
89
147
  end
90
148
 
149
+ # Public: Test the manifest tokens for any variables that are referenced in
150
+ # the manifest. If the variables are not fully qualified or one of the
151
+ # variables automatically created in the scope, check that they have been
152
+ # defined in the local scope and record a warning for each variable that has
153
+ # not.
154
+ #
155
+ # Returns nothing.
91
156
  check 'variable_scope' do
157
+ variables_in_scope = [
158
+ 'name',
159
+ 'title',
160
+ 'module_name',
161
+ 'environment',
162
+ 'clientcert',
163
+ 'clientversion',
164
+ 'servername',
165
+ 'serverip',
166
+ 'serverversion',
167
+ 'caller_module_name',
168
+ ]
92
169
  (class_indexes + defined_type_indexes).each do |idx|
93
170
  object_tokens = tokens[idx[:start]..idx[:end]]
94
- variables_in_scope = ['name', 'title', 'module_name', 'environment', 'clientcert', 'clientversion', 'servername', 'serverip', 'serverversion', 'caller_module_name']
171
+ object_tokens.reject! { |r| formatting_tokens.include?(r.type) }
95
172
  referenced_variables = []
96
- header_end_idx = object_tokens.index { |r| r.first == :LBRACE }
97
- lparen_idx = object_tokens[0..header_end_idx].index { |r| r.first == :LPAREN }
98
- rparen_idx = object_tokens[0..header_end_idx].rindex { |r| r.first == :RPAREN }
173
+ header_end_idx = object_tokens.index { |r| r.type == :LBRACE }
174
+ lparen_idx = object_tokens[0..header_end_idx].index { |r|
175
+ r.type == :LPAREN
176
+ }
177
+ rparen_idx = object_tokens[0..header_end_idx].rindex { |r|
178
+ r.type == :RPAREN
179
+ }
99
180
 
100
181
  unless lparen_idx.nil? or rparen_idx.nil?
101
182
  param_tokens = object_tokens[lparen_idx..rparen_idx]
102
183
  param_tokens.each_index do |param_tokens_idx|
103
184
  this_token = param_tokens[param_tokens_idx]
104
185
  next_token = param_tokens[param_tokens_idx+1]
105
- if this_token.first == :VARIABLE
106
- if [:COMMA, :EQUALS, :RPAREN].include? next_token.first
107
- variables_in_scope << this_token.last[:value]
186
+ if this_token.type == :VARIABLE
187
+ if [:COMMA, :EQUALS, :RPAREN].include? next_token.type
188
+ variables_in_scope << this_token.value
108
189
  end
109
190
  end
110
191
  end
@@ -114,20 +195,25 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
114
195
  this_token = object_tokens[object_token_idx]
115
196
  next_token = object_tokens[object_token_idx + 1]
116
197
 
117
- if this_token.first == :VARIABLE
118
- if next_token.first == :EQUALS
119
- variables_in_scope << this_token.last[:value]
198
+ if this_token.type == :VARIABLE
199
+ if next_token.type == :EQUALS
200
+ variables_in_scope << this_token.value
120
201
  else
121
202
  referenced_variables << this_token
122
203
  end
123
204
  end
124
205
  end
125
206
 
207
+ msg = "top-scope variable being used without an explicit namespace"
126
208
  referenced_variables.each do |token|
127
- unless token.last[:value].include? '::'
128
- unless variables_in_scope.include? token.last[:value]
129
- unless token.last[:value] =~ /\d+/
130
- notify :warning, :message => "top-scope variable being used without an explicit namespace", :linenumber => token.last[:line]
209
+ unless token.value.include? '::'
210
+ unless variables_in_scope.include? token.value
211
+ unless token.value =~ /\d+/
212
+ notify :warning, {
213
+ :message => msg,
214
+ :linenumber => token.line,
215
+ :column => token.column,
216
+ }
131
217
  end
132
218
  end
133
219
  end
@@ -1,14 +1,24 @@
1
1
  class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
2
+ # Public: Test the manifest tokens for any selectors embedded within resource
3
+ # declarations and record a warning for each instance found.
4
+ #
5
+ # Returns nothing.
2
6
  check 'selector_inside_resource' do
3
7
  resource_indexes.each do |resource|
4
- resource_tokens = tokens[resource[:start]..resource[:end]]
8
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
9
+ formatting_tokens.include? r.type
10
+ }
5
11
 
6
12
  resource_tokens.each_index do |resource_token_idx|
7
- if resource_tokens[resource_token_idx].first == :FARROW
8
- if resource_tokens[resource_token_idx + 1].first == :VARIABLE
13
+ if resource_tokens[resource_token_idx].type == :FARROW
14
+ if resource_tokens[resource_token_idx + 1].type == :VARIABLE
9
15
  unless resource_tokens[resource_token_idx + 2].nil?
10
- if resource_tokens[resource_token_idx + 2].first == :QMARK
11
- notify :warning, :message => "selector inside resource block", :linenumber => resource_tokens[resource_token_idx].last[:line]
16
+ if resource_tokens[resource_token_idx + 2].type == :QMARK
17
+ notify :warning, {
18
+ :message => 'selector inside resource block',
19
+ :linenumber => resource_tokens[resource_token_idx].line,
20
+ :column => resource_tokens[resource_token_idx].column,
21
+ }
12
22
  end
13
23
  end
14
24
  end
@@ -17,26 +27,23 @@ class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
17
27
  end
18
28
  end
19
29
 
30
+ # Public: Test the manifest tokens for any case statements that do not
31
+ # contain a "default" case and record a warning for each instance found.
32
+ #
33
+ # Returns nothing.
20
34
  check 'case_without_default' do
21
35
  case_indexes = []
22
36
 
23
37
  tokens.each_index do |token_idx|
24
- if tokens[token_idx].first == :COLON
25
- # gather a list of start and end indexes for resource attribute blocks
26
- if tokens[token_idx+1].first != :LBRACE
27
- resource_indexes << {:start => token_idx+1, :end => tokens[token_idx+1..-1].index { |r| [:SEMIC, :RBRACE].include? r.first }+token_idx}
28
- end
29
- end
30
-
31
- if tokens[token_idx].first == :CASE
32
- lbrace_count = 0
33
- tokens[token_idx+1..-1].each_index do |case_token_idx|
34
- idx = case_token_idx + token_idx
35
- if tokens[idx].first == :LBRACE
36
- lbrace_count += 1
37
- elsif tokens[idx].first == :RBRACE
38
- lbrace_count -= 1
39
- if lbrace_count == 0
38
+ if tokens[token_idx].type == :CASE
39
+ depth = 0
40
+ tokens[(token_idx + 1)..-1].each_index do |case_token_idx|
41
+ idx = case_token_idx + token_idx + 1
42
+ if tokens[idx].type == :LBRACE
43
+ depth += 1
44
+ elsif tokens[idx].type == :RBRACE
45
+ depth -= 1
46
+ if depth == 0
40
47
  case_indexes << {:start => token_idx, :end => idx}
41
48
  break
42
49
  end
@@ -48,8 +55,12 @@ class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
48
55
  case_indexes.each do |kase|
49
56
  case_tokens = tokens[kase[:start]..kase[:end]]
50
57
 
51
- unless case_tokens.index { |r| r.first == :DEFAULT }
52
- notify :warning, :message => "case statement without a default case", :linenumber => case_tokens.first.last[:line]
58
+ unless case_tokens.index { |r| r.type == :DEFAULT }
59
+ notify :warning, {
60
+ :message => 'case statement without a default case',
61
+ :linenumber => case_tokens.first.line,
62
+ :column => case_tokens.first.column,
63
+ }
53
64
  end
54
65
  end
55
66
  end
@@ -1,39 +1,79 @@
1
- # Resources
2
- # http://docs.puppetlabs.com/guides/style_guide.html#resources
3
-
4
1
  class PuppetLint::Plugins::CheckResources < PuppetLint::CheckPlugin
2
+ # Public: Check the manifest tokens for any resource titles / namevars that
3
+ # are not quoted and record a warning for each instance found.
4
+ #
5
+ # Return nothing.
5
6
  check 'unquoted_resource_title' do
6
7
  title_tokens.each do |token|
7
- if token.first == :NAME
8
- notify :warning, :message => "unquoted resource title", :linenumber => token.last[:line]
8
+ if token.type == :NAME
9
+ notify :warning, {
10
+ :message => 'unquoted resource title',
11
+ :linenumber => token.line,
12
+ :column => token.column,
13
+ }
9
14
  end
10
15
  end
11
16
  end
12
17
 
18
+ # Public: Check the tokens of each resource instance for an ensure parameter
19
+ # and if found, check that it is the first parameter listed. If it is not
20
+ # the first parameter, record a warning.
21
+ #
22
+ # Returns nothing.
13
23
  check 'ensure_first_param' do
14
24
  resource_indexes.each do |resource|
15
- resource_tokens = tokens[resource[:start]..resource[:end]]
16
- ensure_attr_index = resource_tokens.index { |token| token.first == :NAME and token.last[:value] == 'ensure' }
25
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
26
+ formatting_tokens.include? r.type
27
+ }
28
+
29
+ ensure_attr_index = resource_tokens.index { |token|
30
+ token.type == :NAME and token.value == 'ensure'
31
+ }
32
+
17
33
  unless ensure_attr_index.nil?
18
34
  if ensure_attr_index > 1
19
- ensure_attr_line_no = resource_tokens[ensure_attr_index].last[:line]
20
- notify :warning, :message => "ensure found on line but it's not the first attribute", :linenumber => ensure_attr_line_no
35
+ ensure_token = resource_tokens[ensure_attr_index]
36
+ notify :warning, {
37
+ :message => "ensure found on line but it's not the first attribute",
38
+ :linenumber => ensure_token.line,
39
+ :column => ensure_token.column,
40
+ }
21
41
  end
22
42
  end
23
43
  end
24
44
  end
25
45
 
46
+ # Public: Check the tokens of each File resource instance for a mode
47
+ # parameter and if found, record a warning if the value of that parameter is
48
+ # not a quoted string.
49
+ #
50
+ # Returns nothing.
26
51
  check 'unquoted_file_mode' do
27
52
  resource_indexes.each do |resource|
28
- resource_tokens = tokens[resource[:start]..resource[:end]]
29
- resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
30
- if resource_type_token.last[:value] == "file"
53
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
54
+ formatting_tokens.include? r.type
55
+ }
56
+
57
+ stripped_tokens = tokens[0..resource[:start]].reject { |r|
58
+ formatting_tokens.include? r.type
59
+ }
60
+
61
+ res_type_idx = stripped_tokens.rindex { |r|
62
+ r.type == :LBRACE
63
+ } - 1
64
+
65
+ resource_type_token = stripped_tokens[res_type_idx]
66
+ if resource_type_token.value == "file"
31
67
  resource_tokens.each_index do |resource_token_idx|
32
68
  attr_token = resource_tokens[resource_token_idx]
33
- if attr_token.first == :NAME and attr_token.last[:value] == 'mode'
69
+ if attr_token.type == :NAME and attr_token.value == 'mode'
34
70
  value_token = resource_tokens[resource_token_idx + 2]
35
- if value_token.first == :NAME
36
- notify :warning, :message => "unquoted file mode", :linenumber => value_token.last[:line]
71
+ if value_token.type == :NAME
72
+ notify :warning, {
73
+ :message => 'unquoted file mode',
74
+ :linenumber => value_token.line,
75
+ :column => value_token.column,
76
+ }
37
77
  end
38
78
  end
39
79
  end
@@ -41,35 +81,81 @@ class PuppetLint::Plugins::CheckResources < PuppetLint::CheckPlugin
41
81
  end
42
82
  end
43
83
 
84
+ # Public: Check the tokens of each File resource instance for a mode
85
+ # parameter and if found, record a warning if the value of that parameter is
86
+ # not a 4 digit octal value (0755) or a symbolic mode ('o=rwx,g+r').
87
+ #
88
+ # Returns nothing.
44
89
  check 'file_mode' do
90
+ msg = 'mode should be represented as a 4 digit octal value or symbolic mode'
91
+ sym_mode = /\A([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*\Z/
92
+
45
93
  resource_indexes.each do |resource|
46
- resource_tokens = tokens[resource[:start]..resource[:end]]
47
- resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
48
- if resource_type_token.last[:value] == "file"
94
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
95
+ formatting_tokens.include? r.type
96
+ }
97
+
98
+ stripped_tokens = tokens[0..resource[:start]].reject { |r|
99
+ formatting_tokens.include? r.type
100
+ }
101
+
102
+ res_type_idx = stripped_tokens.rindex { |r|
103
+ r.type == :LBRACE
104
+ } - 1
105
+
106
+ resource_type_token = stripped_tokens[res_type_idx]
107
+ if resource_type_token.value == "file"
49
108
  resource_tokens.each_index do |resource_token_idx|
50
109
  attr_token = resource_tokens[resource_token_idx]
51
- if attr_token.first == :NAME and attr_token.last[:value] == 'mode'
110
+ if attr_token.type == :NAME and attr_token.value == 'mode'
52
111
  value_token = resource_tokens[resource_token_idx + 2]
53
- if value_token.last[:value] !~ /\d{4}/ and value_token.first != :VARIABLE and value_token.last[:value] !~ /^([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*$/
54
- notify :warning, :message => "mode should be represented as a 4 digit octal value or symbolic file mode", :linenumber => value_token.last[:line]
55
- end
112
+
113
+ break if value_token.value =~ /\d{4}/
114
+ break if value_token.type == :VARIABLE
115
+ break if value_token.value =~ sym_mode
116
+
117
+ notify :warning, {
118
+ :message => msg,
119
+ :linenumber => value_token.line,
120
+ :column => value_token.column,
121
+ }
56
122
  end
57
123
  end
58
124
  end
59
125
  end
60
126
  end
61
127
 
128
+ # Public: Check the tokens of each File resource instance for an ensure
129
+ # parameter and record a warning if the value of that parameter looks like
130
+ # a symlink target (starts with a '/').
131
+ #
132
+ # Returns nothing.
62
133
  check 'ensure_not_symlink_target' do
63
134
  resource_indexes.each do |resource|
64
- resource_tokens = tokens[resource[:start]..resource[:end]]
65
- resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
66
- if resource_type_token.last[:value] == "file"
135
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
136
+ formatting_tokens.include? r.type
137
+ }
138
+
139
+ stripped_tokens = tokens[0..resource[:start]].reject { |r|
140
+ formatting_tokens.include? r.type
141
+ }
142
+
143
+ res_type_idx = stripped_tokens.rindex { |r|
144
+ r.type == :LBRACE
145
+ } - 1
146
+
147
+ resource_type_token = stripped_tokens[res_type_idx]
148
+ if resource_type_token.value == "file"
67
149
  resource_tokens.each_index do |resource_token_idx|
68
150
  attr_token = resource_tokens[resource_token_idx]
69
- if attr_token.first == :NAME and attr_token.last[:value] == 'ensure'
151
+ if attr_token.type == :NAME and attr_token.value == 'ensure'
70
152
  value_token = resource_tokens[resource_token_idx + 2]
71
- if value_token.last[:value].start_with? '/'
72
- notify :warning, :message => "symlink target specified in ensure attr", :linenumber => value_token.last[:line]
153
+ if value_token.value.start_with? '/'
154
+ notify :warning, {
155
+ :message => 'symlink target specified in ensure attr',
156
+ :linenumber => value_token.line,
157
+ :column => value_token.column,
158
+ }
73
159
  end
74
160
  end
75
161
  end