ruby-lint 0.0.2 → 0.0.3

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.
Files changed (321) hide show
  1. data.tar.gz.asc +17 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +25 -0
  4. data/.yardopts +4 -0
  5. data/Gemfile +1 -1
  6. data/LICENSE +1 -1
  7. data/MANIFEST +238 -49
  8. data/README.md +84 -131
  9. data/Rakefile +6 -0
  10. data/bin/ruby-lint +2 -2
  11. data/checksum/.gitkeep +0 -0
  12. data/doc/DCO.md +26 -0
  13. data/doc/architecture.md +63 -0
  14. data/doc/code_analysis.md +90 -0
  15. data/doc/configuration.md +86 -0
  16. data/doc/contributing.md +16 -0
  17. data/doc/graphviz/flow.dot +7 -0
  18. data/doc/images/.gitkeep +0 -0
  19. data/doc/images/flow.png +0 -0
  20. data/lib/ruby-lint.rb +35 -35
  21. data/lib/ruby-lint/analyze/argument_amount.rb +73 -0
  22. data/lib/ruby-lint/analyze/shadowing_variables.rb +19 -24
  23. data/lib/ruby-lint/analyze/undefined_methods.rb +68 -0
  24. data/lib/ruby-lint/analyze/undefined_variables.rb +42 -69
  25. data/lib/ruby-lint/analyze/unused_variables.rb +23 -78
  26. data/lib/ruby-lint/base.rb +85 -0
  27. data/lib/ruby-lint/cli.rb +23 -167
  28. data/lib/ruby-lint/cli/analyze.rb +99 -0
  29. data/lib/ruby-lint/cli/ast.rb +35 -0
  30. data/lib/ruby-lint/cli/base.rb +120 -0
  31. data/lib/ruby-lint/configuration.rb +112 -0
  32. data/lib/ruby-lint/constant_loader.rb +92 -0
  33. data/lib/ruby-lint/definition/ruby_method.rb +248 -0
  34. data/lib/ruby-lint/definition/ruby_object.rb +757 -0
  35. data/lib/ruby-lint/definition_generator.rb +155 -0
  36. data/lib/ruby-lint/definitions/core.rb +5 -0
  37. data/lib/ruby-lint/definitions/core/arg0.rb +7 -0
  38. data/lib/ruby-lint/definitions/core/argf.rb +7 -0
  39. data/lib/ruby-lint/definitions/core/argument_error.rb +12 -0
  40. data/lib/ruby-lint/definitions/core/argv.rb +7 -0
  41. data/lib/ruby-lint/definitions/core/array.rb +414 -0
  42. data/lib/ruby-lint/definitions/core/autoload.rb +39 -0
  43. data/lib/ruby-lint/definitions/core/basic_object.rb +46 -0
  44. data/lib/ruby-lint/definitions/core/bignum.rb +128 -0
  45. data/lib/ruby-lint/definitions/core/binding.rb +52 -0
  46. data/lib/ruby-lint/definitions/core/class.rb +23 -0
  47. data/lib/ruby-lint/definitions/core/comparable.rb +38 -0
  48. data/lib/ruby-lint/definitions/core/complex.rb +195 -0
  49. data/lib/ruby-lint/definitions/core/condition_variable.rb +19 -0
  50. data/lib/ruby-lint/definitions/core/continuation.rb +8 -0
  51. data/lib/ruby-lint/definitions/core/data.rb +8 -0
  52. data/lib/ruby-lint/definitions/core/date.rb +706 -0
  53. data/lib/ruby-lint/definitions/core/date_time.rb +381 -0
  54. data/lib/ruby-lint/definitions/core/default_record_separator.rb +7 -0
  55. data/lib/ruby-lint/definitions/core/digest.rb +166 -0
  56. data/lib/ruby-lint/definitions/core/dir.rb +496 -0
  57. data/lib/ruby-lint/definitions/core/encoding.rb +2030 -0
  58. data/lib/ruby-lint/definitions/core/encoding_error.rb +8 -0
  59. data/lib/ruby-lint/definitions/core/enumerable.rb +352 -0
  60. data/lib/ruby-lint/definitions/core/enumerator.rb +37 -0
  61. data/lib/ruby-lint/definitions/core/env.rb +7 -0
  62. data/lib/ruby-lint/definitions/core/eoferror.rb +8 -0
  63. data/lib/ruby-lint/definitions/core/erb.rb +304 -0
  64. data/lib/ruby-lint/definitions/core/errno.rb +3331 -0
  65. data/lib/ruby-lint/definitions/core/etc.rb +138 -0
  66. data/lib/ruby-lint/definitions/core/exception.rb +72 -0
  67. data/lib/ruby-lint/definitions/core/false.rb +7 -0
  68. data/lib/ruby-lint/definitions/core/false_class.rb +30 -0
  69. data/lib/ruby-lint/definitions/core/fatal_error.rb +8 -0
  70. data/lib/ruby-lint/definitions/core/fiber.rb +35 -0
  71. data/lib/ruby-lint/definitions/core/fiber_error.rb +8 -0
  72. data/lib/ruby-lint/definitions/core/file.rb +1277 -0
  73. data/lib/ruby-lint/definitions/core/file_list.rb +727 -0
  74. data/lib/ruby-lint/definitions/core/file_test.rb +106 -0
  75. data/lib/ruby-lint/definitions/core/file_utils.rb +1027 -0
  76. data/lib/ruby-lint/definitions/core/fixnum.rb +156 -0
  77. data/lib/ruby-lint/definitions/core/float.rb +307 -0
  78. data/lib/ruby-lint/definitions/core/float_domain_error.rb +8 -0
  79. data/lib/ruby-lint/definitions/core/gc.rb +57 -0
  80. data/lib/ruby-lint/definitions/core/gem.rb +3161 -0
  81. data/lib/ruby-lint/definitions/core/hash.rb +512 -0
  82. data/lib/ruby-lint/definitions/core/immediate_value.rb +19 -0
  83. data/lib/ruby-lint/definitions/core/index_error.rb +8 -0
  84. data/lib/ruby-lint/definitions/core/integer.rb +100 -0
  85. data/lib/ruby-lint/definitions/core/interrupt.rb +14 -0
  86. data/lib/ruby-lint/definitions/core/io.rb +928 -0
  87. data/lib/ruby-lint/definitions/core/ioerror.rb +8 -0
  88. data/lib/ruby-lint/definitions/core/kernel.rb +504 -0
  89. data/lib/ruby-lint/definitions/core/key_error.rb +8 -0
  90. data/lib/ruby-lint/definitions/core/load_error.rb +28 -0
  91. data/lib/ruby-lint/definitions/core/local_jump_error.rb +8 -0
  92. data/lib/ruby-lint/definitions/core/main.rb +25 -0
  93. data/lib/ruby-lint/definitions/core/marshal.rb +466 -0
  94. data/lib/ruby-lint/definitions/core/match_data.rb +73 -0
  95. data/lib/ruby-lint/definitions/core/math.rb +205 -0
  96. data/lib/ruby-lint/definitions/core/memory_segmention_error.rb +8 -0
  97. data/lib/ruby-lint/definitions/core/method.rb +61 -0
  98. data/lib/ruby-lint/definitions/core/module.rb +262 -0
  99. data/lib/ruby-lint/definitions/core/monitor.rb +39 -0
  100. data/lib/ruby-lint/definitions/core/monitor_mixin.rb +59 -0
  101. data/lib/ruby-lint/definitions/core/mutex.rb +32 -0
  102. data/lib/ruby-lint/definitions/core/name_error.rb +16 -0
  103. data/lib/ruby-lint/definitions/core/nil.rb +7 -0
  104. data/lib/ruby-lint/definitions/core/nil_class.rb +46 -0
  105. data/lib/ruby-lint/definitions/core/no_memory_error.rb +8 -0
  106. data/lib/ruby-lint/definitions/core/no_method_error.rb +18 -0
  107. data/lib/ruby-lint/definitions/core/not_implemented_error.rb +8 -0
  108. data/lib/ruby-lint/definitions/core/numeric.rb +123 -0
  109. data/lib/ruby-lint/definitions/core/object.rb +31 -0
  110. data/lib/ruby-lint/definitions/core/object_space.rb +41 -0
  111. data/lib/ruby-lint/definitions/core/open_struct.rb +49 -0
  112. data/lib/ruby-lint/definitions/core/option_parser.rb +1355 -0
  113. data/lib/ruby-lint/definitions/core/precision.rb +21 -0
  114. data/lib/ruby-lint/definitions/core/primitive_failure.rb +8 -0
  115. data/lib/ruby-lint/definitions/core/proc.rb +109 -0
  116. data/lib/ruby-lint/definitions/core/process.rb +602 -0
  117. data/lib/ruby-lint/definitions/core/psych.rb +2231 -0
  118. data/lib/ruby-lint/definitions/core/queue.rb +44 -0
  119. data/lib/ruby-lint/definitions/core/rake.rb +4784 -0
  120. data/lib/ruby-lint/definitions/core/rake_file_utils.rb +203 -0
  121. data/lib/ruby-lint/definitions/core/rakeversion.rb +7 -0
  122. data/lib/ruby-lint/definitions/core/random.rb +38 -0
  123. data/lib/ruby-lint/definitions/core/range.rb +104 -0
  124. data/lib/ruby-lint/definitions/core/range_error.rb +8 -0
  125. data/lib/ruby-lint/definitions/core/rational.rb +96 -0
  126. data/lib/ruby-lint/definitions/core/rb_config.rb +36 -0
  127. data/lib/ruby-lint/definitions/core/regexp.rb +396 -0
  128. data/lib/ruby-lint/definitions/core/regexp_error.rb +8 -0
  129. data/lib/ruby-lint/definitions/core/rubinius.rb +16637 -0
  130. data/lib/ruby-lint/definitions/core/ruby_copyright.rb +7 -0
  131. data/lib/ruby-lint/definitions/core/ruby_description.rb +7 -0
  132. data/lib/ruby-lint/definitions/core/ruby_engine.rb +7 -0
  133. data/lib/ruby-lint/definitions/core/ruby_lint.rb +93 -0
  134. data/lib/ruby-lint/definitions/core/ruby_patchlevel.rb +7 -0
  135. data/lib/ruby-lint/definitions/core/ruby_platform.rb +7 -0
  136. data/lib/ruby-lint/definitions/core/ruby_release_date.rb +7 -0
  137. data/lib/ruby-lint/definitions/core/ruby_version.rb +7 -0
  138. data/lib/ruby-lint/definitions/core/runtime_error.rb +8 -0
  139. data/lib/ruby-lint/definitions/core/scan_error.rb +8 -0
  140. data/lib/ruby-lint/definitions/core/script_error.rb +8 -0
  141. data/lib/ruby-lint/definitions/core/security_error.rb +8 -0
  142. data/lib/ruby-lint/definitions/core/shellwords.rb +37 -0
  143. data/lib/ruby-lint/definitions/core/signal.rb +37 -0
  144. data/lib/ruby-lint/definitions/core/signal_exception.rb +19 -0
  145. data/lib/ruby-lint/definitions/core/singleton.rb +37 -0
  146. data/lib/ruby-lint/definitions/core/sized_queue.rb +42 -0
  147. data/lib/ruby-lint/definitions/core/standard_error.rb +8 -0
  148. data/lib/ruby-lint/definitions/core/stderr.rb +7 -0
  149. data/lib/ruby-lint/definitions/core/stdin.rb +7 -0
  150. data/lib/ruby-lint/definitions/core/stdout.rb +7 -0
  151. data/lib/ruby-lint/definitions/core/stop_iteration.rb +8 -0
  152. data/lib/ruby-lint/definitions/core/string.rb +713 -0
  153. data/lib/ruby-lint/definitions/core/string_io.rb +287 -0
  154. data/lib/ruby-lint/definitions/core/string_scanner.rb +158 -0
  155. data/lib/ruby-lint/definitions/core/struct.rb +357 -0
  156. data/lib/ruby-lint/definitions/core/syck.rb +30 -0
  157. data/lib/ruby-lint/definitions/core/symbol.rb +90 -0
  158. data/lib/ruby-lint/definitions/core/syntax_error.rb +44 -0
  159. data/lib/ruby-lint/definitions/core/system_call_error.rb +31 -0
  160. data/lib/ruby-lint/definitions/core/system_exit.rb +19 -0
  161. data/lib/ruby-lint/definitions/core/system_stack_error.rb +8 -0
  162. data/lib/ruby-lint/definitions/core/thread.rb +209 -0
  163. data/lib/ruby-lint/definitions/core/thread_error.rb +8 -0
  164. data/lib/ruby-lint/definitions/core/thread_group.rb +22 -0
  165. data/lib/ruby-lint/definitions/core/time.rb +233 -0
  166. data/lib/ruby-lint/definitions/core/toplevel_binding.rb +7 -0
  167. data/lib/ruby-lint/definitions/core/true.rb +7 -0
  168. data/lib/ruby-lint/definitions/core/true_class.rb +30 -0
  169. data/lib/ruby-lint/definitions/core/type_error.rb +8 -0
  170. data/lib/ruby-lint/definitions/core/unbound_method.rb +51 -0
  171. data/lib/ruby-lint/definitions/core/unmarshalable.rb +13 -0
  172. data/lib/ruby-lint/definitions/core/unsupported_library_error.rb +8 -0
  173. data/lib/ruby-lint/definitions/core/weak_ref.rb +42 -0
  174. data/lib/ruby-lint/definitions/core/zero_division_error.rb +8 -0
  175. data/lib/ruby-lint/definitions_builder.rb +692 -0
  176. data/lib/ruby-lint/extensions/string.rb +15 -0
  177. data/lib/ruby-lint/helper/constant_paths.rb +41 -0
  178. data/lib/ruby-lint/helper/conversion.rb +33 -0
  179. data/lib/ruby-lint/helper/current_scope.rb +98 -0
  180. data/lib/ruby-lint/helper/methods.rb +91 -0
  181. data/lib/ruby-lint/inspector.rb +191 -0
  182. data/lib/ruby-lint/iterator.rb +187 -127
  183. data/lib/ruby-lint/node.rb +107 -0
  184. data/lib/ruby-lint/parser.rb +510 -1137
  185. data/lib/ruby-lint/parser_error.rb +15 -27
  186. data/lib/ruby-lint/presenter/json.rb +19 -0
  187. data/lib/ruby-lint/presenter/text.rb +37 -0
  188. data/lib/ruby-lint/report.rb +95 -53
  189. data/lib/ruby-lint/report/entry.rb +71 -0
  190. data/lib/ruby-lint/template/definition.erb +24 -0
  191. data/lib/ruby-lint/template/scope.rb +25 -0
  192. data/lib/ruby-lint/variable_predicates.rb +109 -0
  193. data/lib/ruby-lint/version.rb +1 -1
  194. data/ruby-lint.gemspec +19 -8
  195. data/spec/helper.rb +10 -2
  196. data/spec/ruby-lint/analyze/argument_amount.rb +91 -0
  197. data/spec/ruby-lint/analyze/shadowing_variables.rb +69 -14
  198. data/spec/ruby-lint/analyze/undefined_methods.rb +174 -0
  199. data/spec/ruby-lint/analyze/undefined_variables.rb +70 -179
  200. data/spec/ruby-lint/analyze/unused_variables.rb +63 -183
  201. data/spec/ruby-lint/configuration.rb +15 -0
  202. data/spec/ruby-lint/constant_loader.rb +32 -0
  203. data/spec/ruby-lint/definition/dsl.rb +142 -0
  204. data/spec/ruby-lint/definition/method_calls.rb +26 -0
  205. data/spec/ruby-lint/definition/ruby_method.rb +175 -0
  206. data/spec/ruby-lint/definition/ruby_object.rb +228 -0
  207. data/spec/ruby-lint/definitions_builder/assignments/arrays.rb +71 -0
  208. data/spec/ruby-lint/definitions_builder/assignments/hashes.rb +65 -0
  209. data/spec/ruby-lint/definitions_builder/assignments/objects.rb +23 -0
  210. data/spec/ruby-lint/definitions_builder/assignments/optional.rb +22 -0
  211. data/spec/ruby-lint/definitions_builder/assignments/return_values.rb +78 -0
  212. data/spec/ruby-lint/definitions_builder/assignments/variables.rb +71 -0
  213. data/spec/ruby-lint/definitions_builder/associate_nodes.rb +17 -0
  214. data/spec/ruby-lint/definitions_builder/blocks.rb +40 -0
  215. data/spec/ruby-lint/definitions_builder/classes.rb +230 -0
  216. data/spec/ruby-lint/definitions_builder/for.rb +16 -0
  217. data/spec/ruby-lint/definitions_builder/methods.rb +147 -0
  218. data/spec/ruby-lint/definitions_builder/modules.rb +175 -0
  219. data/spec/ruby-lint/definitions_builder/reference_amount.rb +31 -0
  220. data/spec/ruby-lint/definitions_builder/unused.rb +15 -0
  221. data/spec/ruby-lint/extensions/string.rb +7 -0
  222. data/spec/ruby-lint/iterator.rb +42 -417
  223. data/spec/ruby-lint/node.rb +38 -0
  224. data/spec/ruby-lint/parser/assignments.rb +225 -0
  225. data/spec/ruby-lint/parser/classes.rb +80 -122
  226. data/spec/ruby-lint/parser/errors.rb +7 -14
  227. data/spec/ruby-lint/parser/metadata.rb +17 -0
  228. data/spec/ruby-lint/parser/method_definitions.rb +111 -0
  229. data/spec/ruby-lint/parser/methods.rb +184 -216
  230. data/spec/ruby-lint/parser/modules.rb +54 -33
  231. data/spec/ruby-lint/parser/operators.rb +30 -65
  232. data/spec/ruby-lint/parser/statements/begin.rb +55 -0
  233. data/spec/ruby-lint/parser/statements/case.rb +34 -0
  234. data/spec/ruby-lint/parser/statements/defined.rb +11 -0
  235. data/spec/ruby-lint/parser/statements/for.rb +34 -0
  236. data/spec/ruby-lint/parser/statements/if.rb +46 -0
  237. data/spec/ruby-lint/parser/statements/return.rb +14 -0
  238. data/spec/ruby-lint/parser/statements/super.rb +49 -0
  239. data/spec/ruby-lint/parser/statements/unless.rb +42 -0
  240. data/spec/ruby-lint/parser/statements/until.rb +25 -0
  241. data/spec/ruby-lint/parser/statements/while.rb +25 -0
  242. data/spec/ruby-lint/parser/statements/yield.rb +18 -0
  243. data/spec/ruby-lint/parser/types/arrays.rb +47 -0
  244. data/spec/ruby-lint/parser/types/booleans.rb +11 -0
  245. data/spec/ruby-lint/parser/types/constants.rb +32 -0
  246. data/spec/ruby-lint/parser/types/hashes.rb +55 -0
  247. data/spec/ruby-lint/parser/types/nil.rb +7 -0
  248. data/spec/ruby-lint/parser/types/numbers.rb +11 -0
  249. data/spec/ruby-lint/parser/types/procs.rb +11 -0
  250. data/spec/ruby-lint/parser/types/ranges.rb +11 -0
  251. data/spec/ruby-lint/parser/types/regexp.rb +27 -0
  252. data/spec/ruby-lint/parser/types/strings.rb +44 -0
  253. data/spec/ruby-lint/parser/types/symbols.rb +15 -0
  254. data/spec/ruby-lint/presenter/json.rb +31 -0
  255. data/spec/ruby-lint/presenter/text.rb +22 -0
  256. data/spec/ruby-lint/report.rb +45 -15
  257. data/spec/ruby-lint/report/entry.rb +24 -0
  258. data/spec/support/bacon.rb +33 -0
  259. data/spec/support/building.rb +43 -0
  260. data/spec/support/definitions.rb +23 -0
  261. data/spec/support/parsing.rb +23 -0
  262. data/spec/support/simplecov.rb +16 -0
  263. data/task/build.rake +9 -0
  264. data/task/checksum.rake +13 -0
  265. data/task/coverage.rake +6 -0
  266. data/task/doc.rake +5 -0
  267. data/task/generate.rake +34 -0
  268. data/task/graphviz.rake +12 -0
  269. data/task/stdlib.rake +2 -9
  270. data/task/tag.rake +6 -0
  271. metadata +337 -68
  272. metadata.gz.asc +17 -0
  273. data/.rbenv-version +0 -1
  274. data/lib/ruby-lint/analyze/coding_style.rb +0 -407
  275. data/lib/ruby-lint/analyze/definitions.rb +0 -244
  276. data/lib/ruby-lint/analyze/method_validation.rb +0 -104
  277. data/lib/ruby-lint/callback.rb +0 -67
  278. data/lib/ruby-lint/constant_importer.rb +0 -112
  279. data/lib/ruby-lint/definition.rb +0 -230
  280. data/lib/ruby-lint/formatter/text.rb +0 -54
  281. data/lib/ruby-lint/helper/definition_resolver.rb +0 -143
  282. data/lib/ruby-lint/helper/scoping.rb +0 -138
  283. data/lib/ruby-lint/options.rb +0 -58
  284. data/lib/ruby-lint/token/assignment_token.rb +0 -35
  285. data/lib/ruby-lint/token/begin_rescue_token.rb +0 -57
  286. data/lib/ruby-lint/token/block_token.rb +0 -26
  287. data/lib/ruby-lint/token/case_token.rb +0 -44
  288. data/lib/ruby-lint/token/class_token.rb +0 -24
  289. data/lib/ruby-lint/token/keyword_token.rb +0 -43
  290. data/lib/ruby-lint/token/method_definition_token.rb +0 -64
  291. data/lib/ruby-lint/token/method_token.rb +0 -56
  292. data/lib/ruby-lint/token/parameters_token.rb +0 -99
  293. data/lib/ruby-lint/token/regexp_token.rb +0 -15
  294. data/lib/ruby-lint/token/statement_token.rb +0 -69
  295. data/lib/ruby-lint/token/token.rb +0 -176
  296. data/lib/ruby-lint/token/variable_token.rb +0 -18
  297. data/spec/benchmarks/memory.rb +0 -52
  298. data/spec/benchmarks/parse_parser.rb +0 -16
  299. data/spec/fixtures/stdlib/un.rb +0 -348
  300. data/spec/ruby-lint/analyze/coding_style.rb +0 -224
  301. data/spec/ruby-lint/analyze/complex/un.rb +0 -29
  302. data/spec/ruby-lint/analyze/definitions/classes.rb +0 -114
  303. data/spec/ruby-lint/analyze/definitions/methods.rb +0 -91
  304. data/spec/ruby-lint/analyze/definitions/modules.rb +0 -207
  305. data/spec/ruby-lint/analyze/definitions/variables.rb +0 -103
  306. data/spec/ruby-lint/analyze/method_validation.rb +0 -177
  307. data/spec/ruby-lint/callback.rb +0 -28
  308. data/spec/ruby-lint/constant_importer.rb +0 -27
  309. data/spec/ruby-lint/definition.rb +0 -96
  310. data/spec/ruby-lint/formatter/text.rb +0 -21
  311. data/spec/ruby-lint/parser/arrays.rb +0 -147
  312. data/spec/ruby-lint/parser/expander_assignments.rb +0 -183
  313. data/spec/ruby-lint/parser/hashes.rb +0 -136
  314. data/spec/ruby-lint/parser/keywords.rb +0 -89
  315. data/spec/ruby-lint/parser/objects.rb +0 -39
  316. data/spec/ruby-lint/parser/procs.rb +0 -113
  317. data/spec/ruby-lint/parser/ranges.rb +0 -49
  318. data/spec/ruby-lint/parser/regexp.rb +0 -31
  319. data/spec/ruby-lint/parser/scalars.rb +0 -93
  320. data/spec/ruby-lint/parser/statements.rb +0 -591
  321. data/spec/ruby-lint/parser/variables.rb +0 -230
