ruby-lint 0.0.1a

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.gitignore +5 -0
  2. data/.rbenv-version +1 -0
  3. data/.yardopts +10 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +19 -0
  6. data/MANIFEST +79 -0
  7. data/README.md +48 -0
  8. data/Rakefile +14 -0
  9. data/bin/rlint +6 -0
  10. data/doc/.gitkeep +0 -0
  11. data/doc/build/.gitkeep +0 -0
  12. data/doc/css/.gitkeep +0 -0
  13. data/doc/css/common.css +68 -0
  14. data/lib/rlint/analyze/coding_style.rb +407 -0
  15. data/lib/rlint/analyze/definitions.rb +244 -0
  16. data/lib/rlint/analyze/method_validation.rb +104 -0
  17. data/lib/rlint/analyze/shadowing_variables.rb +37 -0
  18. data/lib/rlint/analyze/undefined_variables.rb +99 -0
  19. data/lib/rlint/analyze/unused_variables.rb +103 -0
  20. data/lib/rlint/callback.rb +67 -0
  21. data/lib/rlint/cli.rb +167 -0
  22. data/lib/rlint/constant_importer.rb +102 -0
  23. data/lib/rlint/definition.rb +230 -0
  24. data/lib/rlint/formatter/text.rb +54 -0
  25. data/lib/rlint/helper/definition_resolver.rb +143 -0
  26. data/lib/rlint/helper/scoping.rb +138 -0
  27. data/lib/rlint/iterator.rb +193 -0
  28. data/lib/rlint/options.rb +58 -0
  29. data/lib/rlint/parser.rb +1252 -0
  30. data/lib/rlint/parser_error.rb +42 -0
  31. data/lib/rlint/report.rb +98 -0
  32. data/lib/rlint/token/assignment_token.rb +46 -0
  33. data/lib/rlint/token/begin_rescue_token.rb +57 -0
  34. data/lib/rlint/token/block_token.rb +17 -0
  35. data/lib/rlint/token/case_token.rb +44 -0
  36. data/lib/rlint/token/class_token.rb +24 -0
  37. data/lib/rlint/token/method_definition_token.rb +64 -0
  38. data/lib/rlint/token/method_token.rb +58 -0
  39. data/lib/rlint/token/parameters_token.rb +99 -0
  40. data/lib/rlint/token/regexp_token.rb +15 -0
  41. data/lib/rlint/token/statement_token.rb +69 -0
  42. data/lib/rlint/token/token.rb +162 -0
  43. data/lib/rlint/token/variable_token.rb +18 -0
  44. data/lib/rlint/version.rb +3 -0
  45. data/lib/rlint.rb +36 -0
  46. data/ruby-lint.gemspec +23 -0
  47. data/spec/benchmarks/memory.rb +52 -0
  48. data/spec/benchmarks/parse_parser.rb +16 -0
  49. data/spec/helper.rb +4 -0
  50. data/spec/rlint/analyze/coding_style.rb +224 -0
  51. data/spec/rlint/analyze/definitions/classes.rb +114 -0
  52. data/spec/rlint/analyze/definitions/methods.rb +91 -0
  53. data/spec/rlint/analyze/definitions/modules.rb +207 -0
  54. data/spec/rlint/analyze/definitions/variables.rb +103 -0
  55. data/spec/rlint/analyze/method_validation.rb +177 -0
  56. data/spec/rlint/analyze/shadowing_variables.rb +30 -0
  57. data/spec/rlint/analyze/undefined_variables.rb +230 -0
  58. data/spec/rlint/analyze/unused_variables.rb +225 -0
  59. data/spec/rlint/callback.rb +28 -0
  60. data/spec/rlint/constant_importer.rb +27 -0
  61. data/spec/rlint/definition.rb +96 -0
  62. data/spec/rlint/formatter/text.rb +21 -0
  63. data/spec/rlint/iterator.rb +452 -0
  64. data/spec/rlint/parser/arrays.rb +147 -0
  65. data/spec/rlint/parser/classes.rb +152 -0
  66. data/spec/rlint/parser/errors.rb +19 -0
  67. data/spec/rlint/parser/hashes.rb +136 -0
  68. data/spec/rlint/parser/methods.rb +249 -0
  69. data/spec/rlint/parser/modules.rb +49 -0
  70. data/spec/rlint/parser/objects.rb +39 -0
  71. data/spec/rlint/parser/operators.rb +75 -0
  72. data/spec/rlint/parser/procs.rb +113 -0
  73. data/spec/rlint/parser/ranges.rb +49 -0
  74. data/spec/rlint/parser/regexp.rb +31 -0
  75. data/spec/rlint/parser/scalars.rb +93 -0
  76. data/spec/rlint/parser/statements.rb +550 -0
  77. data/spec/rlint/parser/variables.rb +181 -0
  78. data/spec/rlint/report.rb +30 -0
  79. data/task/test.rake +6 -0
  80. metadata +188 -0
