ruby-lint 0.0.1a
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.
- data/.gitignore +5 -0
- data/.rbenv-version +1 -0
- data/.yardopts +10 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/MANIFEST +79 -0
- data/README.md +48 -0
- data/Rakefile +14 -0
- data/bin/rlint +6 -0
- data/doc/.gitkeep +0 -0
- data/doc/build/.gitkeep +0 -0
- data/doc/css/.gitkeep +0 -0
- data/doc/css/common.css +68 -0
- data/lib/rlint/analyze/coding_style.rb +407 -0
- data/lib/rlint/analyze/definitions.rb +244 -0
- data/lib/rlint/analyze/method_validation.rb +104 -0
- data/lib/rlint/analyze/shadowing_variables.rb +37 -0
- data/lib/rlint/analyze/undefined_variables.rb +99 -0
- data/lib/rlint/analyze/unused_variables.rb +103 -0
- data/lib/rlint/callback.rb +67 -0
- data/lib/rlint/cli.rb +167 -0
- data/lib/rlint/constant_importer.rb +102 -0
- data/lib/rlint/definition.rb +230 -0
- data/lib/rlint/formatter/text.rb +54 -0
- data/lib/rlint/helper/definition_resolver.rb +143 -0
- data/lib/rlint/helper/scoping.rb +138 -0
- data/lib/rlint/iterator.rb +193 -0
- data/lib/rlint/options.rb +58 -0
- data/lib/rlint/parser.rb +1252 -0
- data/lib/rlint/parser_error.rb +42 -0
- data/lib/rlint/report.rb +98 -0
- data/lib/rlint/token/assignment_token.rb +46 -0
- data/lib/rlint/token/begin_rescue_token.rb +57 -0
- data/lib/rlint/token/block_token.rb +17 -0
- data/lib/rlint/token/case_token.rb +44 -0
- data/lib/rlint/token/class_token.rb +24 -0
- data/lib/rlint/token/method_definition_token.rb +64 -0
- data/lib/rlint/token/method_token.rb +58 -0
- data/lib/rlint/token/parameters_token.rb +99 -0
- data/lib/rlint/token/regexp_token.rb +15 -0
- data/lib/rlint/token/statement_token.rb +69 -0
- data/lib/rlint/token/token.rb +162 -0
- data/lib/rlint/token/variable_token.rb +18 -0
- data/lib/rlint/version.rb +3 -0
- data/lib/rlint.rb +36 -0
- data/ruby-lint.gemspec +23 -0
- data/spec/benchmarks/memory.rb +52 -0
- data/spec/benchmarks/parse_parser.rb +16 -0
- data/spec/helper.rb +4 -0
- data/spec/rlint/analyze/coding_style.rb +224 -0
- data/spec/rlint/analyze/definitions/classes.rb +114 -0
- data/spec/rlint/analyze/definitions/methods.rb +91 -0
- data/spec/rlint/analyze/definitions/modules.rb +207 -0
- data/spec/rlint/analyze/definitions/variables.rb +103 -0
- data/spec/rlint/analyze/method_validation.rb +177 -0
- data/spec/rlint/analyze/shadowing_variables.rb +30 -0
- data/spec/rlint/analyze/undefined_variables.rb +230 -0
- data/spec/rlint/analyze/unused_variables.rb +225 -0
- data/spec/rlint/callback.rb +28 -0
- data/spec/rlint/constant_importer.rb +27 -0
- data/spec/rlint/definition.rb +96 -0
- data/spec/rlint/formatter/text.rb +21 -0
- data/spec/rlint/iterator.rb +452 -0
- data/spec/rlint/parser/arrays.rb +147 -0
- data/spec/rlint/parser/classes.rb +152 -0
- data/spec/rlint/parser/errors.rb +19 -0
- data/spec/rlint/parser/hashes.rb +136 -0
- data/spec/rlint/parser/methods.rb +249 -0
- data/spec/rlint/parser/modules.rb +49 -0
- data/spec/rlint/parser/objects.rb +39 -0
- data/spec/rlint/parser/operators.rb +75 -0
- data/spec/rlint/parser/procs.rb +113 -0
- data/spec/rlint/parser/ranges.rb +49 -0
- data/spec/rlint/parser/regexp.rb +31 -0
- data/spec/rlint/parser/scalars.rb +93 -0
- data/spec/rlint/parser/statements.rb +550 -0
- data/spec/rlint/parser/variables.rb +181 -0
- data/spec/rlint/report.rb +30 -0
- data/task/test.rake +6 -0
- metadata +188 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
module Rlint
|
2
|
+
##
|
3
|
+
# {Rlint::Options} is a class that can be used to configure various parts of
|
4
|
+
# Rlint such as what formatter to use, the reporting levels, etc.
|
5
|
+
#
|
6
|
+
class Options
|
7
|
+
##
|
8
|
+
# Array containing the analyzer classes that are always enabled. The order
|
9
|
+
# of these classes is preserved.
|
10
|
+
#
|
11
|
+
# @return [Array]
|
12
|
+
#
|
13
|
+
REQUIRED_ANALYZERS = [Analyze::Definitions]
|
14
|
+
|
15
|
+
##
|
16
|
+
# The reporting formatter to use, set to {Rlint::Formatter::Text} by
|
17
|
+
# default.
|
18
|
+
#
|
19
|
+
# @return [Rlint::Formatter]
|
20
|
+
#
|
21
|
+
attr_accessor :formatter
|
22
|
+
|
23
|
+
##
|
24
|
+
# The enabled reporting levels. See {Rlint::Report#levels} and
|
25
|
+
# {Rlint::Report#initialize} for more information.
|
26
|
+
#
|
27
|
+
# @return [Array]
|
28
|
+
#
|
29
|
+
attr_accessor :levels
|
30
|
+
|
31
|
+
##
|
32
|
+
# Array of classes to use for analyzing code. By default all the classes
|
33
|
+
# defined under {Rlint::Analyze} are used.
|
34
|
+
#
|
35
|
+
# @return [Array]
|
36
|
+
#
|
37
|
+
attr_accessor :analyzers
|
38
|
+
|
39
|
+
##
|
40
|
+
# Sets the default values for various options.
|
41
|
+
#
|
42
|
+
def initialize
|
43
|
+
@formatter = Formatter::Text
|
44
|
+
@levels = Report::DEFAULT_LEVELS
|
45
|
+
@analyzers = REQUIRED_ANALYZERS.dup
|
46
|
+
|
47
|
+
Analyze.constants.each do |c|
|
48
|
+
const = Analyze.const_get(c)
|
49
|
+
|
50
|
+
@analyzers << const unless @analyzers.include?(const)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end # Options
|
54
|
+
|
55
|
+
@options = Options.new
|
56
|
+
|
57
|
+
class << self; attr_reader :options; end
|
58
|
+
end # Rlint
|
data/lib/rlint/parser.rb
ADDED
@@ -0,0 +1,1252 @@
|
|
1
|
+
module Rlint
|
2
|
+
##
|
3
|
+
# {Rlint::Parser} uses Ripper to parse Ruby source code and turn it into an
|
4
|
+
# AST. Instead of returning arrays (the Ripper default) this class uses the
|
5
|
+
# various token classes such as {Rlint::Token::Token} and
|
6
|
+
# {Rlint::Token::VariableToken}. It also takes care of a few more things such
|
7
|
+
# as saving the associated line of code and setting method visibility.
|
8
|
+
#
|
9
|
+
# Parsing Ruby code requires two steps:
|
10
|
+
#
|
11
|
+
# 1. Create a new instance of this class and pass a string containing source
|
12
|
+
# code to the constructor method.
|
13
|
+
# 2. Call the method {Rlint::Parser#parse} and do something with the returned
|
14
|
+
# AST.
|
15
|
+
#
|
16
|
+
# For example, to parse a simple "Hello World" example you'd use this parser
|
17
|
+
# as following:
|
18
|
+
#
|
19
|
+
# require 'pp'
|
20
|
+
#
|
21
|
+
# parser = Rlint::Parser.new('puts "Hello, world!"')
|
22
|
+
#
|
23
|
+
# pp parser.parse
|
24
|
+
#
|
25
|
+
# This outputs the following AST:
|
26
|
+
#
|
27
|
+
# [#<Rlint::Token::MethodToken:0x000000012f04d0
|
28
|
+
# @code="puts \"Hello, world!\"",
|
29
|
+
# @column=0,
|
30
|
+
# @event=:method,
|
31
|
+
# @line=1,
|
32
|
+
# @name="puts",
|
33
|
+
# @parameters=
|
34
|
+
# [#<Rlint::Token::Token:0x000000012e9fb8
|
35
|
+
# @code="puts \"Hello, world!\"",
|
36
|
+
# @column=6,
|
37
|
+
# @event=:string,
|
38
|
+
# @line=1,
|
39
|
+
# @name="Hello, world!",
|
40
|
+
# @type=:string,
|
41
|
+
# @value="Hello, world!">],
|
42
|
+
# @type=:method>]
|
43
|
+
#
|
44
|
+
class Parser < Ripper::SexpBuilderPP
|
45
|
+
##
|
46
|
+
# Array containing all the event names of which the methods should simply
|
47
|
+
# returned the passed argument.
|
48
|
+
#
|
49
|
+
# @return [Array]
|
50
|
+
#
|
51
|
+
RETURN_FIRST_ARG_EVENTS = [
|
52
|
+
:program,
|
53
|
+
:var_field,
|
54
|
+
:args_add_block,
|
55
|
+
:assoclist_from_args,
|
56
|
+
:symbol_literal,
|
57
|
+
:begin,
|
58
|
+
:mrhs_new_from_args,
|
59
|
+
:blockarg,
|
60
|
+
:rest_param,
|
61
|
+
:arg_paren,
|
62
|
+
:block_var,
|
63
|
+
:const_ref,
|
64
|
+
:top_const_ref
|
65
|
+
]
|
66
|
+
|
67
|
+
##
|
68
|
+
# Array of events of which the callback method should simply return nil.
|
69
|
+
#
|
70
|
+
# @return [Array]
|
71
|
+
#
|
72
|
+
RETURN_NIL_EVENTS = [:void_stmt]
|
73
|
+
|
74
|
+
##
|
75
|
+
# Array of event names that should return an instance of
|
76
|
+
# {Rlint::Token::MethodToken}.
|
77
|
+
#
|
78
|
+
# @return [Array]
|
79
|
+
#
|
80
|
+
RETURN_METHOD_EVENTS = [:fcall, :vcall]
|
81
|
+
|
82
|
+
##
|
83
|
+
# Hash containing the names of various event callbacks that should return
|
84
|
+
# a token class containing details about a single line statement.
|
85
|
+
#
|
86
|
+
# @return [Hash]
|
87
|
+
#
|
88
|
+
MOD_STATEMENT_EVENTS = {
|
89
|
+
:while_mod => :while,
|
90
|
+
:if_mod => :if,
|
91
|
+
:unless_mod => :unless,
|
92
|
+
:until_mod => :until
|
93
|
+
}
|
94
|
+
|
95
|
+
##
|
96
|
+
# Array containing the three method calls that set the visibility of a
|
97
|
+
# method.
|
98
|
+
#
|
99
|
+
# @return [Array]
|
100
|
+
#
|
101
|
+
METHOD_VISIBILITY = ['public', 'protected', 'private']
|
102
|
+
|
103
|
+
##
|
104
|
+
# Symbol containing the default method visibility.
|
105
|
+
#
|
106
|
+
# @return [Symbol]
|
107
|
+
#
|
108
|
+
DEFAULT_VISIBILITY = :public
|
109
|
+
|
110
|
+
# Return an Rlint::Token::Token instance for each scanner event instead of
|
111
|
+
# an array with multiple indexes.
|
112
|
+
SCANNER_EVENTS.each do |event|
|
113
|
+
define_method("on_#{event}") do |token|
|
114
|
+
return Token::Token.new(
|
115
|
+
:name => token,
|
116
|
+
:type => event,
|
117
|
+
:value => token,
|
118
|
+
:line => lineno,
|
119
|
+
:column => column,
|
120
|
+
:code => code(lineno)
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
RETURN_FIRST_ARG_EVENTS.each do |event|
|
126
|
+
define_method("on_#{event}") { |*args| return args[0] }
|
127
|
+
end
|
128
|
+
|
129
|
+
RETURN_NIL_EVENTS.each do |event|
|
130
|
+
define_method("on_#{event}") { |*args| return nil }
|
131
|
+
end
|
132
|
+
|
133
|
+
RETURN_METHOD_EVENTS.each do |event|
|
134
|
+
define_method("on_#{event}") do |token|
|
135
|
+
if METHOD_VISIBILITY.include?(token.name)
|
136
|
+
@visibility = token.name.to_sym
|
137
|
+
|
138
|
+
return nil
|
139
|
+
end
|
140
|
+
|
141
|
+
return Token::MethodToken.new(
|
142
|
+
:name => token.name,
|
143
|
+
:line => token.line,
|
144
|
+
:column => token.column,
|
145
|
+
:value => token.name,
|
146
|
+
:code => code(token.line)
|
147
|
+
)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
MOD_STATEMENT_EVENTS.each do |ripper_event, rlint_event|
|
152
|
+
define_method("on_#{ripper_event}") do |statement, value|
|
153
|
+
value = [value] unless value.is_a?(Array)
|
154
|
+
|
155
|
+
return Token::StatementToken.new(
|
156
|
+
:type => rlint_event,
|
157
|
+
:statement => statement,
|
158
|
+
:value => value,
|
159
|
+
:line => lineno,
|
160
|
+
:column => column,
|
161
|
+
:code => code(lineno)
|
162
|
+
)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Creates a new instance of the parser and pre-defines various instance
|
168
|
+
# variables.
|
169
|
+
#
|
170
|
+
# @see Ripper::SexpBuilderPP#initialize
|
171
|
+
#
|
172
|
+
def initialize(code, file = '(rlint)', line = 1)
|
173
|
+
super
|
174
|
+
|
175
|
+
@file = file
|
176
|
+
@visibility = DEFAULT_VISIBILITY
|
177
|
+
@lines = []
|
178
|
+
|
179
|
+
code.each_line do |code_line|
|
180
|
+
@lines << code_line.chomp
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# Called when a parser error was encountered.
|
186
|
+
#
|
187
|
+
# @param [String] message The error message.
|
188
|
+
# @raise [Rlint::ParserError]
|
189
|
+
#
|
190
|
+
def on_parse_error(message)
|
191
|
+
raise ParserError.new(message, lineno, column, @file)
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Called when a string literal was found.
|
196
|
+
#
|
197
|
+
# @param [Array] token Array containing details about the string.
|
198
|
+
# @return [Rlint::Token::Token]
|
199
|
+
#
|
200
|
+
def on_string_literal(token)
|
201
|
+
if token and token[1]
|
202
|
+
return token[1]
|
203
|
+
else
|
204
|
+
return Token::Token.new(
|
205
|
+
:name => '',
|
206
|
+
:value => '',
|
207
|
+
:line => lineno,
|
208
|
+
:column => column,
|
209
|
+
:type => :string
|
210
|
+
)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# Called when a symbol is found.
|
216
|
+
#
|
217
|
+
# @param [Rlint::Token::Token] token The symbol token.
|
218
|
+
# @return [Rlint::Token::Token]
|
219
|
+
#
|
220
|
+
def on_symbol(token)
|
221
|
+
token.type = :symbol
|
222
|
+
|
223
|
+
return token
|
224
|
+
end
|
225
|
+
|
226
|
+
##
|
227
|
+
# Called when a symbol using quotes was found.
|
228
|
+
#
|
229
|
+
# @see Rlint::Parser#on_symbol
|
230
|
+
#
|
231
|
+
def on_dyna_symbol(token)
|
232
|
+
return on_symbol(token[0])
|
233
|
+
end
|
234
|
+
|
235
|
+
##
|
236
|
+
# Called when an array is found.
|
237
|
+
#
|
238
|
+
# @param [Array] values The values of the array.
|
239
|
+
# @return [Rlint::Token::Token]
|
240
|
+
#
|
241
|
+
def on_array(values)
|
242
|
+
values ||= []
|
243
|
+
|
244
|
+
return Token::Token.new(
|
245
|
+
:type => :array,
|
246
|
+
:value => values.map { |v| v.is_a?(Array) ? v[0] : v },
|
247
|
+
:line => lineno,
|
248
|
+
:column => column,
|
249
|
+
:code => code(lineno)
|
250
|
+
)
|
251
|
+
end
|
252
|
+
|
253
|
+
##
|
254
|
+
# Called when a reference to a particular array index is found.
|
255
|
+
#
|
256
|
+
# @param [Rlint::Token::Token] array The array that was referenced.
|
257
|
+
# @param [Rlint::Token::Token] index The index that was referenced.
|
258
|
+
# @return [Rlint::Token::Token]
|
259
|
+
#
|
260
|
+
def on_aref(array, index)
|
261
|
+
array.key = index
|
262
|
+
|
263
|
+
return array
|
264
|
+
end
|
265
|
+
|
266
|
+
##
|
267
|
+
# Called when a value is assigned to an array index.
|
268
|
+
#
|
269
|
+
# @param [Rlint::Token::Token] array The array that was referenced.
|
270
|
+
# @param [Rlint::Token::Token] index The index of the array that was
|
271
|
+
# referenced.
|
272
|
+
# @return [Rlint::Token::Token]
|
273
|
+
#
|
274
|
+
def on_aref_field(array, index)
|
275
|
+
array.key = index
|
276
|
+
|
277
|
+
return Token::AssignmentToken.new(
|
278
|
+
:receiver => array,
|
279
|
+
:line => lineno,
|
280
|
+
:column => column,
|
281
|
+
:type => array.type,
|
282
|
+
:code => code(lineno)
|
283
|
+
)
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Called when a Hash is found.
|
288
|
+
#
|
289
|
+
# @param [Array] pairs An array of key/value pairs of the hash.
|
290
|
+
# @return [Rlint::Token::Token]
|
291
|
+
#
|
292
|
+
def on_hash(pairs)
|
293
|
+
# column() is set to the column number of the very end of the hash.
|
294
|
+
col = pairs[0].column rescue column
|
295
|
+
|
296
|
+
return Token::Token.new(
|
297
|
+
:type => :hash,
|
298
|
+
:value => pairs,
|
299
|
+
:line => lineno,
|
300
|
+
:column => col,
|
301
|
+
:code => code(lineno)
|
302
|
+
)
|
303
|
+
end
|
304
|
+
|
305
|
+
##
|
306
|
+
# Called when a bare Hash is found. A bare Hash is a hash that's declared
|
307
|
+
# without the curly braces.
|
308
|
+
#
|
309
|
+
# @see Rlint::Parser#on_hash
|
310
|
+
#
|
311
|
+
def on_bare_assoc_hash(pairs)
|
312
|
+
return on_hash(pairs)
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# Called when a new key/value pair of a Hash is found.
|
317
|
+
#
|
318
|
+
# @param [Rlint::Token::Token] key The key of the pair.
|
319
|
+
# @param [Rlint::Token::Token] value The value of the pair.
|
320
|
+
# @return [Rlint::Token::Token]
|
321
|
+
#
|
322
|
+
def on_assoc_new(key, value)
|
323
|
+
key.name = key.value
|
324
|
+
key.value = value
|
325
|
+
|
326
|
+
return key
|
327
|
+
end
|
328
|
+
|
329
|
+
##
|
330
|
+
# Called when a block is created using curly braces.
|
331
|
+
#
|
332
|
+
# @param [Rlint::Token::ParametersToken] params The parameters of the
|
333
|
+
# block.
|
334
|
+
# @param [Array] body Array containing the tokens of the block.
|
335
|
+
# @return [Rlint::Token::BlockToken]
|
336
|
+
#
|
337
|
+
def on_brace_block(params, body)
|
338
|
+
return Token::BlockToken.new(
|
339
|
+
:parameters => params,
|
340
|
+
:value => body,
|
341
|
+
:line => lineno,
|
342
|
+
:column => column,
|
343
|
+
:type => :block,
|
344
|
+
:code => code(lineno)
|
345
|
+
)
|
346
|
+
end
|
347
|
+
|
348
|
+
##
|
349
|
+
# Called when a block is created using the do/end statements.
|
350
|
+
#
|
351
|
+
# @see Rlint::Parser#on_brace_block
|
352
|
+
#
|
353
|
+
def on_do_block(params, body)
|
354
|
+
return on_brace_block(params, body)
|
355
|
+
end
|
356
|
+
|
357
|
+
##
|
358
|
+
# Called when a lambda is found.
|
359
|
+
#
|
360
|
+
# @see Rlint::Parser#on_brace_block
|
361
|
+
#
|
362
|
+
def on_lambda(params, body)
|
363
|
+
token = on_brace_block(params, body)
|
364
|
+
token.type = :lambda
|
365
|
+
|
366
|
+
return token
|
367
|
+
end
|
368
|
+
|
369
|
+
##
|
370
|
+
# Called when a Range is found.
|
371
|
+
#
|
372
|
+
# @param [Rlint::Token::Token] start The start value of the range.
|
373
|
+
# @param [Rlint::Token::Token] stop The end value of the range.
|
374
|
+
# @return [Rlint::Token::Token]
|
375
|
+
#
|
376
|
+
def on_dot2(start, stop)
|
377
|
+
return Token::Token.new(
|
378
|
+
:type => :range,
|
379
|
+
:line => start.line,
|
380
|
+
:column => start.line,
|
381
|
+
:value => [start, stop],
|
382
|
+
:code => code(start.line)
|
383
|
+
)
|
384
|
+
end
|
385
|
+
|
386
|
+
##
|
387
|
+
# Called when a regular expression is found.
|
388
|
+
#
|
389
|
+
# @param [Array] regexp The regular expression's value.
|
390
|
+
# @param [Rlint::Token::Token] modes The modes of the regular expression.
|
391
|
+
# @return [Rlint::Token::RegexpToken]
|
392
|
+
#
|
393
|
+
def on_regexp_literal(regexp, modes)
|
394
|
+
regexp = regexp[0]
|
395
|
+
modes_array = []
|
396
|
+
|
397
|
+
if modes
|
398
|
+
modes_array = modes.value.split('').select { |c| c =~ /\w/ }
|
399
|
+
end
|
400
|
+
|
401
|
+
return Token::RegexpToken.new(
|
402
|
+
:type => :regexp,
|
403
|
+
:value => regexp.value,
|
404
|
+
:line => regexp.line,
|
405
|
+
:column => regexp.column,
|
406
|
+
:modes => modes_array,
|
407
|
+
:code => code(lineno)
|
408
|
+
)
|
409
|
+
end
|
410
|
+
|
411
|
+
##
|
412
|
+
# Called when a value is assigned to a variable.
|
413
|
+
#
|
414
|
+
# @param [Rlint::Token::Token] variable The variable that is assigned.
|
415
|
+
# @param [Rlint::Token::Token] value The value to assign.
|
416
|
+
# @return [Rlint::Token::VariableToken]
|
417
|
+
#
|
418
|
+
def on_assign(variable, value)
|
419
|
+
if variable.class == Rlint::Token::AssignmentToken
|
420
|
+
variable.value = value
|
421
|
+
|
422
|
+
return variable
|
423
|
+
end
|
424
|
+
|
425
|
+
if variable.is_a?(Array)
|
426
|
+
line = variable[-1].line
|
427
|
+
col = variable[-1].column
|
428
|
+
type = variable[-1].type
|
429
|
+
name = variable
|
430
|
+
else
|
431
|
+
line = variable.line
|
432
|
+
col = variable.column
|
433
|
+
type = variable.type
|
434
|
+
name = variable.name
|
435
|
+
end
|
436
|
+
|
437
|
+
return Token::AssignmentToken.new(
|
438
|
+
:line => line,
|
439
|
+
:column => col,
|
440
|
+
:name => name,
|
441
|
+
:type => type,
|
442
|
+
:value => value,
|
443
|
+
:code => code(line)
|
444
|
+
)
|
445
|
+
end
|
446
|
+
|
447
|
+
##
|
448
|
+
# Called when a set of values is assigned to multiple variables.
|
449
|
+
#
|
450
|
+
# @param [Array] variables The variables that are being assigned values.
|
451
|
+
# @param [Array] values The values to assign.
|
452
|
+
# @return [Rlint::Token::AssignmentToken]
|
453
|
+
#
|
454
|
+
def on_massign(variables, values)
|
455
|
+
return Token::AssignmentToken.new(
|
456
|
+
:line => variables[0].line,
|
457
|
+
:column => variables[0].column,
|
458
|
+
:code => code(variables[0].line),
|
459
|
+
:type => :mass_assignment,
|
460
|
+
:event => :mass_assignment,
|
461
|
+
:name => variables,
|
462
|
+
:value => values
|
463
|
+
)
|
464
|
+
end
|
465
|
+
|
466
|
+
##
|
467
|
+
# Called when a value is assigned to an object attribute.
|
468
|
+
#
|
469
|
+
# @param [Rlint::Token::VariableToken] receiver The receiver of the
|
470
|
+
# assignment.
|
471
|
+
# @param [Symbol] operator The operator that was used to separate the
|
472
|
+
# object and attribute.
|
473
|
+
# @param [Rlint::Token::Token] attribute The attribute to which the value
|
474
|
+
# is assigned.
|
475
|
+
# @return [Rlint::Token::VariableToken]
|
476
|
+
#
|
477
|
+
def on_field(receiver, operator, attribute)
|
478
|
+
return Token::AssignmentToken.new(
|
479
|
+
:name => attribute.value,
|
480
|
+
:line => attribute.line,
|
481
|
+
:column => attribute.column,
|
482
|
+
:type => attribute.type,
|
483
|
+
:receiver => receiver,
|
484
|
+
:operator => operator,
|
485
|
+
:code => code(attribute.line)
|
486
|
+
)
|
487
|
+
end
|
488
|
+
|
489
|
+
##
|
490
|
+
# Called when a (binary) operator operation is performed.
|
491
|
+
#
|
492
|
+
# @param [Rlint::Token::Token] left The left hand side of the operator.
|
493
|
+
# @param [Symbol] op The operator that was used.
|
494
|
+
# @param [Rlint::Token::Token] right The right hand side of the operator.
|
495
|
+
# @return [Rlint::Token::Token]
|
496
|
+
#
|
497
|
+
def on_binary(left, op, right)
|
498
|
+
return Token::Token.new(
|
499
|
+
:type => :binary,
|
500
|
+
:value => [left, op, right],
|
501
|
+
:line => lineno,
|
502
|
+
:column => column,
|
503
|
+
:code => code(lineno)
|
504
|
+
)
|
505
|
+
end
|
506
|
+
|
507
|
+
##
|
508
|
+
# Called when an unary operator/operation is found.
|
509
|
+
#
|
510
|
+
# @param [Symbol] operator The unary operator.
|
511
|
+
# @param [Rlint::Token::Token] token The token after the unary operator.
|
512
|
+
# @return [Rlint::Token::Token]
|
513
|
+
#
|
514
|
+
def on_unary(operator, token)
|
515
|
+
return Token::Token.new(
|
516
|
+
:type => :unary,
|
517
|
+
:value => [operator, token],
|
518
|
+
:line => lineno,
|
519
|
+
:column => column,
|
520
|
+
:code => code(lineno)
|
521
|
+
)
|
522
|
+
end
|
523
|
+
|
524
|
+
##
|
525
|
+
# Called when a set of parenthesis is found.
|
526
|
+
#
|
527
|
+
# @param [Array] value The data inside the parenthesis.
|
528
|
+
# @return [Rlint::Token::Token]
|
529
|
+
#
|
530
|
+
def on_paren(value)
|
531
|
+
if value.is_a?(Array)
|
532
|
+
return value[0]
|
533
|
+
else
|
534
|
+
return value
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
##
|
539
|
+
# Called when a return statement is found.
|
540
|
+
#
|
541
|
+
# @param [Array] values The return values of the statement.
|
542
|
+
# @return [Rlint::Token::StatementToken]
|
543
|
+
#
|
544
|
+
def on_return(values)
|
545
|
+
source = code(lineno)
|
546
|
+
col = calculate_column(source, 'return')
|
547
|
+
|
548
|
+
return Token::StatementToken.new(
|
549
|
+
:type => :return,
|
550
|
+
:line => lineno,
|
551
|
+
:column => col,
|
552
|
+
:value => values,
|
553
|
+
:code => source
|
554
|
+
)
|
555
|
+
end
|
556
|
+
|
557
|
+
##
|
558
|
+
# Called when a while loop is found.
|
559
|
+
#
|
560
|
+
# @param [Rlint::Token::Token] statement The statement to evaluate.
|
561
|
+
# @param [Rlint::Token::Token] value The body of the while loop.
|
562
|
+
# @return [Rlint::Token::StatementToken]
|
563
|
+
#
|
564
|
+
def on_while(statement, value)
|
565
|
+
source = code(statement.line)
|
566
|
+
col = calculate_column(source, 'while')
|
567
|
+
|
568
|
+
return Token::StatementToken.new(
|
569
|
+
:type => :while,
|
570
|
+
:statement => statement,
|
571
|
+
:value => value,
|
572
|
+
:line => statement.line,
|
573
|
+
:column => col,
|
574
|
+
:code => source
|
575
|
+
)
|
576
|
+
end
|
577
|
+
|
578
|
+
##
|
579
|
+
# Called when a for loop is found.
|
580
|
+
#
|
581
|
+
# @param [Array] variables Array of variables to create for each iteration.
|
582
|
+
#
|
583
|
+
# pry_binding
|
584
|
+
# @param [Rlint::Token::Token] enumerable The enumerable to iterate.
|
585
|
+
# @param [Array] value The body of the for loop.
|
586
|
+
# @return [Rlint::Token::StatementToken]
|
587
|
+
#
|
588
|
+
def on_for(variables, enumerable, value)
|
589
|
+
source = code(variables[0].line)
|
590
|
+
col = calculate_column(source, 'for')
|
591
|
+
|
592
|
+
return Token::StatementToken.new(
|
593
|
+
:type => :for,
|
594
|
+
:statement => [variables, enumerable],
|
595
|
+
:value => value,
|
596
|
+
:column => col,
|
597
|
+
:line => variables[0].line,
|
598
|
+
:code => source
|
599
|
+
)
|
600
|
+
end
|
601
|
+
|
602
|
+
##
|
603
|
+
# Called when an if statement is found.
|
604
|
+
#
|
605
|
+
# @param [Rlint::Token::Token] statement The if statement to evaluate.
|
606
|
+
# @param [Array] value Array containing the tokens of the code that will
|
607
|
+
# be executed if the if statement evaluates to true.
|
608
|
+
# @param [Array] rest Array containing the tokens for the elsif and else
|
609
|
+
# statements (if any).
|
610
|
+
# @return [Rlint::Token::StatementToken]
|
611
|
+
#
|
612
|
+
def on_if(statement, value, rest)
|
613
|
+
source = code(statement.line)
|
614
|
+
col = calculate_column(source, 'if')
|
615
|
+
|
616
|
+
else_statement = nil
|
617
|
+
elsif_statements = []
|
618
|
+
|
619
|
+
if rest and rest.respond_to?(:each)
|
620
|
+
rest.each do |token|
|
621
|
+
next if token.nil?
|
622
|
+
|
623
|
+
if token.type == :elsif
|
624
|
+
elsif_statements << token
|
625
|
+
else
|
626
|
+
else_statement = token
|
627
|
+
end
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
return Token::StatementToken.new(
|
632
|
+
:type => :if,
|
633
|
+
:statement => statement,
|
634
|
+
:value => value,
|
635
|
+
:line => statement.line,
|
636
|
+
:column => col,
|
637
|
+
:else => else_statement,
|
638
|
+
:elsif => elsif_statements.reverse,
|
639
|
+
:code => source
|
640
|
+
)
|
641
|
+
end
|
642
|
+
|
643
|
+
##
|
644
|
+
# Called whne a tenary operator is found.
|
645
|
+
#
|
646
|
+
# @see Rlint::Parser#on_if
|
647
|
+
#
|
648
|
+
def on_ifop(statement, value, else_statement)
|
649
|
+
else_statement = Token::StatementToken.new(
|
650
|
+
:type => :else,
|
651
|
+
:value => [else_statement],
|
652
|
+
:line => else_statement.line,
|
653
|
+
:column => else_statement.column,
|
654
|
+
:code => code(else_statement.line)
|
655
|
+
)
|
656
|
+
|
657
|
+
return Token::StatementToken.new(
|
658
|
+
:type => :if,
|
659
|
+
:statement => statement,
|
660
|
+
:value => [value],
|
661
|
+
:line => statement.line,
|
662
|
+
:column => statement.column,
|
663
|
+
:code => code(statement.line),
|
664
|
+
:else => else_statement
|
665
|
+
)
|
666
|
+
end
|
667
|
+
|
668
|
+
##
|
669
|
+
# Called when an else statement is found.
|
670
|
+
#
|
671
|
+
# @param [Array] value The value of the statement.
|
672
|
+
# @return [Rlint::Token::StatementToken]
|
673
|
+
#
|
674
|
+
def on_else(value)
|
675
|
+
return Token::StatementToken.new(
|
676
|
+
:type => :else,
|
677
|
+
:value => value,
|
678
|
+
:column => column,
|
679
|
+
:line => lineno,
|
680
|
+
:code => code(lineno)
|
681
|
+
)
|
682
|
+
end
|
683
|
+
|
684
|
+
##
|
685
|
+
# Called when an elsif statement is found.
|
686
|
+
#
|
687
|
+
# @param [Rlint::Token::Token] statement The statement to evaluate.
|
688
|
+
# @param [Array] value The value of the elsif statement.
|
689
|
+
# @param [Array|Rlint::Token::Token] list A list of else and elsif
|
690
|
+
# statements.
|
691
|
+
# @return [Array]
|
692
|
+
#
|
693
|
+
def on_elsif(statement, value, list)
|
694
|
+
source = code(statement.line)
|
695
|
+
col = calculate_column(source, 'elsif')
|
696
|
+
|
697
|
+
token = Token::StatementToken.new(
|
698
|
+
:type => :elsif,
|
699
|
+
:statement => statement,
|
700
|
+
:value => value,
|
701
|
+
:line => statement.line,
|
702
|
+
:column => col,
|
703
|
+
:code => source
|
704
|
+
)
|
705
|
+
|
706
|
+
unless list.is_a?(Array)
|
707
|
+
list = [list]
|
708
|
+
end
|
709
|
+
|
710
|
+
list << token
|
711
|
+
end
|
712
|
+
|
713
|
+
##
|
714
|
+
# Called when the body of a block of Ruby code is found (e.g. a method
|
715
|
+
# definition or a begin/rescue block).
|
716
|
+
#
|
717
|
+
# @param [Array] value Array containing the tokens of the body/statement.
|
718
|
+
# @param [Array] rescues An array of rescue statements.
|
719
|
+
# @param [Rlint::Token::StatementToken] else_statement The else statement
|
720
|
+
# of the block.
|
721
|
+
# @param [Rlint::Token::StatementToken] ensure_statement The ensure
|
722
|
+
# statement of the block.
|
723
|
+
# @return [Rlint::Token::BeginRescueToken]
|
724
|
+
#
|
725
|
+
def on_bodystmt(value, rescues, else_statement, ensure_statement)
|
726
|
+
if rescues.nil? and else_statement.nil? and ensure_statement.nil?
|
727
|
+
return value
|
728
|
+
end
|
729
|
+
|
730
|
+
return Token::BeginRescueToken.new(
|
731
|
+
:type => :begin,
|
732
|
+
:value => value,
|
733
|
+
:rescue => (rescues || []).reverse.select { |t| !t.nil? },
|
734
|
+
:ensure => ensure_statement,
|
735
|
+
:else => else_statement,
|
736
|
+
:line => lineno,
|
737
|
+
:column => column,
|
738
|
+
:code => code(lineno)
|
739
|
+
)
|
740
|
+
end
|
741
|
+
|
742
|
+
##
|
743
|
+
# Called when a rescue statement is found.
|
744
|
+
#
|
745
|
+
# @param [Array] exceptions An array of exceptions to catch.
|
746
|
+
# @param [Rlint::Token::Token] variable The variable in which to store
|
747
|
+
# the exception details.
|
748
|
+
# @param [Array] value The value of the rescue statement.
|
749
|
+
# @param [Array|Rlint::Token::Token] list A set of all the rescue tokens.
|
750
|
+
# @return [Rlint::Token::StatementToken]
|
751
|
+
#
|
752
|
+
def on_rescue(exceptions, variable, value, list)
|
753
|
+
source = code(lineno)
|
754
|
+
col = calculate_column(source, 'rescue')
|
755
|
+
|
756
|
+
token = Token::StatementToken.new(
|
757
|
+
:type => :rescue,
|
758
|
+
:statement => [exceptions, variable],
|
759
|
+
:line => lineno,
|
760
|
+
:column => col,
|
761
|
+
:value => value,
|
762
|
+
:code => source
|
763
|
+
)
|
764
|
+
|
765
|
+
unless list.is_a?(Array)
|
766
|
+
list = [list]
|
767
|
+
end
|
768
|
+
|
769
|
+
list << token
|
770
|
+
end
|
771
|
+
|
772
|
+
##
|
773
|
+
# Called when a single line rescue statement (in the form of `[VALUE]
|
774
|
+
# rescue [RESCUE VALUE]`) is found.
|
775
|
+
#
|
776
|
+
# @param [Rlint::Token::Token|Array] value The body of the begin/rescue
|
777
|
+
# statement.
|
778
|
+
# @param [Rlint::Token::Token] statement The statement to evaluate when the
|
779
|
+
# data in `value` raised an exception.
|
780
|
+
# @return [Rlint::Token::BeginRescueToken]
|
781
|
+
#
|
782
|
+
def on_rescue_mod(value, statement)
|
783
|
+
value = [value] unless value.is_a?(Array)
|
784
|
+
statement = [statement] unless statement.is_a?(Array)
|
785
|
+
|
786
|
+
return Token::BeginRescueToken.new(
|
787
|
+
:type => :rescue,
|
788
|
+
:rescue => statement,
|
789
|
+
:value => value,
|
790
|
+
:line => lineno,
|
791
|
+
:column => column,
|
792
|
+
:code => code(lineno)
|
793
|
+
)
|
794
|
+
end
|
795
|
+
|
796
|
+
##
|
797
|
+
# Called when an ensure statement is found.
|
798
|
+
#
|
799
|
+
# @param [Array] value The value of the statement.
|
800
|
+
# @return [Rlint::Token::StatementToken]
|
801
|
+
#
|
802
|
+
def on_ensure(value)
|
803
|
+
return Token::StatementToken.new(
|
804
|
+
:type => :ensure,
|
805
|
+
:value => value,
|
806
|
+
:line => lineno,
|
807
|
+
:column => column,
|
808
|
+
:code => code(lineno)
|
809
|
+
)
|
810
|
+
end
|
811
|
+
|
812
|
+
##
|
813
|
+
# Called for an entire case/when/else block.
|
814
|
+
#
|
815
|
+
# @param [Rlint::Token::Token] statement The statement of the `case`
|
816
|
+
# statement itself.
|
817
|
+
# @param [Array] list Array containing the various when statements and
|
818
|
+
# optionally an else statement.
|
819
|
+
# @return [Rlint::Token::CaseToken]
|
820
|
+
#
|
821
|
+
def on_case(statement, list)
|
822
|
+
when_statements = []
|
823
|
+
else_statement = nil
|
824
|
+
source = code(statement.line)
|
825
|
+
col = calculate_column(source, 'case')
|
826
|
+
|
827
|
+
if list and list.respond_to?(:each)
|
828
|
+
list.each do |token|
|
829
|
+
if token.type == :when
|
830
|
+
when_statements << token
|
831
|
+
else
|
832
|
+
else_statement = token
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
return Token::CaseToken.new(
|
838
|
+
:type => :case,
|
839
|
+
:statement => statement,
|
840
|
+
:else => else_statement,
|
841
|
+
:when => when_statements.reverse,
|
842
|
+
:line => statement.line,
|
843
|
+
:column => col,
|
844
|
+
:code => source
|
845
|
+
)
|
846
|
+
end
|
847
|
+
|
848
|
+
##
|
849
|
+
# Called when a `when` statement is found.
|
850
|
+
#
|
851
|
+
# @param [Array] statement Array of statements to evaluate.
|
852
|
+
# @param [Array] body Array containing the tokens of the statement's body.
|
853
|
+
# @param [Array] list The list of `when` tokens.
|
854
|
+
# @return [Array]
|
855
|
+
#
|
856
|
+
def on_when(statement, body, list)
|
857
|
+
source = code(statement[0].line)
|
858
|
+
col = calculate_column(source, 'when')
|
859
|
+
|
860
|
+
token = Token::StatementToken.new(
|
861
|
+
:type => :when,
|
862
|
+
:statement => statement,
|
863
|
+
:value => body,
|
864
|
+
:line => statement[0].line,
|
865
|
+
:column => col,
|
866
|
+
:code => source
|
867
|
+
)
|
868
|
+
|
869
|
+
unless list.is_a?(Array)
|
870
|
+
list = [list]
|
871
|
+
end
|
872
|
+
|
873
|
+
list << token
|
874
|
+
end
|
875
|
+
|
876
|
+
##
|
877
|
+
# Called when a unless statement is found.
|
878
|
+
#
|
879
|
+
# @param [Rlint::Token::Token] statement The statement to evaluate.
|
880
|
+
# @param [Array] body The body of the unless statement.
|
881
|
+
# @param [Rlint::Token::StatementToken] else_token An optional else
|
882
|
+
# statement.
|
883
|
+
# @return [Rlint::Token::StatementToken]
|
884
|
+
#
|
885
|
+
def on_unless(statement, body, else_token)
|
886
|
+
source = code(statement.line)
|
887
|
+
col = calculate_column(source, 'unless')
|
888
|
+
|
889
|
+
return Token::StatementToken.new(
|
890
|
+
:type => :unless,
|
891
|
+
:statement => statement,
|
892
|
+
:else => else_token,
|
893
|
+
:value => body,
|
894
|
+
:line => statement.line,
|
895
|
+
:column => col,
|
896
|
+
:code => source
|
897
|
+
)
|
898
|
+
end
|
899
|
+
|
900
|
+
##
|
901
|
+
# Called when an until statement is found.
|
902
|
+
#
|
903
|
+
# @see Rlint::Parser#on_unless
|
904
|
+
#
|
905
|
+
def on_until(statement, body)
|
906
|
+
source = code(statement.line)
|
907
|
+
col = calculate_column(source, 'until')
|
908
|
+
|
909
|
+
return Token::StatementToken.new(
|
910
|
+
:type => :until,
|
911
|
+
:statement => statement,
|
912
|
+
:value => body,
|
913
|
+
:line => statement.line,
|
914
|
+
:column => col,
|
915
|
+
:code => source
|
916
|
+
)
|
917
|
+
end
|
918
|
+
|
919
|
+
##
|
920
|
+
# Called when a variable is referenced.
|
921
|
+
#
|
922
|
+
# @param [Rlint::Token::Token] variable The variable that was referenced.
|
923
|
+
# @return [Rlint::Token::VariableToken]
|
924
|
+
#
|
925
|
+
def on_var_ref(variable)
|
926
|
+
return Token::VariableToken.new(
|
927
|
+
:line => variable.line,
|
928
|
+
:column => variable.column,
|
929
|
+
:name => variable.value,
|
930
|
+
:type => variable.type,
|
931
|
+
:code => code(variable.line)
|
932
|
+
)
|
933
|
+
end
|
934
|
+
|
935
|
+
##
|
936
|
+
# Called when a constant path reference is found.
|
937
|
+
#
|
938
|
+
# @param [Array] segments The path segments.
|
939
|
+
# @return [Array]
|
940
|
+
#
|
941
|
+
def on_const_path_ref(*segments)
|
942
|
+
return Token::VariableToken.new(
|
943
|
+
:name => segments.map { |t| t.name }.flatten,
|
944
|
+
:type => :constant_path,
|
945
|
+
:line => segments[0].line,
|
946
|
+
:column => segments[0].column,
|
947
|
+
:code => code(segments[-1].line)
|
948
|
+
)
|
949
|
+
end
|
950
|
+
|
951
|
+
##
|
952
|
+
# Called when a constant path is assigned.
|
953
|
+
#
|
954
|
+
# @see Rlint::Parser#on_const_path_ref
|
955
|
+
#
|
956
|
+
def on_const_path_field(*segments)
|
957
|
+
return on_const_path_ref(*segments)
|
958
|
+
end
|
959
|
+
|
960
|
+
##
|
961
|
+
# Called when a new method is defined.
|
962
|
+
#
|
963
|
+
# @param [Rlint::Token::Token] name Token containing details about the
|
964
|
+
# method name.
|
965
|
+
# @param [Rlint::Token::ParametersToken] params Token containing details
|
966
|
+
# about the method parameters.
|
967
|
+
# @param [Array] body Array containing the tokens of the method's body.
|
968
|
+
# @return [Rlint::Token::MethodDefinitionToken]
|
969
|
+
#
|
970
|
+
def on_def(name, params, body)
|
971
|
+
return Token::MethodDefinitionToken.new(
|
972
|
+
:name => name.value,
|
973
|
+
:line => name.line,
|
974
|
+
:column => name.column,
|
975
|
+
:parameters => params,
|
976
|
+
:visibility => @visibility,
|
977
|
+
:value => body.select { |t| !t.nil? },
|
978
|
+
:code => code(name.line)
|
979
|
+
)
|
980
|
+
end
|
981
|
+
|
982
|
+
##
|
983
|
+
# Called when a method is defined on a specific constant/location
|
984
|
+
# (e.g. `self`).
|
985
|
+
#
|
986
|
+
# @param [Rlint::Token::Token] receiver The object that the method was
|
987
|
+
# defined on.
|
988
|
+
# @param [Rlint::Token::Token] operator The operator that was used to
|
989
|
+
# separate the receiver and method name.
|
990
|
+
# @param [Rlint::Token::Token] name The name of the method.
|
991
|
+
# @param [Rlint::Token::ParametersToken] params The method parameters.
|
992
|
+
# @param [Array] body The body of the method.
|
993
|
+
# @return [Rlint::Token::MethodDefinitionToken]
|
994
|
+
#
|
995
|
+
def on_defs(receiver, operator, name, params, body)
|
996
|
+
token = on_def(name, params, body)
|
997
|
+
token.receiver = receiver
|
998
|
+
token.operator = operator
|
999
|
+
|
1000
|
+
return token
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
##
|
1004
|
+
# Called when a set of method parameters is found. The order of the `args`
|
1005
|
+
# parameter is the following:
|
1006
|
+
#
|
1007
|
+
# * 0: array of required parameters
|
1008
|
+
# * 1: array of optional parameters
|
1009
|
+
# * 2: the rest parameter (if any)
|
1010
|
+
# * 3: array of "more" parameters (parameters set after the rest parameter)
|
1011
|
+
# * 4: the block parameter (if any)
|
1012
|
+
#
|
1013
|
+
# @param [Array] args Array containing all the passed method parameters.
|
1014
|
+
# @return [Rlint::Token::ParametersToken]
|
1015
|
+
#
|
1016
|
+
def on_params(*args)
|
1017
|
+
# Convert all the arguments from regular Token instances to VariableToken
|
1018
|
+
# instances.
|
1019
|
+
args.each_with_index do |arg, index|
|
1020
|
+
# Required, optional and more parameters.
|
1021
|
+
if arg.is_a?(Array)
|
1022
|
+
args[index] = arg.map do |token|
|
1023
|
+
value = nil
|
1024
|
+
|
1025
|
+
if token.is_a?(Array)
|
1026
|
+
value = token[1]
|
1027
|
+
token = token[0]
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
Token::VariableToken.new(
|
1031
|
+
:name => token.value,
|
1032
|
+
:value => value,
|
1033
|
+
:line => token.line,
|
1034
|
+
:column => token.column,
|
1035
|
+
:type => token.type,
|
1036
|
+
:code => code(token.line)
|
1037
|
+
)
|
1038
|
+
end
|
1039
|
+
# Rest and block parameters.
|
1040
|
+
elsif !arg.nil?
|
1041
|
+
args[index] = Token::VariableToken.new(
|
1042
|
+
:name => arg.value,
|
1043
|
+
:line => arg.line,
|
1044
|
+
:column => arg.column,
|
1045
|
+
:type => arg.type,
|
1046
|
+
:code => code(arg.line)
|
1047
|
+
)
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
return Token::ParametersToken.new(
|
1052
|
+
:value => args[0],
|
1053
|
+
:optional => args[1],
|
1054
|
+
:rest => args[2],
|
1055
|
+
:more => args[3],
|
1056
|
+
:block => args[4]
|
1057
|
+
)
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
##
|
1061
|
+
# Called when a method call using parenthesis is found.
|
1062
|
+
#
|
1063
|
+
# @param [Rlint::Token::Token] name The name of the method that was called.
|
1064
|
+
# @param [Array] params The parameters of the method call.
|
1065
|
+
# @return [Rlint::Token::MethodToken]
|
1066
|
+
#
|
1067
|
+
def on_method_add_arg(name, params)
|
1068
|
+
if name.class == Rlint::Token::MethodToken
|
1069
|
+
name.parameters = params
|
1070
|
+
|
1071
|
+
return name
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
return Token::MethodToken.new(
|
1075
|
+
:name => name.value,
|
1076
|
+
:parameters => params,
|
1077
|
+
:line => name.line,
|
1078
|
+
:column => name.column,
|
1079
|
+
:code => code(name.line)
|
1080
|
+
)
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
##
|
1084
|
+
# Called when a block is passed to a method call.
|
1085
|
+
#
|
1086
|
+
# @param [Rlint::Token::MethodToken] method Token class for the method that
|
1087
|
+
# the block is passed to.
|
1088
|
+
# @param [Rlint::Token::BlockToken] block The block that was passed to the
|
1089
|
+
# method.
|
1090
|
+
# @return [Rlint::Token::MethodToken]
|
1091
|
+
#
|
1092
|
+
def on_method_add_block(method, block)
|
1093
|
+
method.block = block
|
1094
|
+
|
1095
|
+
return method
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
##
|
1099
|
+
# Called when a class declaration is found.
|
1100
|
+
#
|
1101
|
+
# @param [Array|Rlint::Token::Token] name The name of the class.
|
1102
|
+
# @param [Array|NilClass] parent The name of the parent class.
|
1103
|
+
# @param [Array] body The body of the class.
|
1104
|
+
# @return [Rlint::Token::ClassToken]
|
1105
|
+
#
|
1106
|
+
def on_class(name, parent, body)
|
1107
|
+
name_segments = name.name.is_a?(Array) ? name.name : [name.name]
|
1108
|
+
parent_segments = []
|
1109
|
+
|
1110
|
+
if parent
|
1111
|
+
parent_segments = parent.name.is_a?(Array) ? parent.name : [parent.name]
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
body = body.is_a?(Array) ? body.flatten.select { |t| !t.nil? } : []
|
1115
|
+
|
1116
|
+
@visibility = DEFAULT_VISIBILITY
|
1117
|
+
|
1118
|
+
return Token::ClassToken.new(
|
1119
|
+
:name => name_segments,
|
1120
|
+
:parent => parent_segments,
|
1121
|
+
:type => :class,
|
1122
|
+
:value => body,
|
1123
|
+
:line => name.line,
|
1124
|
+
:column => name.column,
|
1125
|
+
:code => name.code
|
1126
|
+
)
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
##
|
1130
|
+
# Called when a set of class methods are added using a `class << self`
|
1131
|
+
# block.
|
1132
|
+
#
|
1133
|
+
# @param [Rlint::Token::VariableToken] receiver The receiver for all the
|
1134
|
+
# methods.
|
1135
|
+
# @param [Array] value The body of the block.
|
1136
|
+
# @return [Array]
|
1137
|
+
#
|
1138
|
+
def on_sclass(receiver, value)
|
1139
|
+
value.each_with_index do |token, index|
|
1140
|
+
if token.respond_to?(:receiver)
|
1141
|
+
token.receiver = receiver
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
value[index] = token
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
return value
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
##
|
1151
|
+
# Called when a module definition is found.
|
1152
|
+
#
|
1153
|
+
# @param [Rlint::Token::Token|Array] name The name of the module, either a
|
1154
|
+
# single token class or an array of token classes.
|
1155
|
+
# @param [Array|NilClass] body The body of the module.
|
1156
|
+
# @return [Rlint::Token::Token]
|
1157
|
+
#
|
1158
|
+
def on_module(name, body)
|
1159
|
+
name_segments = name.name.is_a?(Array) ? name.name : [name.name]
|
1160
|
+
|
1161
|
+
return Token::Token.new(
|
1162
|
+
:type => :module,
|
1163
|
+
:name => name_segments,
|
1164
|
+
:value => body,
|
1165
|
+
:line => name.line,
|
1166
|
+
:column => name.column,
|
1167
|
+
:code => name.code
|
1168
|
+
)
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
##
|
1172
|
+
# Called when a method call without parenthesis was found.
|
1173
|
+
#
|
1174
|
+
# @see Rlint::Parser#on_method_add_arg
|
1175
|
+
#
|
1176
|
+
def on_command(name, params)
|
1177
|
+
return on_method_add_arg(name, params)
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
##
|
1181
|
+
# Called when a method was invoked on an object.
|
1182
|
+
#
|
1183
|
+
# @param [Rlint::Token::Token] receiver The object that the method was
|
1184
|
+
# invoked on.
|
1185
|
+
# @param [Symbol] operator The operator that was used to separate the
|
1186
|
+
# receiver and method name.
|
1187
|
+
# @param [Rlint::Token::Token] name Token containing details about the
|
1188
|
+
# method name.
|
1189
|
+
# @return [Rlint::Token::MethodToken]
|
1190
|
+
#
|
1191
|
+
def on_call(receiver, operator, name)
|
1192
|
+
return Token::MethodToken.new(
|
1193
|
+
:name => name.value,
|
1194
|
+
:line => name.line,
|
1195
|
+
:column => name.column,
|
1196
|
+
:receiver => receiver,
|
1197
|
+
:operator => operator,
|
1198
|
+
:code => code(name.line)
|
1199
|
+
)
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
##
|
1203
|
+
# Called when a method was invoked on an object without using parenthesis.
|
1204
|
+
#
|
1205
|
+
# @see Rlint::Parser#on_call
|
1206
|
+
# @param [Array] params The parameters passed to the method.
|
1207
|
+
# @return [Rlint::Token::MethodToken]
|
1208
|
+
#
|
1209
|
+
def on_command_call(receiver, operator, name, params)
|
1210
|
+
return Token::MethodToken.new(
|
1211
|
+
:name => name.value,
|
1212
|
+
:line => name.line,
|
1213
|
+
:column => name.column,
|
1214
|
+
:receiver => receiver,
|
1215
|
+
:operator => operator,
|
1216
|
+
:parameters => params,
|
1217
|
+
:code => code(name.line)
|
1218
|
+
)
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
private
|
1222
|
+
|
1223
|
+
##
|
1224
|
+
# Returns a string containing the code for the specified line number.
|
1225
|
+
#
|
1226
|
+
# @param [Fixnum|Bignum] line The line number.
|
1227
|
+
# @return [String]
|
1228
|
+
#
|
1229
|
+
def code(line)
|
1230
|
+
return @lines[line - 1]
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
##
|
1234
|
+
# Calculates the column position based on a given line and a stop string.
|
1235
|
+
#
|
1236
|
+
# @param [String] line The line of code to use for calculating the column
|
1237
|
+
# number.
|
1238
|
+
# @param [String] stop The string that indicates the start of the token.
|
1239
|
+
# @return [Fixnum]
|
1240
|
+
#
|
1241
|
+
def calculate_column(line, stop)
|
1242
|
+
matches = line.match(/^(.+)#{stop}/)
|
1243
|
+
number = 0
|
1244
|
+
|
1245
|
+
if matches and matches[1]
|
1246
|
+
number = matches[1].to_i
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
return number
|
1250
|
+
end
|
1251
|
+
end # Parser
|
1252
|
+
end # Rlint
|