@@ -1,47 +1,34 @@
1
1
  module RubyLint
2
2
  ##
3
- # {RubyLint::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 {RubyLint::Token::Token} and
6
- # {RubyLint::Token::VariableToken}. It also takes care of a few more things such
7
- # as saving the associated line of code and setting method visibility.
3
+ # {RubyLint::Parser} parses Ruby code and returns a clean and usable AST
4
+ # instead of the rather raw AST returned by Ripper itself. Each node in the
5
+ # AST is an instance of {RubyLint::Node}.
8
6
  #
9
- # Parsing Ruby code requires two steps:
7
+ # ## Example
10
8
  #
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 {RubyLint::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 = RubyLint::Parser.new('puts "Hello, world!"')
22
- #
23
- # pp parser.parse
24
- #
25
- # This outputs the following AST:
26
- #
27
- # [#<RubyLint::Token::MethodToken:0x000000012f04d0
28
- # @code="puts \"Hello, world!\"",
29
- # @column=0,
30
- # @event=:method,
31
- # @line=1,
32
- # @name="puts",
33
- # @parameters=
34
- # [#<RubyLint::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>]
9
+ # RubyLint::Parser.new('[10, 20]').parse
10
+ # # => (root (array (integer "10") (integer "20")))
43
11
  #
44
12
  class Parser < Ripper::SexpBuilderPP
13
+ ##
14
+ # Hash containing various Ripper types and the RubyLint types to use
15
+ # instead.
16
+ #
17
+ # @return [Hash]
18
+ #
19
+ TYPE_MAPPING = {
20
+ :ident => :identifier,
21
+ :gvar => :global_variable,
22
+ :ivar => :instance_variable,
23
+ :cvar => :class_variable,
24
+ :const => :constant,
25
+ :int => :integer,
26
+ :float => :float,
27
+ :tstring_content => :string,
28
+ :label => :symbol,
29
+ :kw => :keyword
30
+ }
31
+
45
32
  ##
46
33
  # Array containing all the event names of which the methods should simply
47
34
  # returned the passed argument.
@@ -49,29 +36,21 @@ module RubyLint
49
36
  # @return [Array]
50
37
  #
51
38
  RETURN_FIRST_ARG_EVENTS = [
52
- :program,
53
- :var_field,
54
- :args_add_block,
39
+ :arg_paren,
55
40
  :assoclist_from_args,
56
- :symbol_literal,
57
41
  :begin,
58
- :mrhs_new_from_args,
59
- :blockarg,
60
- :rest_param,
61
- :arg_paren,
62
42
  :block_var,
43
+ :blockarg,
63
44
  :const_ref,
45
+ :mlhs_paren,
46
+ :mrhs_new_from_args,
47
+ :rest_param,
48
+ :symbol_literal,
64
49
  :top_const_ref,
65
- :mlhs_paren
50
+ :var_field,
51
+ :paren
66
52
  ]
67
53
 
68
- ##
69
- # Array of events of which the callback method should simply return nil.
70
- #
71
- # @return [Array]
72
- #
73
- RETURN_NIL_EVENTS = [:void_stmt]
74
-
75
54
  ##
76
55
  # Array of event names that should return an instance of
77
56
  # {RubyLint::Token::MethodToken}.
@@ -81,8 +60,8 @@ module RubyLint
81
60
  RETURN_METHOD_EVENTS = [:fcall, :vcall]
82
61
 
83
62
  ##
84
- # Hash containing the names of various event callbacks that should return
85
- # a token class containing details about a single line statement.
63
+ # List of modified statements, used to dynamically define the callback
64
+ # methods.
86
65
  #
87
66
  # @return [Hash]
88
67
  #
@@ -94,32 +73,83 @@ module RubyLint
94
73
  }