@@ -0,0 +1,99 @@
1
+ module Rlint
2
+ module Token
3
+ ##
4
+ # Token class that contains details about the parameters of a method.
5
+ #
6
+ # The following attributes are used:
7
+ #
8
+ # * value: contains the required parameters (aliased as `#required()`)
9
+ # * optional: contains all optional parameters
10
+ # * rest: contains the rest parameter (if any)
11
+ # * more: contains all more parameters (parameters specified after a rest
12
+ # parameter).
13
+ # * block: contains the block parameter (if any)
14
+ #
15
+ class ParametersToken < Token
16
+ ##
17
+ # An array of optional parameters.
18
+ #
19
+ # @return [Array]
20
+ #
21
+ attr_accessor :optional
22
+
23
+ ##
24
+ # The rest parameter (if any).
25
+ #
26
+ # @return [Rlint::Token::Token]
27
+ #
28
+ attr_accessor :rest
29
+
30
+ ##
31
+ # An array of more parameters.
32
+ #
33
+ # @return [Array]
34
+ #
35
+ attr_accessor :more
36
+
37
+ ##
38
+ # The block parameter (if any).
39
+ #
40
+ # @return [Rlint::Token::Token]
41
+ #
42
+ attr_accessor :block
43
+
44
+ ##
45
+ # @see Rlint::Token::Token#initialize
46
+ #
47
+ def initialize(*args)
48
+ @optional = []
49
+ @more = []
50
+ @value = []
51
+
52
+ super
53
+ end
54
+
55
+ ##
56
+ # @see Rlint::Token::Token#child_nodes
57
+ #
58
+ def child_nodes
59
+ nodes = super
60
+
61
+ if @optional
62
+ nodes << @optional
63
+ end
64
+
65
+ if @rest
66
+ nodes << [@rest]
67
+ end
68
+
69
+ if @more
70
+ nodes << @more
71
+ end
72
+
73
+ if @block
74
+ nodes << [@block]
75
+ end
76
+
77
+ return nodes.select { |array| array.length > 0 }
78
+ end
79
+
80
+ ##
81
+ # Executes the provided block for every parameter of the method. The
82
+ # order in which parameters are processed is the following:
83
+ #
84
+ # 1. Required parameters
85
+ # 2. Optional parameters
86
+ # 3. Rest parameters
87
+ # 4. "More" parameters
88
+ # 5. Block parameters
89
+ #
90
+ def each
91
+ params = [@value, @optional, @rest, @more, @block].select do |p|
92
+ !p.nil?
93
+ end
94
+
95
+ params.flatten.each { |param| yield param }
96
+ end
97
+ end # ParametersToken
98
+ end # Token
99
+ end # Rlint
@@ -0,0 +1,15 @@
1
+ module Rlint
2
+ module Token
3
+ ##
4
+ # Token class for storing information about regular expressions.
5
+ #
6
+ class RegexpToken < Token
7
+ ##
8
+ # Array containing the modes of the regular expression.
9
+ #
10
+ # @return [Array]
11
+ #
12
+ attr_accessor :modes
13
+ end # RegexpToken
14
+ end # Token
15
+ end # Rlint
@@ -0,0 +1,69 @@
1
+ module Rlint
2
+ module Token
3
+ ##
4
+ # Token class for storing information about statements such as `return`
5
+ # statements and `elsif` statements.
6
+ #
7
+ # @since 2012-08-08
8
+ #
9
+ class StatementToken < Token
10
+ ##
11
+ # The value of the statement in case of `if` and `elsif` statements.
12
+ #
13
+ # @return [Rlint::Token::Token|Array]
14
+ #
15
+ attr_accessor :statement
16
+
17
+ ##
18
+ # The content of the `else` statement.
19
+ #
20
+ # @return [Rlint::Token::StatementToken]
21
+ #
22
+ attr_accessor :else
23
+
24
+ ##
25
+ # Array containing the `elsif` statement in their original order.
26
+ #
27
+ # @return [Array]
28
+ #
29
+ attr_accessor :elsif
30
+
31
+ ##
32
+ # @see Rlint::Token::Token#initialize
33
+ #
34
+ def initialize(*args)
35
+ @type = :statement
36
+ @elsif = []
37
+
38
+ super
39
+ end
40
+
41
+ ##
42
+ # @see Rlint::Token::Token#child_nodes
43
+ #
44
+ def child_nodes
45
+ nodes = []
46
+
47
+ if @statement
48
+ if @statement.is_a?(Array)
49
+ nodes << @statement.flatten
50
+ else
51
+ nodes << [@statement]
52
+ end
53
+ end
54
+
55
+ nodes += super
56
+
57
+ if @elsif
58
+ nodes << @elsif
59
+ end
60
+
61
+ if @else
62
+ nodes << [@else]
63
+ end
64
+
65
+ return nodes.select { |array| array.length > 0 }
66
+ end
67
+ end # StatementToken
68
+ end # Token
69
+ end # Rlint
@@ -0,0 +1,162 @@
1
+ module Rlint
2
+ module Token
3
+ ##
4
+ # Generic token class used for data that doesn't require its own specific
5
+ # token.
6
+ #
7
+ # @since 2012-07-29
8
+ #
9
+ class Token
10
+ ##
11
+ # Hash containing various Ripper types and the Rlint types to use
12
+ # instead.
13
+ #
14
+ # @since 2012-07-29
15
+ # @return [Hash]
16
+ #
17
+ TYPE_MAPPING = {
18
+ :ident => :identifier,
19
+ :gvar => :global_variable,
20
+ :ivar => :instance_variable,
21
+ :cvar => :class_variable,
22
+ :const => :constant,
23
+ :int => :integer,
24
+ :float => :float,
25
+ :tstring_content => :string,
26
+ :label => :symbol,
27
+ :kw => :keyword
28
+ }
29
+
30
+ ##
31
+ # The name of the token. For example, when the token is an identifier
32
+ # this value is set to `:ident`.
33
+ #
34
+ # @since 2012-07-29
35
+ # @return [String]
36
+ #
37
+ attr_accessor :name
38
+
39
+ ##
40
+ # The value of the token. For example, if the token is a variable this
41
+ # attribute is set to the token for the variable's value.
42
+ #
43
+ # @since 2012-07-29
44
+ # @return [Rlint::Token::Token]
45
+ #
46
+ attr_accessor :value
47
+
48
+ ##
49
+ # The type of token. For example, if the token is a local variable then
50
+ # this value is set to `:local_variable`.
51
+ #
52
+ # @since 2012-07-29
53
+ # @return [Symbol]
54
+ #
55
+ attr_reader :type
56
+
57
+ ##
58
+ # The line number on which the token was defined.
59
+ #
60
+ # @since 2012-07-29
61
+ # @return [Fixnum|Bignum]
62
+ #
63
+ attr_accessor :line
64
+
65
+ ##
66
+ # The column number on which the token was defined.
67
+ #
68
+ # @since 2012-07-29
69
+ # @return [Fixnum|Bignum]
70
+ #
71
+ attr_accessor :column
72
+
73
+ ##
74
+ # The code of the current line.
75
+ #
76
+ # @return [String]
77
+ #
78
+ attr_accessor :code
79
+
80
+ ##
81
+ # The key, index or object member that was accessed from the token.
82
+ #
83
+ # @since 2012-08-24
84
+ # @return [Array]
85
+ #
86
+ attr_accessor :key
87
+
88
+ ##
89
+ # The name of the event to call when iterating over an AST. Set to the
90
+ # value of {Rlint::Token::Token#type} unless specified otherwise.
91
+ #
92
+ # @return [Symbol]
93
+ #
94
+ attr_reader :event
95
+
96
+ ##
97
+ # Creates a new instance of the token and sets various instance variables
98
+ # based on the specified hash.
99
+ #
100
+ # @since 2012-07-29
101
+ # @param [Hash] options A hash containing various instance variables to
102
+ # set and their values. For a variable to be set it requires a
103
+ # corresponding public getter mehtod to be set.
104
+ #
105
+ def initialize(options = {})
106
+ options.each do |key, value|
107
+ if respond_to?(key)
108
+ instance_variable_set("@#{key}", value)
109
+ end
110
+ end
111
+
112
+ if TYPE_MAPPING[@type]
113
+ @type = TYPE_MAPPING[@type]
114
+ end
115
+
116
+ @event = @type
117
+
118
+ # Remove NilClass instances from the `value` array, these serve no
119
+ # useful purpose.
120
+ @value.select! { |t| !t.nil? } if @value.is_a?(Array)
121
+ end
122
+
123
+ ##
124
+ # Sets the type of the token and updates the event name accordingly.
125
+ #
126
+ # @param [Symbol] type The new type of the token.
127
+ #
128
+ def type=(type)
129
+ if TYPE_MAPPING[type]
130
+ type = TYPE_MAPPING[type]
131
+ end
132
+
133
+ @type = type
134
+ @event = type
135
+ end
136
+
137
+ ##
138
+ # Returns an array containing all the child nodes that can be iterated by
139
+ # {Rlint::Iterator}.
140
+ #
141
+ # @return [Array]
142
+ #
143
+ def child_nodes
144
+ nodes = []
145
+
146
+ if @value
147
+ if @value.is_a?(Array)
148
+ nodes << @value
149
+ else
150
+ nodes << [@value]
151
+ end
152
+ end
153
+
154
+ if @key
155
+ nodes << @key
156
+ end
157
+
158
+ return nodes
159
+ end
160
+ end # Token
161
+ end # Token
162
+ end # Rlint
@@ -0,0 +1,18 @@
1
+ module Rlint
2
+ module Token
3
+ ##
4
+ # Token class used for storing information about variable references.
5
+ #
6
+ class VariableToken < Token
7
+ ##
8
+ # @see Rlint::Token::Token#initialize
9
+ #
10
+ def initialize(*args)
11
+ super
12
+
13
+ @type = :local_variable if @type == :identifier
14
+ @event = @type
15
+ end
16
+ end # VariableToken
17
+ end # Token
18
+ end # Rlint
@@ -0,0 +1,3 @@
1
+ module Rlint
2
+ VERSION = '0.0.1a'
3
+ end # Rlint
data/lib/rlint.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'ripper'
2
+
3
+ unless $:.include?(File.expand_path('../', __FILE__))
4
+ $:.unshift(File.expand_path('../', __FILE__))
5
+ end
6
+
7
+ require 'rlint/version'
8
+ require 'rlint/parser'
9
+ require 'rlint/token/token'
10
+ require 'rlint/token/variable_token'
11
+ require 'rlint/token/statement_token'
12
+ require 'rlint/token/begin_rescue_token'
13
+ require 'rlint/token/method_definition_token'
14
+ require 'rlint/token/parameters_token'
15
+ require 'rlint/token/method_token'
16
+ require 'rlint/token/block_token'
17
+ require 'rlint/token/assignment_token'
18
+ require 'rlint/token/case_token'
19
+ require 'rlint/token/regexp_token'
20
+ require 'rlint/token/class_token'
21
+ require 'rlint/parser_error'
22
+ require 'rlint/iterator'
23
+ require 'rlint/callback'
24
+ require 'rlint/report'
25
+ require 'rlint/definition'
26
+ require 'rlint/constant_importer'
27
+ require 'rlint/formatter/text'
28
+ require 'rlint/helper/scoping'
29
+ require 'rlint/helper/definition_resolver'
30
+ require 'rlint/analyze/coding_style'
31
+ require 'rlint/analyze/definitions'
32
+ require 'rlint/analyze/unused_variables'
33
+ require 'rlint/analyze/undefined_variables'
34
+ require 'rlint/analyze/shadowing_variables'
35
+ require 'rlint/analyze/method_validation'
36
+ require 'rlint/options'
data/ruby-lint.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../lib/rlint/version', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'ruby-lint'
5
+ s.version = Rlint::VERSION
6
+ s.date = '2012-11-12'
7
+ s.authors = ['Yorick Peterse']
8
+ s.email = 'yorickpeterse@gmail.com'
9
+ s.summary = 'Static code analysis tool and linter for Ruby'
10
+ s.homepage = 'https://github.com/yorickpeterse/rlint/'
11
+ s.description = s.summary
12
+ s.executables = ['rlint']
13
+
14
+ s.files = File.read(File.expand_path('../MANIFEST', __FILE__)).split("\n")
15
+
16
+ s.has_rdoc = 'yard'
17
+ s.required_ruby_version = '>= 1.9.2'
18
+
19
+ s.add_development_dependency('rake', ['>= 0.9.2.2'])
20
+ s.add_development_dependency('redcarpet', ['>= 2.1.1'])
21
+ s.add_development_dependency('bacon', ['>= 1.1.0'])
22
+ s.add_development_dependency('yard', ['>= 0.8.2.1'])
23
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path('../../../lib/rlint', __FILE__)
2
+
3
+ # This file benchmarks the memory increase after parsing a particular Rlint
4
+ # file and performing code analysis on the resulting tokens.
5
+ #
6
+ # For each iteration (the amount is set in the "AMOUNT" environment variable)
7
+ # the increase is measured. Once finished the average increase is displayed as
8
+ # well as the total memory usage at the end of the script.
9
+
10
+ def memory_usage
11
+ return `ps -o rss= #{Process.pid}`.strip.to_i
12
+ end
13
+
14
+ def benchmark_memory
15
+ start_memory = memory_usage
16
+
17
+ yield
18
+
19
+ return memory_usage - start_memory
20
+ end
21
+
22
+ memory_kb = 0.0
23
+ amount = ENV['AMOUNT'] ? ENV['AMOUNT'].to_i : 100
24
+ path = File.expand_path('../../../lib/rlint/parser.rb', __FILE__)
25
+ code = File.read(path, File.size(path))
26
+
27
+ amount.times do
28
+ memory_kb += benchmark_memory do
29
+ tokens = Rlint::Parser.new(code, path).parse
30
+ iterator = Rlint::Iterator.new
31
+
32
+ iterator.bind(Rlint::Analyze::CodingStyle)
33
+ iterator.bind(Rlint::Analyze::Definitions)
34
+
35
+ iterator.run(tokens)
36
+ end
37
+ end
38
+
39
+ memory_kb /= amount
40
+ memory_mb = memory_kb / 1024
41
+ memory_end_kb = memory_usage
42
+ memory_end_mb = memory_end_kb / 1024
43
+
44
+ puts "Average memory increase for each iteration (total of #{amount})"
45
+ puts
46
+ puts "Kilobytes: #{memory_kb.round}"
47
+ puts "Megabytes: #{memory_mb.round(2)}"
48
+ puts
49
+ puts 'End memory usage'
50
+ puts
51
+ puts "Kilobytes: #{memory_end_kb.round}"
52
+ puts "Megabytes: #{memory_end_mb.round(2)}"