95
74
 
96
75
  ##
97
- # Array containing the three method calls that set the visibility of a
98
- # method.
76
+ # Collection of Ripper events of which the callbacks all share similar
77
+ # code. The corresponding methods are defined on the fly.
78
+ #
79
+ # @return [Hash]
80
+ #
81
+ BASIC_EVENTS = {
82
+ :bodystmt => :body,
83
+ :class => :class,
84
+ :module => :module,
85
+ :binary => :binary,
86
+ :unary => :unary,
87
+ :return => :return,
88
+ :else => :else,
89
+ :unless => :unless,
90
+ :until => :until,
91
+ :while => :while,
92
+ :dot2 => :dot2,
93
+ :dot3 => :dot3,
94
+ :assoc_new => :key_value,
95
+ :hash => :hash,
96
+ :aref => :aref,
97
+ :string_concat => :string_concat,
98
+ :string_embexpr => :embed,
99
+ :begin => :begin,
100
+ :ensure => :ensure,
101
+ :defined => :defined,
102
+ :super => :super,
103
+ :yield0 => :yield,
104
+ :yield => :yield,
105
+ :sclass => :sclass
106
+ }
107
+
108
+ ##
109
+ # Hash containing various Ripper event names and the methods these events
110
+ # should execute.
111
+ #
112
+ # @return [Hash]
113
+ #
114
+ EVENT_ALIASES = {
115
+ :dyna_symbol => :on_symbol,
116
+ :aref_field => :on_aref,
117
+ :bare_assoc_hash => :on_hash,
118
+ :do_block => :on_brace_block
119
+ }
120
+
121
+ ##
122
+ # Array of events (the ones used by ruby-lint) of which the child nodes
123
+ # should be stripped of `nil` values.
99
124
  #
100
125
  # @return [Array]
101
126
  #
102
- METHOD_VISIBILITY = ['public', 'protected', 'private']
127
+ COMPACT_EVENT_ARGS = [:body, :unless]
103
128
 
104
129
  ##
105
- # Symbol containing the default method visibility.
130
+ # Array of events of which the first callback parameter should be used for
131
+ # the child nodes of a callback.
106
132
  #
107
- # @return [Symbol]
133
+ # @return [Array]
108
134
  #
109
- DEFAULT_VISIBILITY = :public
110
-
111
- # Return an RubyLint::Token::Token instance for each scanner event instead of
112
- # an array with multiple indexes.
113
- SCANNER_EVENTS.each do |event|
114
- define_method("on_#{event}") do |token|
115
- return Token::Token.new(
116
- :name => token,
117
- :type => event,
118
- :value => token,
119
- :line => lineno,
120
- :column => column,
121
- :code => code(lineno)
122
- )
135
+ UNPACK_EVENT_ARGS = [:else, :hash, :embed, :ensure]
136
+
137
+ ##
138
+ # Hash containing parameter indexes and the node types.
139
+ #
140
+ # @return [Hash]
141
+ #
142
+ PARAMETER_INDEX_TYPES = {
143
+ 0 => :argument,
144
+ 1 => :optional_argument,
145
+ 2 => :rest_argument,
146
+ 3 => :more_argument,
147
+ 4 => :block_argument
148
+ }
149
+
150
+ SCANNER_EVENTS.each do |type|
151
+ define_method("on_#{type}") do |value|
152
+ return Node.new(readable_type_name(type), [value], metadata)
123
153
  end
124
154
  end
125
155
 
@@ -127,1327 +157,670 @@ module RubyLint
127
157
  define_method("on_#{event}") { |*args| return args[0] }
128
158
  end
129
159
 
130
- RETURN_NIL_EVENTS.each do |event|
131
- define_method("on_#{event}") { |*args| return nil }
160
+ RETURN_METHOD_EVENTS.each do |event|
161
+ define_method("on_#{event}") do |node|
162
+ return Node.new(
163
+ :method,
164
+ [node.children[0], on_params, nil, nil], metadata(node)
165
+ )
166
+ end
132
167
  end
133
168
 
134
- RETURN_METHOD_EVENTS.each do |event|
135
- define_method("on_#{event}") do |token|
136
- if METHOD_VISIBILITY.include?(token.name)
137
- @visibility = token.name.to_sym
169
+ BASIC_EVENTS.each do |original, new|
170
+ define_method("on_#{original}") do |*args|
171
+ if COMPACT_EVENT_ARGS.include?(new)
172
+ args = args.map { |arg| arg.compact rescue arg }.compact
138
173
  end
139
174
 
140
- return Token::MethodToken.new(
141
- :name => token.name,
142
- :line => token.line,
143
- :column => token.column,
144
- :value => token.name,
145
- :code => code(token.line)
146
- )
175
+ args = args[0] if UNPACK_EVENT_ARGS.include?(new)
176
+
177
+ return Node.new(new, args, metadata)
147
178
  end
148
179
  end
149
180
 
150
- MOD_STATEMENT_EVENTS.each do |ripper_event, ruby_lint_event|
151
- define_method("on_#{ripper_event}") do |statement, value|
181
+ MOD_STATEMENT_EVENTS.each do |mod, normal|
182
+ define_method("on_#{mod}") do |statement, value|
152
183
  value = [value] unless value.is_a?(Array)
153
184
 
154
- return Token::StatementToken.new(
155
- :type => ruby_lint_event,
156
- :statement => statement,
157
- :value => value,
158
- :line => lineno,
159
- :column => column,
160
- :code => code(lineno)
161
- )
185
+ return send("on_#{normal}", statement, value)
186
+ end
187
+ end
188
+
189
+ EVENT_ALIASES.each do |event, method|
190
+ define_method("on_#{event}") do |*args|
191
+ return send(method, *args)
162
192
  end
163
193
  end
164
194
 
165
195
  ##
166
- # Creates a new instance of the parser and pre-defines various instance
167
- # variables.
168
- #
169
196
  # @see Ripper::SexpBuilderPP#initialize
170
197
  #
171
198
  def initialize(code, file = '(ruby-lint)', line = 1)
172
199
  super
173
200
 
174
- @file = file
175
- @visibility = DEFAULT_VISIBILITY
176
- @lines = []
201
+ @file = file
202
+ end
177
203
 
178
- code.each_line do |code_line|
179
- @lines << code_line.chomp
180
- end
204
+ ##
205
+ # @return [NilClass]
206
+ #
207
+ def on_void_stmt
208
+ return nil
181
209
  end
182
210
 
183
211
  ##
184
- # Called when a parser error was encountered.
212
+ # Called at the start of a Ruby program.
185
213
  #
186
- # @param [String] message The error message.
187
- # @raise [RubyLint::ParserError]
214
+ # @param [Array] nodes The various nodes of the program.
215
+ # @return [RubyLint::Node]
188
216
  #
189
- def on_parse_error(message)
190
- raise ParserError.new(message, lineno, column, @file)
217
+ def on_program(nodes)
218
+ nodes = [nodes] unless nodes.is_a?(Array)
219
+
220
+ return Node.new(:root, nodes, :line => 1, :column => 0, :file => @file)
191
221
  end
192
222
 
193
223
  ##
194
- # Called when a string literal was found.
195
- #
196
- # @param [Array] token Array containing details about the string.
197
- # @return [RubyLint::Token::Token]
224
+ # @param [String] message The error message.
225
+ # @raise [RubyLint::ParserError]
198
226
  #
199
- def on_string_literal(token)
200
- if token and token[1]
201
- return token[1]
202
- else
203
- return Token::Token.new(
204
- :name => '',
205
- :value => '',
206
- :line => lineno,
207
- :column => column,
208
- :type => :string
209
- )
210
- end
227
+ def on_parse_error(message)
228
+ raise ParserError.new(message, lineno, column, @file)
211
229
  end
212
230
 
213
231
  ##
214
232
  # Called when a symbol is found.
215
233
  #
216
- # @param [RubyLint::Token::Token] token The symbol token.
217
- # @return [RubyLint::Token::Token]
234
+ # @param [RubyLint::Node|Array] node The value of the symbol. This
235
+ # parameter is set to an Array when parsing code such as `:"hello"`.
236
+ # @return [RubyLint::Node]
218
237
  #
219
- def on_symbol(token)
220
- token.type = :symbol
238
+ def on_symbol(node)
239
+ node = node[0] if node.is_a?(Array)
221
240
 
222
- return token
241
+ return Node.new(:symbol, node.children, metadata(node))
223
242
  end
224
243
 
225
244
  ##
226
- # Called when a symbol using quotes was found.
227
- #
228
- # @see RubyLint::Parser#on_symbol
245
+ # @param [Array] content The contents of the string.
246
+ # @return [RubyLint::Node]
229
247
  #
230
- def on_dyna_symbol(token)
231
- return on_symbol(token[0])
248
+ def on_string_literal(content)
249
+ return content[1] || Node.new(:string, [], metadata)
232
250
  end
233
251
 
234
252
  ##
235
- # Called when an expression is embedded in a string.
253
+ # Called when a piece of code is embedded using `#expressions` (e.g.
254
+ # `#$foo`).
236
255
  #
237
- # @param [Array] exp The embedded expressions.
238
- # @return [RubyLint::Token::Token]
256
+ # @param [RubyLint::Node] node
257
+ # @return [RubyLint::Node]
239
258
  #
240
- def on_string_embexpr(exp)
241
- return exp[0]
259
+ def on_string_dvar(node)
260
+ return Node.new(:embed, [node], metadata(node))
242
261
  end
243
262
 
244
263
  ##
245
- # Called when an array is found.
246
- #
247
264
  # @param [Array] values The values of the array.
248
- # @return [RubyLint::Token::Token]
265
+ # @return [RubyLint::Node]
249
266
  #
250
267
  def on_array(values)
251
268
  values ||= []
269
+ values = [values] unless values.is_a?(Array)
270
+ children = values.flatten
252
271
 
253
- return Token::Token.new(
254
- :type => :array,
255
- :value => values.map { |v| v.is_a?(Array) ? v[0] : v },
256
- :line => lineno,
257
- :column => column,
258
- :code => code(lineno)
259
- )
272
+ return Node.new(:array, children, metadata)
260
273
  end
261
274
 
262
275
  ##
263
- # Called when a reference to a particular array index is found.
264
- #
265
- # @param [RubyLint::Token::Token] array The array that was referenced.
266
- # @param [RubyLint::Token::Token] index The index that was referenced.
267
- # @return [RubyLint::Token::Token]
276
+ # @param [Array] regexp Array containing the regular expression's body.
277
+ # @return [RubyLint::Node] mode The mode for the regular expression.
278
+ # @return [RubyLint::Node]
268
279
  #
269
- def on_aref(array, index)
270
- array.key = index
271
-
272
- return array
273
- end
274
-
275
- ##
276
- # Called when a value is assigned to an array index.
277
- #
278
- # @param [RubyLint::Token::Token] array The array that was referenced.
279
- # @param [RubyLint::Token::Token] index The index of the array that was
280
- # referenced.
281
- # @return [RubyLint::Token::Token]
282
- #
283
- def on_aref_field(array, index)
284
- array.key = index
285
-
286
- return Token::AssignmentToken.new(
287
- :receiver => array,
288
- :line => lineno,
289
- :column => column,
290
- :type => array.type,
291
- :code => code(lineno)
292
- )
280
+ def on_regexp_literal(regexp, mode)
281
+ return Node.new(:regexp, [regexp[0], mode], metadata)
293
282
  end
294
283
 
295
284
  ##
296
- # Called when a Hash is found.
285
+ # @param [RubyLint::Node] params The parameters of the lamda.
286
+ # @param [Array] body The body of the lambda.
287
+ # @return [RubyLint::Node]
297
288
  #
298
- # @param [Array] pairs An array of key/value pairs of the hash.
299
- # @return [RubyLint::Token::Token]
300
- #
301
- def on_hash(pairs)
302
- # column() is set to the column number of the very end of the hash.
303
- col = pairs[0].column rescue column
304
-
305
- return Token::Token.new(
306
- :type => :hash,
307
- :value => pairs,
308
- :line => lineno,
309
- :column => col,
310
- :code => code(lineno)
311
- )
289
+ def on_lambda(params, body)
290
+ return on_brace_block(params, body).updated(:lambda)
312
291
  end
313
292
 
314
293
  ##
315
- # Called when a bare Hash is found. A bare Hash is a hash that's declared
316
- # without the curly braces.
317
- #
318
- # @see RubyLint::Parser#on_hash
294
+ # @param [RubyLint::Node] params The parameters of the block.
295
+ # @param [Array] body The body of the block.
296
+ # @return [RubyLint::Node]
319
297
  #
320
- def on_bare_assoc_hash(pairs)
321
- return on_hash(pairs)
298
+ def on_brace_block(params, body)
299
+ return Node.new(:block, [params || on_params, on_bodystmt(body)], metadata)
322
300
  end
323
301
 
324
302
  ##
325
- # Called when a new key/value pair of a Hash is found.
326
- #
327
- # @param [RubyLint::Token::Token] key The key of the pair.
328
- # @param [RubyLint::Token::Token] value The value of the pair.
329
- # @return [RubyLint::Token::Token]
303
+ # @param [RubyLint::Node] left
304
+ # @param [RubyLint::Node] right
305
+ # @return [RubyLint::Node]
330
306
  #
331
- def on_assoc_new(key, value)
332
- key.name = key.value
333
- key.value = value
307
+ def on_const_path_ref(left, right)
308
+ left = left.type == :constant_path ? left.children : left
334
309
 
335
- return key
336
- end
337
-
338
- ##
339
- # Called when a block is created using curly braces.
340
- #
341
- # @param [RubyLint::Token::ParametersToken] params The parameters of the
342
- # block.
343
- # @param [Array] body Array containing the tokens of the block.
344
- # @return [RubyLint::Token::BlockToken]
345
- #
346
- def on_brace_block(params, body)
347
- return Token::BlockToken.new(
348
- :parameters => params,
349
- :value => body,
350
- :line => lineno,
351
- :column => column,
352
- :type => :block,
353
- :code => code(lineno)
354
- )
310
+ return Node.new(:constant_path, [left, right].flatten, metadata)
355
311
  end
356
312
 
357
313
  ##
358
- # Called when a block is created using the do/end statements.
359
- #
360
- # @see RubyLint::Parser#on_brace_block
314
+ # @see #on_constant_path_ref
361
315
  #
362
- def on_do_block(params, body)
363
- return on_brace_block(params, body)
316
+ def on_const_path_field(left, right)
317
+ return on_const_path_ref(left, right)
364
318
  end
365
319
 
366
320
  ##
367
- # Called when a lambda is found.
321
+ # Called when a variable is assigned to a start (`*`).
368
322
  #
369
- # @see RubyLint::Parser#on_brace_block
323
+ # @param [Array|RubyLint::Node] left The variable(s) to the left of the
324
+ # star.
325
+ # @param [Array|RubyLint::Node] right The variable(s) to the right of the
326
+ # star.
327
+ # @return [RubyLint::Node]
370
328
  #
371
- def on_lambda(params, body)
372
- token = on_brace_block(params, body)
373
- token.type = :lambda
374
-
375
- return token
376
- end
377
-
378
- ##
379
- # Called when a Range is found.
380
- #
381
- # @param [RubyLint::Token::Token] start The start value of the range.
382
- # @param [RubyLint::Token::Token] stop The end value of the range.
383
- # @return [RubyLint::Token::Token]
384
- #
385
- def on_dot2(start, stop)
386
- return Token::Token.new(
387
- :type => :range,
388
- :line => start.line,
389
- :column => start.line,
390
- :value => [start, stop],
391
- :code => code(start.line)
392
- )
393
- end
329
+ def on_mlhs_add_star(left, right)
330
+ if right
331
+ left << right.updated(nil, [*right.children, true])
332
+ # Add a placeholder for the expander token.
333
+ else
334
+ left << nil
335
+ end
394
336
 
395
- ##
396
- # Called when a range using 3 dots is found.
397
- #
398
- # @see RubyLint::Parser#on_dot2
399
- # @todo There's a difference between ranges created using two and three
400
- # dots, this method should return a different token in the future.
401
- #
402
- def on_dot3(start, stop)
403
- return on_dot2(start, stop)
337
+ return left
404
338
  end
405
339
 
406
340
  ##
407
- # Called when a regular expression is found.
408
- #
409
- # @param [Array] regexp The regular expression's value.
410
- # @param [RubyLint::Token::Token] modes The modes of the regular expression.
411
- # @return [RubyLint::Token::RegexpToken]
341
+ # @param [RubyLint::Node] variable The data to assign the value to.
342
+ # @param [RubyLint::Node] value The value to assign.
343
+ # @return [RubyLint::Node]
412
344
  #
413
- def on_regexp_literal(regexp, modes)
414
- regexp = regexp[0]
415
- modes_array = []
416
-
417
- value = regexp.respond_to?(:value) ? regexp.value : nil
418
- line = regexp.respond_to?(:line) ? regexp.line : lineno
419
- col = regexp.respond_to?(:column) ? regexp.column : column
345
+ def on_assign(variable, value)
346
+ variable = variable.updated(:local_variable) if variable.identifier?
420
347
 
421
- if modes
422
- modes_array = modes.value.split('').select { |c| c =~ /\w/ }
348
+ # When assigning values to array indexes or hash keys the value should
349
+ # always be an array. This makes it easier to assign values without
350
+ # having to check the type of data we're dealing with.
351
+ if variable.type == :aref and !value.is_a?(Array)
352
+ value = [value]
423
353
  end
424
354
 
425
- return Token::RegexpToken.new(
426
- :type => :regexp,
427
- :value => value,
428
- :line => line,
429
- :column => col,
430
- :modes => modes_array,
431
- :code => code(line)
432
- )
355
+ return Node.new(:assign, [variable, value], metadata(variable))
433
356
  end
434
357
 
435
358
  ##
436
- # Called when a value is assigned to a variable.
359
+ # Called when a conditional assignment is found.
437
360
  #
438
- # @param [RubyLint::Token::Token] variable The variable that is assigned.
439
- # @param [RubyLint::Token::Token] value The value to assign.
440
- # @return [RubyLint::Token::VariableToken]
361
+ # @see RubyLint::Parser#on_assign
441
362
  #
442
- def on_assign(variable, value)
443
- if variable.class == RubyLint::Token::AssignmentToken
444
- variable.value = value
445
-
446
- return variable
447
- end
448
-
449
- if variable.is_a?(Array)
450
- line = variable[-1].line
451
- col = variable[-1].column
452
- type = variable[-1].type
453
- name = variable
454
- else
455
- line = variable.line
456
- col = variable.column
457
- type = variable.type
458
- name = variable.name
459
- end
460
-
461
- return Token::AssignmentToken.new(
462
- :line => line,
463
- :column => col,
464
- :name => name,
465
- :type => type,
466
- :value => value,
467
- :code => code(line)
468
- )
363
+ def on_opassign(variable, operator, value)
364
+ return on_assign(variable, value).updated(:op_assign)
469
365
  end
470
366
 
471
367
  ##
472
- # Called when a set of values is assigned to multiple variables.
473
- #
474
- # @param [Array] variables The variables that are being assigned values.
475
- # @param [Array|RubyLint::Token::Token] values The values to assign.
476
- # @return [RubyLint::Token::AssignmentToken]
368
+ # @param [Array] variables The variables that are being assigned.
369
+ # @param [Array|RubyLint::Node] values The values to assign.
370
+ # @return [RubyLint::Node]
477
371
  #
478
372
  def on_massign(variables, values)
479
- assignments = []
480
- variables = variables.flatten
481
- assigned = []
482
- expander = nil
483
- value_index = 0
484
-
485
- variables.each_with_index do |variable, var_index|
486
- if variable.expand
487
- expander = var_index
488
- value = Token::Token.new(
489
- :type => :array,
490
- :line => variable.line,
491
- :column => variable.column,
492
- :code => variable.code,
493
- :value => []
494
- )
495
- else
496
- value = nil
497
- end
498
-
499
- assignments << Token::AssignmentToken.new(
500
- :name => variable.name,
501
- :line => variable.line,
502
- :column => variable.column,
503
- :code => variable.code,
504
- :type => variable.type,
505
- :expand => variable.expand,
506
- :value => value
507
- )
508
- end
373
+ nodes = []
374
+ variables = variables.flatten
375
+ before = 0
509
376
 
510
- # Unpack array based values and ensure that `values` is always an array.
511
- if values.is_a?(Token::Token) and values.type == :array
512
- values = values.value
513
- elsif values.is_a?(Token::Token)
377
+ if values.is_a?(Node) and values.type == :array
378
+ values = values.children.dup
379
+ elsif !values.is_a?(Array)
514
380
  values = [values]
515
381
  end
516
382
 
517
- equal_length = assignments.length == values.length
383
+ var_length = variables.length
384
+ val_length = values.length
385
+
386
+ variables.each_with_index do |variable, index|
387
+ if !variable
388
+ values.shift
389
+ next
390
+ end
391
+
392
+ variable = variable.updated(:local_variable) if variable.identifier?
393
+
394
+ # Extract the values for the expander variable based on the amount of
395
+ # variables, values and the amount of variables that were assigned
396
+ # before the expander.
397
+ if variable.children[1]
398
+ slice_length = val_length - (var_length - 1)
518
399
 
519
- # Assign the values to each variable. The remaining values will be
520
- # assigned to the expanding variable.
521
- assignments.each do |assignment|
522
- if !assignment.expand and values[value_index]
523
- assignment.value = values[value_index]
400
+ value = Node.new(
401
+ :array,
402
+ values.slice!(index - before, slice_length),
403
+ metadata(variable)
404
+ )
524
405
 
525
- assigned << values[value_index]
526
- value_index += 1
406
+ variable = variable.updated(nil, [variable.children[0]])
407
+ else
408
+ before += 1
409
+ value = values.shift
527
410
  end
528
411
 
529
- # THINK: I really wonder if this is the way to make sure the expander
530
- # value is assigned correctly.
531
- if assignment.expand and equal_length
532
- value_index += 1
412
+ unless value
413
+ value = Node.new(
414
+ :keyword,
415
+ ['nil'],
416
+ metadata(variable)
417
+ )
533
418
  end
534
- end
535
419
 
536
- # Assign the remaining values to the expander variable.
537
- if expander
538
- assignments[expander].value.value = values - assigned
420
+ nodes << Node.new(:assign, [variable, value], metadata(variable))
539
421
  end
540
422
 
541
- return assignments
423
+ return Node.new(:mass_assign, nodes, metadata)
542
424
  end
543
425
 
544
426
  ##
545
- # Called when a expand assignment is found.
546
- #
547
- # @param [Array] left The variables assigned on the left hand side of the
548
- # expand operator.
549
- # @param [RubyLint::Token::Token|NilClass] right The variable assigned on
550
- # the right hand side of the operator.
427
+ # @param [RubyLint::Node] variable The variable that was referenced.
428
+ # @return [RubyLint::Node]
551
429
  #
552
- def on_mlhs_add_star(left, right)
553
- variables = left || []
554
-
555
- if right and right.name != '*'
556
- right.expand = true
557
-
558
- variables << right
559
- end
430
+ def on_var_ref(variable)
431
+ variable = variable.updated(:local_variable) if variable.identifier?
560
432
 
561
- return variables
433
+ return variable
562
434
  end
563
435
 
564
436
  ##
565
- # @see RubyLint::Parser#on_mlhs_add_star
437
+ # @param [RubyLint::Node] object The object of the field.
438
+ # @param [Symbol] operator The operator used to separate the object and
439
+ # field.
440
+ # @param [RubyLint::Node] field The field that was referenced.
441
+ # @return [RubyLint::Node]
566
442
  #
567
- def on_mrhs_add_star(left, right)
568
- return on_mlhs_add_star(left, right)
443
+ def on_field(object, operator, field)
444
+ return Node.new(:field, [object, field], metadata)
569
445
  end
570
446
 
571
447
  ##
572
- # Called when a method call was prefixed with a `*` to indicate that the
573
- # values it returns should be expanded.
448
+ # Called when a method without parenthesis is called.
574
449
  #
575
- # @param [Array] left The variables to the left.
576
- # @param [RubyLint::Token::Token] right The variable to expand.
577
- # @return [Array]
450
+ # @see RubyLint::Parser#on_method_add_arg
578
451
  #
579
- def on_args_add_star(left, right)
580
- variables = left || []
581
-
582
- if right
583
- right.expand = true
584
-
585
- variables << right
586
- end
587
-
588
- return variables
589
- end
590
-
591
- ##
592
- # Called when a value is assigned to an object attribute.
593
- #
594
- # @param [RubyLint::Token::VariableToken] receiver The receiver of the
595
- # assignment.
596
- # @param [Symbol] operator The operator that was used to separate the
597
- # object and attribute.
598
- # @param [RubyLint::Token::Token] attribute The attribute to which the value
599
- # is assigned.
600
- # @return [RubyLint::Token::VariableToken]
601
- #
602
- def on_field(receiver, operator, attribute)
603
- return Token::AssignmentToken.new(
604
- :name => attribute.value,
605
- :line => attribute.line,
606
- :column => attribute.column,
607
- :type => attribute.type,
608
- :receiver => receiver,
609
- :operator => operator,
610
- :code => code(attribute.line)
611
- )
612
- end
613
-
614
- ##
615
- # Called when a (binary) operator operation is performed.
616
- #
617
- # @param [RubyLint::Token::Token] left The left hand side of the operator.
618
- # @param [Symbol] op The operator that was used.
619
- # @param [RubyLint::Token::Token] right The right hand side of the operator.
620
- # @return [RubyLint::Token::Token]
621
- #
622
- def on_binary(left, op, right)
623
- return Token::Token.new(
624
- :type => :binary,
625
- :value => [left, op, right],
626
- :line => lineno,
627
- :column => column,
628
- :code => code(lineno)
629
- )
630
- end
631
-
632
- ##
633
- # Called when an unary operator/operation is found.
634
- #
635
- # @param [Symbol] operator The unary operator.
636
- # @param [RubyLint::Token::Token] token The token after the unary operator.
637
- # @return [RubyLint::Token::Token]
638
- #
639
- def on_unary(operator, token)
640
- return Token::Token.new(
641
- :type => :unary,
642
- :value => [operator, token],
643
- :line => lineno,
644
- :column => column,
645
- :code => code(lineno)
452
+ def on_command(name, params)
453
+ return Node.new(
454
+ :method,
455
+ [name.children[0], on_params(params), nil, nil],
456
+ metadata(name)
646
457
  )
647
458
  end
648
459
 
649
460
  ##
650
- # Called when a set of parenthesis is found.
461
+ # Called when a method is invoked on an object.
651
462
  #
652
- # @param [Array] value The data inside the parenthesis.
653
- # @return [RubyLint::Token::Token]
463
+ # @param [RubyLint::Node] object The object the method was invoked on.
464
+ # @param [Symbol] operator The operator used for the method call.
465
+ # @param [RubyLint::Node] name The name of the method.
466
+ # @return [RubyLint::Node]
654
467
  #
655
- def on_paren(value)
656
- if value.is_a?(Array)
657
- return value[0]
658
- else
659
- return value
660
- end
468
+ def on_call(object, operator, name)
469
+ return Node.new(
470
+ :method,
471
+ [name.children[0], on_params, nil, object],
472
+ metadata(name)
473
+ )
661
474
  end
662
475
 
663
476
  ##
664
- # Called when a return statement is found.
477
+ # Called when a method is invoked on an object without the use of
478
+ # parenthesis.
665
479
  #
666
- # @param [Array] values The return values of the statement.
667
- # @return [RubyLint::Token::StatementToken]
480
+ # @see RubyLint::Parser#on_call
668
481
  #
669
- def on_return(values)
670
- source = code(lineno)
671
- col = calculate_column(source, 'return')
672
-
673
- return Token::StatementToken.new(
674
- :type => :return,
675
- :line => lineno,
676
- :column => col,
677
- :value => values,
678
- :code => source
679
- )
680
- end
482
+ def on_command_call(object, operator, name, params)
483
+ node = on_call(object, operator, name)
484
+ children = node.children.dup
485
+ children[1] = on_params(params)
681
486
 
682
- ##
683
- # Called when a while loop is found.
684
- #
685
- # @param [RubyLint::Token::Token|Array] statement The statement to
686
- # evaluate.
687
- # @param [RubyLint::Token::Token] value The body of the while loop.
688
- # @return [RubyLint::Token::StatementToken]
689
- #
690
- def on_while(statement, value)
691
- line = statement.is_a?(Array) ? statement[0].line : statement.line
692
- source = code(line)
693
- col = calculate_column(source, 'while')
694
-
695
- return Token::StatementToken.new(
696
- :type => :while,
697
- :statement => statement,
698
- :value => value,
699
- :line => line,
700
- :column => col,
701
- :code => source
702
- )
487
+ return node.updated(nil, children)
703
488
  end
704
489
 
705
490
  ##
706
- # Called when a for loop is found.
707
- #
708
- # @param [Array|RubyLint::Token::Token] variables A single token or array
709
- # of tokens for the variables to create for each iteration.
710
- # @param [RubyLint::Token::Token] enumerable The enumerable to iterate.
711
- # @param [Array] value The body of the for loop.
712
- # @return [RubyLint::Token::StatementToken]
491
+ # @param [RubyLint::Node] method The method that is called.
492
+ # @param [RubyLint::Node|Array] params Array of parameters passed to the
493
+ # method.
494
+ # @return [RubyLint::Node]
713
495
  #
714
- def on_for(variables, enumerable, value)
715
- variables = [variables] unless variables.is_a?(Array)
716
- source = code(variables[0].line)
717
- col = calculate_column(source, 'for')
718
-
719
- return Token::StatementToken.new(
720
- :type => :for,
721
- :statement => [variables, enumerable],
722
- :value => value,
723
- :column => col,
724
- :line => variables[0].line,
725
- :code => source
726
- )
727
- end
496
+ def on_method_add_arg(method, params)
497
+ children = method.children.dup
728
498
 
729
- ##
730
- # Called when an if statement is found.
731
- #
732
- # @param [RubyLint::Token::Token] statement The if statement to evaluate.
733
- # @param [Array] value Array containing the tokens of the code that will
734
- # be executed if the if statement evaluates to true.
735
- # @param [Array] rest Array containing the tokens for the elsif and else
736
- # statements (if any).
737
- # @return [RubyLint::Token::StatementToken]
738
- #
739
- def on_if(statement, value, rest)
740
- source = code(statement.line)
741
- col = calculate_column(source, 'if')
742
-
743
- else_statement = nil
744
- elsif_statements = []
745
-
746
- if rest and rest.respond_to?(:each)
747
- rest.each do |token|
748
- next if token.nil?
749
-
750
- if token.type == :elsif
751
- elsif_statements << token
752
- else
753
- else_statement = token
754
- end
755
- end
499
+ if !params.is_a?(Array)
500
+ children[1] = params
756
501
  end
757
502
 
758
- return Token::StatementToken.new(
759
- :type => :if,
760
- :statement => statement,
761
- :value => value,
762
- :line => statement.line,
763
- :column => col,
764
- :else => else_statement,
765
- :elsif => elsif_statements.reverse,
766
- :code => source
767
- )
503
+ return method.updated(nil, children)
768
504
  end
769
505
 
770
506
  ##
771
- # Called whne a tenary operator is found.
772
- #
773
- # @see RubyLint::Parser#on_if
507
+ # @param [Mixed] arguments
508
+ # @param [Mixed] block
774
509
  #
775
- def on_ifop(statement, value, else_statement)
776
- else_statement = Token::StatementToken.new(
777
- :type => :else,
778
- :value => [else_statement],
779
- :line => else_statement.line,
780
- :column => else_statement.column,
781
- :code => code(else_statement.line)
782
- )
783
-
784
- return Token::StatementToken.new(
785
- :type => :if,
786
- :statement => statement,
787
- :value => [value],
788
- :line => statement.line,
789
- :column => statement.column,
790
- :code => code(statement.line),
791
- :else => else_statement
792
- )
510
+ def on_args_add_block(arguments, block)
511
+ return on_params(arguments, nil, nil, nil, block)
793
512
  end
794
513
 
795
514
  ##
796
- # Called when an else statement is found.
797
- #
798
- # @param [Array] value The value of the statement.
799
- # @return [RubyLint::Token::StatementToken]
800
- #
801
- def on_else(value)
802
- return Token::StatementToken.new(
803
- :type => :else,
804
- :value => value,
805
- :column => column,
806
- :line => lineno,
807
- :code => code(lineno)
808
- )
809
- end
810
-
811
- ##
812
- # Called when an elsif statement is found.
813
- #
814
- # @param [RubyLint::Token::Token] statement The statement to evaluate.
815
- # @param [Array] value The value of the elsif statement.
816
- # @param [Array|RubyLint::Token::Token] list A list of else and elsif
817
- # statements.
515
+ # @param [Mixed] arguments
516
+ # @param [Mixed] splat
818
517
  # @return [Array]
819
518
  #
820
- def on_elsif(statement, value, list)
821
- source = code(statement.line)
822
- col = calculate_column(source, 'elsif')
823
-
824
- token = Token::StatementToken.new(
825
- :type => :elsif,
826
- :statement => statement,
827
- :value => value,
828
- :line => statement.line,
829
- :column => col,
830
- :code => source
831
- )
832
-
833
- unless list.is_a?(Array)
834
- list = [list]
835
- end
836
-
837
- list << token
838
- end
519
+ def on_args_add_star(arguments, splat)
520
+ # Ripper isn't exactly consistent with its output. In certain cases, such
521
+ # `*(foo = something_else)` splat will be set to an Array instead of the
522
+ # assignment node.
523
+ splat = splat[0] if splat.is_a?(Array)
839
524
 
840
- ##
841
- # Called when the body of a block of Ruby code is found (e.g. a method
842
- # definition or a begin/rescue block).
843
- #
844
- # @param [Array] value Array containing the tokens of the body/statement.
845
- # @param [Array] rescues An array of rescue statements.
846
- # @param [RubyLint::Token::StatementToken] else_statement The else statement
847
- # of the block.
848
- # @param [RubyLint::Token::StatementToken] ensure_statement The ensure
849
- # statement of the block.
850
- # @return [RubyLint::Token::BeginRescueToken]
851
- #
852
- def on_bodystmt(value, rescues, else_statement, ensure_statement)
853
- if rescues.nil? and else_statement.nil? and ensure_statement.nil?
854
- return value
855
- end
856
-
857
- return Token::BeginRescueToken.new(
858
- :type => :begin,
859
- :value => value,
860
- :rescue => (rescues || []).reverse.select { |t| !t.nil? },
861
- :ensure => ensure_statement,
862
- :else => else_statement,
863
- :line => lineno,
864
- :column => column,
865
- :code => code(lineno)
866
- )
525
+ return arguments << Node.new(:splat_argument, [splat], metadata(splat))
867
526
  end
868
527
 
869
528
  ##
870
- # Called when a rescue statement is found.
871
- #
872
- # @param [Array] exceptions An array of exceptions to catch.
873
- # @param [RubyLint::Token::Token] variable The variable in which to store
874
- # the exception details.
875
- # @param [Array] value The value of the rescue statement.
876
- # @param [Array|RubyLint::Token::Token] list A set of all the rescue tokens.
877
- # @return [RubyLint::Token::StatementToken]
878
- #
879
- def on_rescue(exceptions, variable, value, list)
880
- source = code(lineno)
881
- col = calculate_column(source, 'rescue')
882
-
883
- token = Token::StatementToken.new(
884
- :type => :rescue,
885
- :statement => [exceptions, variable],
886
- :line => lineno,
887
- :column => col,
888
- :value => value,
889
- :code => source
890
- )
891
-
892
- unless list.is_a?(Array)
893
- list = [list]
894
- end
895
-
896
- list << token
897
- end
529
+ # @param [RubyLint::Node] method The method node.
530
+ # @param [RubyLint::Node] block The block passed to the method.
531
+ # @return [RubyLint::Node]
532
+ #
533
+ def on_method_add_block(method, block)
534
+ children = method.children.dup
535
+ index = method.type == :super ? 1 : -2
536
+ children[index] = block
898
537
 
899
- ##
900
- # Called when a single line rescue statement (in the form of `[VALUE]
901
- # rescue [RESCUE VALUE]`) is found.
902
- #
903
- # @param [RubyLint::Token::Token|Array] value The body of the begin/rescue
904
- # statement.
905
- # @param [RubyLint::Token::Token] statement The statement to evaluate when the
906
- # data in `value` raised an exception.
907
- # @return [RubyLint::Token::BeginRescueToken]
908
- #
909
- def on_rescue_mod(value, statement)
910
- value = [value] unless value.is_a?(Array)
911
- statement = [statement] unless statement.is_a?(Array)
912
-
913
- return Token::BeginRescueToken.new(
914
- :type => :rescue,
915
- :rescue => statement,
916
- :value => value,
917
- :line => lineno,
918
- :column => column,
919
- :code => code(lineno)
920
- )
538
+ return method.updated(nil, children)
921
539
  end
922
540
 
923
541
  ##
924
- # Called when an ensure statement is found.
925
- #
926
- # @param [Array] value The value of the statement.
927
- # @return [RubyLint::Token::StatementToken]
928
- #
929
- def on_ensure(value)
930
- return Token::StatementToken.new(
931
- :type => :ensure,
932
- :value => value,
933
- :line => lineno,
934
- :column => column,
935
- :code => code(lineno)
542
+ # @param [RubyLint::Node] name The name of the method.
543
+ # @param [Array] params The parameters of the method.
544
+ # @param [Array] body The body of the method.
545
+ # @return [RubyLint::Node]
546
+ #
547
+ def on_def(name, params, body)
548
+ return Node.new(
549
+ :method_definition,
550
+ [name.children[0], params, nil, body],
551
+ metadata(name)
936
552
  )
937
553
  end
938
554
 
939
555
  ##
940
- # Called for an entire case/when/else block.
556
+ # Called when a method definition using a receiver is found.
941
557
  #
942
- # @param [RubyLint::Token::Token] statement The statement of the `case`
943
- # statement itself.
944
- # @param [Array] list Array containing the various when statements and
945
- # optionally an else statement.
946
- # @return [RubyLint::Token::CaseToken]
558
+ # @see RubyLint::Parser#on_def
947
559
  #
948
- def on_case(statement, list)
949
- when_statements = []
950
- else_statement = nil
951
- list = list.reject(&:nil?)
952
-
953
- line = statement.respond_to?(:line) ? statement.line : list[0].line
954
- source = code(line)
955
- col = calculate_column(source, 'case')
956
-
957
- if list and list.respond_to?(:each)
958
- list.each do |token|
959
- if token.type == :when
960
- when_statements << token
961
- else
962
- else_statement = token
963
- end
964
- end
965
- end
966
-
967
- return Token::CaseToken.new(
968
- :type => :case,
969
- :statement => statement,
970
- :else => else_statement,
971
- :when => when_statements.reverse,
972
- :line => line,
973
- :column => col,
974
- :code => source
560
+ def on_defs(receiver, operator, name, params, body)
561
+ return Node.new(
562
+ :method_definition,
563
+ [name.children[0], params, receiver, body],
564
+ metadata(name)
975
565
  )
976
566
  end
977
567
 
978
568
  ##
979
- # Called when a `when` statement is found.
569
+ # Called when a set of method parameters if found.
980
570
  #
981
- # @param [Array] statement Array of statements to evaluate.
982
- # @param [Array] body Array containing the tokens of the statement's body.
983
- # @param [Array] list The list of `when` tokens.
571
+ # @param [Array] params The specified parameters.
984
572
  # @return [Array]
985
573
  #
986
- def on_when(statement, body, list)
987
- source = code(statement[0].line)
988
- col = calculate_column(source, 'when')
989
-
990
- token = Token::StatementToken.new(
991
- :type => :when,
992
- :statement => statement,
993
- :value => body,
994
- :line => statement[0].line,
995
- :column => col,
996
- :code => source
997
- )
574
+ def on_params(*params)
575
+ if params[0].is_a?(Node) and params[0].type == :arguments
576
+ return params[0]
577
+ end
998
578
 
999
- unless list.is_a?(Array)
1000
- list = [list]
579
+ if params[1]
580
+ params[1] = remap_optional_arguments(params[1])
1001
581
  end
1002
582
 
1003
- list << token
1004
- end
583
+ params = group_arguments(params)
1005
584
 
1006
- ##
1007
- # Called when a unless statement is found.
1008
- #
1009
- # @param [RubyLint::Token::Token] statement The statement to evaluate.
1010
- # @param [Array] body The body of the unless statement.
1011
- # @param [RubyLint::Token::StatementToken] else_token An optional else
1012
- # statement.
1013
- # @return [RubyLint::Token::StatementToken]
1014
- #
1015
- def on_unless(statement, body, else_token)
1016
- source = code(statement.line)
1017
- col = calculate_column(source, 'unless')
1018
-
1019
- return Token::StatementToken.new(
1020
- :type => :unless,
1021
- :statement => statement,
1022
- :else => else_token,
1023
- :value => body,
1024
- :line => statement.line,
1025
- :column => col,
1026
- :code => source
1027
- )
585
+ return Node.new(:arguments, params, metadata)
1028
586
  end
1029
587
 
1030
588
  ##
1031
- # Called when an until statement is found.
1032
- #
1033
- # @see RubyLint::Parser#on_unless
589
+ # @param [RubyLint::Node] statement The statement to evaluate.
590
+ # @param [Array] body The body of the if statement.
591
+ # @param [Array|NilClass] rest The rest of the statement, includes the
592
+ # elsif and else statements.
593
+ # @return [RubyLint::Node]
1034
594
  #
1035
- def on_until(statement, body)
1036
- source = code(statement.line)
1037
- col = calculate_column(source, 'until')
595
+ def on_if(statement, body, rest = nil)
596
+ elsif_stmts = []
597
+ else_stmt = nil
1038
598
 
1039
- return Token::StatementToken.new(
1040
- :type => :until,
1041
- :statement => statement,
1042
- :value => body,
1043
- :line => statement.line,
1044
- :column => col,
1045
- :code => source
1046
- )
1047
- end
599
+ rest ||= []
600
+ rest = [rest] unless rest.is_a?(Array)
1048
601
 
1049
- ##
1050
- # Called when a call to `defined?()` is found.
1051
- #
1052
- # @param [RubyLint::Token::Token] token The token which is being checked.
1053
- # @return [RubyLint::Token::StatementToken]
1054
- #
1055
- def on_defined(token)
1056
- return Token::KeywordToken.new(
1057
- :name => 'defined?',
1058
- :parameters => [token],
1059
- :line => token.line,
1060
- :column => token.column,
1061
- :code => token.code
602
+ rest.compact.each do |node|
603
+ if node.type == :else
604
+ else_stmt = node
605
+ else
606
+ elsif_stmts << node
607
+ end
608
+ end
609
+
610
+ return Node.new(
611
+ :if,
612
+ [statement, body, elsif_stmts.reverse, else_stmt],
613
+ metadata
1062
614
  )
1063
615
  end
1064
616
 
1065
617
  ##
1066
- # Called when a call to `super` without parameters is found.
618
+ # Called when a ternary operator is found.
1067
619
  #
1068
- # @return [RubyLint::Token::MethodToken]
620
+ # @param [RubyLint::Node] statement The statement to evaluate.
621
+ # @param [RubyLint::Node] true_val The value to use when the statement
622
+ # evaluates to true.
623
+ # @param [RubyLint::Node] false_val The value to use when the statement
624
+ # evaluates to false.
625
+ # @return [RubyLint::Node]
1069
626
  #
1070
- def on_zsuper
1071
- return Token::KeywordToken.new(
1072
- :name => 'super',
1073
- :line => lineno,
1074
- :column => column,
1075
- :code => code(lineno)
627
+ def on_ifop(statement, true_val, false_val)
628
+ return Node.new(
629
+ :ternary,
630
+ [statement, true_val, false_val],
631
+ metadata
1076
632
  )
1077
633
  end
1078
634
 
1079
635
  ##
1080
- # Called when a call to `super` with parameters is found.
1081
- #
1082
- # @param [Array] params An array of parameters passed to the keyword.
1083
- # @return [RubyLint::Token::KeywordToken]
636
+ # @param [RubyLint::Node] statement The statement to evaluate.
637
+ # @param [Array] body The body of the statement.
638
+ # @param [Array] list Array containing the rest of the if statement.
639
+ # @return [RubyLint::Node]
1084
640
  #
1085
- def on_super(params)
1086
- token = on_zsuper
1087
- token.parameters = params
641
+ def on_elsif(statement, body, list)
642
+ node = Node.new(:elsif, [statement, body], metadata)
643
+ list = [list] unless list.is_a?(Array)
1088
644
 
1089
- return token
645
+ list << node
1090
646
  end
1091
647
 
1092
648
  ##
1093
- # Called when a `yield` keyword without parameters is found.
1094
- #
1095
- # @return [RubyLint::Token::KeywordToken]
649
+ # @param [Array|RubyLint::Node] variables The variables to create for each
650
+ # iteration.
651
+ # @param [RubyLint::Node] enumerator The value to iterate over.
652
+ # @param [Array] body The body of the statement.
653
+ # @return [RubyLint::Node]
1096
654
  #
1097
- def on_yield0
1098
- return Token::KeywordToken.new(
1099
- :name => 'yield',
1100
- :line => lineno,
1101
- :column => column,
1102
- :code => code(lineno)
655
+ def on_for(variables, enumerator, body)
656
+ variables = [variables] unless variables.is_a?(Array)
657
+ variables.map! { |n| n.updated(:local_variable) if n.identifier? }
658
+
659
+ return Node.new(
660
+ :for,
661
+ [variables, enumerator, body],
662
+ metadata(variables[0])
1103
663
  )
1104
664
  end
1105
665
 
1106
666
  ##
1107
- # Called when a `yield` keyword *with* parameters is found.
1108
- #
1109
- # @param [Array] params The parameters of the keyword.
667
+ # @param [Array] exceptions A list of exceptions to catch.
668
+ # @param [RubyLint::Variable|NilClass] variable The variable to store
669
+ # information in about the exception.
670
+ # @param [Array] body The body of the statement.
671
+ # @param [Array] list Array containing all the rescue, else and ensure
672
+ # statements.
673
+ # @return [RubyLint::Node]
1110
674
  #
1111
- def on_yield(params)
1112
- token = on_yield0
1113
- token.parameters = params
675
+ def on_rescue(exceptions, variable, body, list)
676
+ list = list.is_a?(Array) ? list : [list].compact
1114
677
 
1115
- return token
1116
- end
1117
-
1118
- ##
1119
- # Called when a variable is referenced.
1120
- #
1121
- # @param [RubyLint::Token::Token] variable The variable that was referenced.
1122
- # @return [RubyLint::Token::VariableToken]
1123
- #
1124
- def on_var_ref(variable)
1125
- return Token::VariableToken.new(
1126
- :line => variable.line,
1127
- :column => variable.column,
1128
- :name => variable.value,
1129
- :type => variable.type,
1130
- :code => code(variable.line)
1131
- )
1132
- end
678
+ if variable and variable.identifier?
679
+ variable = variable.updated(:local_variable)
680
+ end
1133
681
 
1134
- ##
1135
- # Called when a constant path reference is found.
1136
- #
1137
- # @param [Array] segments The path segments.
1138
- # @return [Array]
1139
- #
1140
- def on_const_path_ref(*segments)
1141
- return Token::VariableToken.new(
1142
- :name => segments.map { |t| t.name }.flatten,
1143
- :type => :constant_path,
1144
- :line => segments[0].line,
1145
- :column => segments[0].column,
1146
- :code => code(segments[-1].line)
682
+ list.unshift(
683
+ Node.new(:rescue, [nil, exceptions, variable, body], metadata)
1147
684
  )
1148
685
  end
1149
686
 
1150
687
  ##
1151
- # Called when a constant path is assigned.
1152
- #
1153
- # @see RubyLint::Parser#on_const_path_ref
1154
- #
1155
- def on_const_path_field(*segments)
1156
- return on_const_path_ref(*segments)
1157
- end
1158
-
1159
- ##
1160
- # Called when a new method is defined.
688
+ # @param [RubyLint::Node] statement The statement for which to catch
689
+ # errors.
690
+ # @param [RubyLint::Node] body The code to execute when an error was
691
+ # raised.
692
+ # @return [RubyLint::Node]
1161
693
  #
1162
- # @param [RubyLint::Token::Token] name Token containing details about the
1163
- # method name.
1164
- # @param [RubyLint::Token::ParametersToken] params Token containing details
1165
- # about the method parameters.
1166
- # @param [Array] body Array containing the tokens of the method's body.
1167
- # @return [RubyLint::Token::MethodDefinitionToken]
1168
- #
1169
- def on_def(name, params, body)
1170
- body = [body] unless body.is_a?(Array)
1171
-
1172
- return Token::MethodDefinitionToken.new(
1173
- :name => name.value,
1174
- :line => name.line,
1175
- :column => name.column,
1176
- :parameters => params,
1177
- :visibility => @visibility,
1178
- :value => body.select { |t| !t.nil? },
1179
- :code => code(name.line)
1180
- )
694
+ def on_rescue_mod(statement, body)
695
+ return Node.new(:rescue, [statement, nil, nil, body], metadata)
1181
696
  end
1182
697
 
1183
698
  ##
1184
- # Called when a method is defined on a specific constant/location
1185
- # (e.g. `self`).
1186
- #
1187
- # @param [RubyLint::Token::Token] receiver The object that the method was
1188
- # defined on.
1189
- # @param [RubyLint::Token::Token] operator The operator that was used to
1190
- # separate the receiver and method name.
1191
- # @param [RubyLint::Token::Token] name The name of the method.
1192
- # @param [RubyLint::Token::ParametersToken] params The method parameters.
1193
- # @param [Array] body The body of the method.
1194
- # @return [RubyLint::Token::MethodDefinitionToken]
699
+ # @param [RubyLint::Node] statement The statement to evaluate.
700
+ # @param [Array] body The body of the case block such as all the when
701
+ # statements.
702
+ # @return [RubyLint::Node]
1195
703
  #
1196
- def on_defs(receiver, operator, name, params, body)
1197
- token = on_def(name, params, body)
1198
- token.receiver = receiver
1199
- token.operator = operator
1200
-
1201
- return token
1202
- end
704
+ def on_case(statement, body)
705
+ when_statements = []
706
+ else_statement = nil
1203
707
 
1204
- ##
1205
- # Called when a set of method parameters is found. The order of the `args`
1206
- # parameter is the following:
1207
- #
1208
- # * 0: array of required parameters
1209
- # * 1: array of optional parameters
1210
- # * 2: the rest parameter (if any)
1211
- # * 3: array of "more" parameters (parameters set after the rest parameter)
1212
- # * 4: the block parameter (if any)
1213
- #
1214
- # @param [Array] args Array containing all the passed method parameters.
1215
- # @return [RubyLint::Token::ParametersToken]
1216
- #
1217
- def on_params(*args)
1218
- # Convert all the arguments from regular Token instances to VariableToken
1219
- # instances.
1220
- args.each_with_index do |arg, index|
1221
- # Required, optional and more parameters.
1222
- if arg.is_a?(Array)
1223
- args[index] = arg.map do |token|
1224
- value = nil
1225
-
1226
- if token.is_a?(Array)
1227
- value = token[1]
1228
- token = token[0]
1229
- end
1230
-
1231
- Token::VariableToken.new(
1232
- :name => token.value,
1233
- :value => value,
1234
- :line => token.line,
1235
- :column => token.column,
1236
- :type => token.type,
1237
- :code => code(token.line)
1238
- )
1239
- end
1240
- # Rest and block parameters.
1241
- elsif !arg.nil?
1242
- args[index] = Token::VariableToken.new(
1243
- :name => arg.value,
1244
- :line => arg.line,
1245
- :column => arg.column,
1246
- :type => arg.type,
1247
- :code => code(arg.line)
1248
- )
708
+ body.each do |node|
709
+ if node.type == :when
710
+ when_statements << node
711
+ else
712
+ else_statement = node
1249
713
  end
1250
714
  end
1251
715
 
1252
- return Token::ParametersToken.new(
1253
- :value => args[0],
1254
- :optional => args[1],
1255
- :rest => args[2],
1256
- :more => args[3],
1257
- :block => args[4]
716
+ return Node.new(
717
+ :case,
718
+ [statement, when_statements, else_statement],
719
+ metadata
1258
720
  )
1259
721
  end
1260
722
 
1261
723
  ##
1262
- # Called when a method call using parenthesis is found.
1263
- #
1264
- # @param [RubyLint::Token::Token] name The name of the method that was called.
1265
- # @param [Array] params The parameters of the method call.
1266
- # @return [RubyLint::Token::MethodToken]
724
+ # @param [RubyLint::Node|Array] values The values to match on.
725
+ # @param [RubyLint::Node] body The body of the statement.
726
+ # @param [RubyLint::Node|Array] list The list of other when and else nodes.
727
+ # @return [RubyLint::Node]
1267
728
  #
1268
- def on_method_add_arg(name, params)
1269
- if name.class == RubyLint::Token::MethodToken
1270
- name.parameters = params
729
+ def on_when(values, body, list)
730
+ list = [list].compact unless list.is_a?(Array)
731
+ values = [values] unless values.is_a?(Array)
1271
732
 
1272
- return name
1273
- end
733
+ node = Node.new(:when, [values, body], metadata)
1274
734
 
1275
- return Token::MethodToken.new(
1276
- :name => name.value,
1277
- :parameters => params,
1278
- :line => name.line,
1279
- :column => name.column,
1280
- :code => code(name.line)
1281
- )
735
+ list.unshift(node)
1282
736
  end
1283
737
 
1284
738
  ##
1285
- # Called when a block is passed to a method call.
739
+ # @return [RubyLint::Node]
1286
740
  #
1287
- # @param [RubyLint::Token::MethodToken] method Token class for the method that
1288
- # the block is passed to.
1289
- # @param [RubyLint::Token::BlockToken] block The block that was passed to the
1290
- # method.
1291
- # @return [RubyLint::Token::MethodToken]
1292
- #
1293
- def on_method_add_block(method, block)
1294
- method.block = block
1295
-
1296
- return method
741
+ def on_zsuper
742
+ return on_super(nil)
1297
743
  end
1298
744
 
745
+ private
746
+
1299
747
  ##
1300
- # Called when a class declaration is found.
748
+ # Returns a more readable version of a Ripper type name.
1301
749
  #
1302
- # @param [Array|RubyLint::Token::Token] name The name of the class.
1303
- # @param [Array|NilClass] parent The name of the parent class.
1304
- # @param [Array] body The body of the class.
1305
- # @return [RubyLint::Token::ClassToken]
750
+ # @param [Symbol] type The type to convert.
751
+ # @return [Symbol]
1306
752
  #
1307
- def on_class(name, parent, body)
1308
- name_segments = name.name.is_a?(Array) ? name.name : [name.name]
1309
- parent_segments = []
1310
-
1311
- if parent
1312
- parent_segments = parent.name.is_a?(Array) ? parent.name : [parent.name]
1313
- end
1314
-
1315
- body = body.is_a?(Array) ? body.flatten.select { |t| !t.nil? } : []
1316
-
1317
- @visibility = DEFAULT_VISIBILITY
1318
-
1319
- return Token::ClassToken.new(
1320
- :name => name_segments,
1321
- :parent => parent_segments,
1322
- :type => :class,
1323
- :value => body,
1324
- :line => name.line,
1325
- :column => name.column,
1326
- :code => name.code
1327
- )
753
+ def readable_type_name(type)
754
+ return TYPE_MAPPING.fetch(type, type)
1328
755
  end
1329
756
 
1330
757
  ##
1331
- # Called when a set of class methods are added using a `class << self`
1332
- # block.
758
+ # Returns a Hash containing metadata such as the line number and the file.
1333
759
  #
1334
- # @param [RubyLint::Token::VariableToken] receiver The receiver for all the
1335
- # methods.
1336
- # @param [Array] value The body of the block.
1337
- # @return [Array]
760
+ # @param [RubyLint::Node] node When set the line and column number will be
761
+ # extracted from this node.
762
+ # @return [Hash]
1338
763
  #
1339
- def on_sclass(receiver, value)
1340
- value.each_with_index do |token, index|
1341
- if token.respond_to?(:receiver)
1342
- token.receiver = receiver
1343
- end
1344
-
1345
- value[index] = token
1346
- end
1347
-
1348
- return value
1349
- end
764
+ def metadata(node = nil)
765
+ line = node ? node.line : lineno
766
+ col = node ? node.column : column
1350
767
 
1351
- ##
1352
- # Called when a module definition is found.
1353
- #
1354
- # @param [RubyLint::Token::Token|Array] name The name of the module, either a
1355
- # single token class or an array of token classes.
1356
- # @param [Array|NilClass] body The body of the module.
1357
- # @return [RubyLint::Token::Token]
1358
- #
1359
- def on_module(name, body)
1360
- name_segments = name.name.is_a?(Array) ? name.name : [name.name]
1361
-
1362
- return Token::Token.new(
1363
- :type => :module,
1364
- :name => name_segments,
1365
- :value => body,
1366
- :line => name.line,
1367
- :column => name.column,
1368
- :code => name.code
1369
- )
768
+ return {:line => line, :column => col, :file => @file}
1370
769
  end
1371
770
 
1372
771
  ##
1373
- # Called when a method call without parenthesis was found.
772
+ # Groups a set of parameters into nodes based on the indexes.
1374
773
  #
1375
- # @see RubyLint::Parser#on_method_add_arg
774
+ # @param [Array] nodes
775
+ # @return [Array]
1376
776
  #
1377
- def on_command(name, params)
1378
- return on_method_add_arg(name, params)
1379
- end
777
+ def group_arguments(nodes)
778
+ new_nodes = []
1380
779
 
1381
- ##
1382
- # Called when a method was invoked on an object.
1383
- #
1384
- # @param [RubyLint::Token::Token] receiver The object that the method was
1385
- # invoked on.
1386
- # @param [Symbol] operator The operator that was used to separate the
1387
- # receiver and method name.
1388
- # @param [RubyLint::Token::Token] name Token containing details about the
1389
- # method name.
1390
- # @return [RubyLint::Token::MethodToken]
1391
- #
1392
- def on_call(receiver, operator, name)
1393
- return Token::MethodToken.new(
1394
- :name => name.value,
1395
- :line => name.line,
1396
- :column => name.column,
1397
- :receiver => receiver,
1398
- :operator => operator,
1399
- :code => code(name.line)
1400
- )
1401
- end
780
+ nodes.each_with_index do |node, index|
781
+ if !node or (node.is_a?(Array) and node.empty?)
782
+ next
783
+ end
1402
784
 
1403
- ##
1404
- # Called when a method was invoked on an object without using parenthesis.
1405
- #
1406
- # @see RubyLint::Parser#on_call
1407
- # @param [Array] params The parameters passed to the method.
1408
- # @return [RubyLint::Token::MethodToken]
1409
- #
1410
- def on_command_call(receiver, operator, name, params)
1411
- return Token::MethodToken.new(
1412
- :name => name.value,
1413
- :line => name.line,
1414
- :column => name.column,
1415
- :receiver => receiver,
1416
- :operator => operator,
1417
- :parameters => params,
1418
- :code => code(name.line)
1419
- )
1420
- end
785
+ new_nodes << convert_argument_node(node, index)
786
+ end
1421
787
 
1422
- private
788
+ return new_nodes.flatten
789
+ end
1423
790
 
1424
791
  ##
1425
- # Returns a string containing the code for the specified line number.
792
+ # Remaps variable/value pairs of optional arguments into single nodes.
1426
793
  #
1427
- # @param [Fixnum|Bignum] line The line number.
1428
- # @return [String]
794
+ # @param [Array] nodes
795
+ # @return [Array]
1429
796
  #
1430
- def code(line)
1431
- return @lines[line - 1]
797
+ def remap_optional_arguments(nodes)
798
+ return nodes.map do |node|
799
+ node[0].updated(nil, [node[0].children[0], node[1]])
800
+ end
1432
801
  end
1433
802
 
1434
803
  ##
1435
- # Calculates the column position based on a given line and a stop string.
804
+ # Converts a parameter node to a type based on its index.
1436
805
  #
1437
- # @param [String] line The line of code to use for calculating the column
1438
- # number.
1439
- # @param [String] stop The string that indicates the start of the token.
1440
- # @return [Fixnum]
806
+ # @param [RubyLint::Node|Array] node
807
+ # @param [Numeric] index
808
+ # @return [Mixed]
1441
809
  #
1442
- def calculate_column(line, stop)
1443
- matches = line.match(/^(.+)#{stop}/)
1444
- number = 0
810
+ def convert_argument_node(node, index)
811
+ if node.is_a?(Array)
812
+ node = node.map { |n| convert_argument_node(n, index) }
813
+ else
814
+ if node.identifier?
815
+ node = node.updated(:local_variable)
816
+ end
1445
817
 
1446
- if matches and matches[1]
1447
- number = matches[1].to_i
818
+ if node.type != :splat_argument
819
+ node = Node.new(PARAMETER_INDEX_TYPES[index], [node])
820
+ end
1448
821
  end
1449
822
 
1450
- return number
823
+ return node
1451
824
  end
1452
825
  end # Parser
1453
826
  end # RubyLint