ruby-lint 0.9.1 → 1.0.0.pre.preview1

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CONTRIBUTING.md +9 -11
  4. data/Gemfile +6 -3
  5. data/MANIFEST +7 -1
  6. data/README.md +15 -24
  7. data/benchmark/bootup.rb +13 -0
  8. data/checksum/ruby-lint-0.9.1.gem.sha512 +1 -0
  9. data/doc/code_analysis.md +20 -0
  10. data/doc/css/common.css +1 -0
  11. data/doc/images/flow.png +0 -0
  12. data/lib/ruby-lint.rb +1 -3
  13. data/lib/ruby-lint/analysis/base.rb +12 -2
  14. data/lib/ruby-lint/analysis/undefined_variables.rb +3 -2
  15. data/lib/ruby-lint/analysis/unused_variables.rb +3 -2
  16. data/lib/ruby-lint/ast/node.rb +1 -1
  17. data/lib/ruby-lint/benchmark/average.rb +115 -0
  18. data/lib/ruby-lint/cli/analyze.rb +19 -1
  19. data/lib/ruby-lint/constant_loader.rb +1 -3
  20. data/lib/ruby-lint/constant_path.rb +112 -0
  21. data/lib/ruby-lint/definition_builder/base.rb +0 -2
  22. data/lib/ruby-lint/definition_builder/ruby_module.rb +1 -1
  23. data/lib/ruby-lint/definitions/core/array.rb +304 -73
  24. data/lib/ruby-lint/definitions/core/fixnum.rb +575 -19
  25. data/lib/ruby-lint/definitions/core/float.rb +2650 -95
  26. data/lib/ruby-lint/definitions/core/hash.rb +926 -85
  27. data/lib/ruby-lint/definitions/core/ruby_copyright.rb +3 -1
  28. data/lib/ruby-lint/definitions/core/ruby_description.rb +3 -1
  29. data/lib/ruby-lint/definitions/core/ruby_engine.rb +3 -1
  30. data/lib/ruby-lint/definitions/core/ruby_patchlevel.rb +3 -1
  31. data/lib/ruby-lint/definitions/core/ruby_platform.rb +3 -1
  32. data/lib/ruby-lint/definitions/core/ruby_release_date.rb +3 -1
  33. data/lib/ruby-lint/definitions/core/ruby_version.rb +3 -1
  34. data/lib/ruby-lint/definitions/core/string.rb +847 -134
  35. data/lib/ruby-lint/definitions/core/string_io.rb +370 -25
  36. data/lib/ruby-lint/definitions/core/struct.rb +611 -146
  37. data/lib/ruby-lint/file_loader.rb +5 -6
  38. data/lib/ruby-lint/file_scanner.rb +44 -11
  39. data/lib/ruby-lint/inspector.rb +12 -2
  40. data/lib/ruby-lint/runner.rb +6 -2
  41. data/lib/ruby-lint/version.rb +1 -1
  42. data/lib/ruby-lint/virtual_machine.rb +19 -5
  43. data/ruby-lint.gemspec +1 -3
  44. data/spec/ruby-lint/analysis/argument_amount_spec.rb +5 -5
  45. data/spec/ruby-lint/analysis/base_spec.rb +4 -0
  46. data/spec/ruby-lint/analysis/shadowing_variables_spec.rb +4 -4
  47. data/spec/ruby-lint/analysis/undefined_methods_spec.rb +6 -6
  48. data/spec/ruby-lint/analysis/undefined_variables_spec.rb +5 -5
  49. data/spec/ruby-lint/analysis/unused_variables_spec.rb +12 -12
  50. data/spec/ruby-lint/cli/analyze_spec.rb +10 -0
  51. data/spec/ruby-lint/constant_path.rb +63 -0
  52. data/spec/ruby-lint/definition/ruby_object_spec.rb +2 -2
  53. data/spec/ruby-lint/report_spec.rb +2 -2
  54. data/spec/ruby-lint/runner_spec.rb +17 -0
  55. data/spec/ruby-lint/virtual_machine/assignments/assignment_arguments_spec.rb +14 -0
  56. data/spec/ruby-lint/virtual_machine/assignments/constants_spec.rb +23 -0
  57. data/spec/ruby-lint/virtual_machine/location_spec.rb +4 -4
  58. data/spec/ruby-lint/virtual_machine/method_call_tracking_spec.rb +4 -4
  59. data/task/build.rake +2 -7
  60. data/task/doc.rake +3 -1
  61. data/task/generate.rake +3 -0
  62. metadata +20 -36
  63. checksums.yaml.gz.asc +0 -17
  64. data.tar.gz.asc +0 -17
  65. data/lib/ruby-lint/helper/constant_paths.rb +0 -50
  66. metadata.gz.asc +0 -17
@@ -27,8 +27,6 @@ module RubyLint
27
27
  # @return [Set]
28
28
  #
29
29
  class FileLoader < Iterator
30
- include Helper::ConstantPaths
31
-
32
30
  attr_reader :file_scanner, :parser, :nodes, :comments, :debug, :paths
33
31
 
34
32
  ##
@@ -45,9 +43,10 @@ module RubyLint
45
43
  # @param [RubyLint::AST::Node] node
46
44
  #
47
45
  def on_const(node)
48
- segments = constant_segments(node)
49
- constant_path = segments.join('::')
50
- files = file_scanner.scan(constant_path)
46
+ const_path = ConstantPath.new(node)
47
+
48
+ files = file_scanner.scan(const_path.to_s)
49
+ last_name = const_path.constant_segments.last.last
51
50
 
52
51
  paths << node.file
53
52
 
@@ -58,7 +57,7 @@ module RubyLint
58
57
 
59
58
  debug_message("Processing extra file: #{path}")
60
59
 
61
- process_file(segments[-1], path)
60
+ process_file(last_name, path)
62
61
  end
63
62
  end
64
63
 
@@ -23,6 +23,13 @@ module RubyLint
23
23
 
24
24
  @directories = directories
25
25
  @ignore = ignore || []
26
+
27
+ # Hash that will contain the matching file paths for a given constant.
28
+ @constant_paths_cache = {}
29
+
30
+ # Globbing all files at once and then comparing those results is faster
31
+ # than running a Dir.glob for every call to #scan.
32
+ @glob_cache = Dir.glob("#{directories.join(',')}/**/*.rb")
26
33
  end
27
34
 
28
35
  ##
@@ -34,17 +41,31 @@ module RubyLint
34
41
  # @return [Array]
35
42
  #
36
43
  def scan(constant)
37
- segment = constant_to_path(constant)
38
- paths = Dir.glob(glob_pattern(segment))
44
+ unless constant_paths_cached?(constant)
45
+ build_constant_paths_cache(constant)
46
+ end
47
+
48
+ return @constant_paths_cache[constant]
49
+ end
50
+
51
+ private
52
+
53
+ ##
54
+ # Searches all the files that could potentially define the given constant
55
+ # and caches them.
56
+ #
57
+ # @param [String] constant
58
+ #
59
+ def build_constant_paths_cache(constant)
60
+ paths = match_globbed_files(constant_to_path(constant))
39
61
 
40
62
  # Lets see if we can find anything when using dashes for the directory
41
63
  # names instead of underscores.
42
64
  if paths.empty?
43
- segment = constant_to_dashed_path(constant)
44
- paths = Dir.glob(glob_pattern(segment))
65
+ paths = match_globbed_files(constant_to_dashed_path(constant))
45
66
  end
46
67
 
47
- paths.map! { |path| File.expand_path(path) }
68
+ paths.map! { |p| File.expand_path(p) }
48
69
 
49
70
  ignore.each do |pattern|
50
71
  paths.reject! do |path|
@@ -52,23 +73,35 @@ module RubyLint
52
73
  end
53
74
  end
54
75
 
55
- # Ensure that the order is from top-level -> deeply nested files instead
56
- # of a random order.
76
+ # Ensure that the order is from top-level -> deeply nested files
77
+ # instead of a random order.
57
78
  paths.sort! do |left, right|
58
79
  left.length <=> right.length
59
80
  end
60
81
 
61
- return paths
82
+ @constant_paths_cache[constant] = paths
62
83
  end
63
84
 
64
- private
85
+ ##
86
+ # @return [Array]
87
+ #
88
+ def match_globbed_files(segment)
89
+ return @glob_cache.select { |p| p.include?(segment) }
90
+ end
91
+
92
+ ##
93
+ # @return [TrueClass|FalseClass]
94
+ #
95
+ def constant_paths_cached?(constant)
96
+ return @constant_paths_cache.key?(constant)
97
+ end
65
98
 
66
99
  ##
67
100
  # @param [String] constant
68
101
  # @return [String]
69
102
  #
70
103
  def constant_to_path(constant)
71
- return constant.gsub('::', '/').snake_case
104
+ return constant.gsub('::', '/').snake_case + '.rb'
72
105
  end
73
106
 
74
107
  ##
@@ -79,7 +112,7 @@ module RubyLint
79
112
  last = segments[-1]
80
113
  path = segments[0..-2].join('/').snake_case.gsub('_', '-')
81
114
 
82
- return "#{path}/#{last.snake_case}"
115
+ return "#{path}/#{last.snake_case}.rb"
83
116
  end
84
117
 
85
118
  ##
@@ -132,9 +132,19 @@ module RubyLint
132
132
  # @return [Array]
133
133
  #
134
134
  def get_methods(getter = :methods)
135
- diff = constant.send(getter) - Object.send(getter)
135
+ diff = constant.send(getter) - Object.send(getter)
136
+ methods = diff | constant.send(getter, false)
137
+
138
+ # If the constant manually defines the initialize method (= private)
139
+ # we'll also want to include it.
140
+ if getter == :instance_methods \
141
+ and constant.is_a?(Class) \
142
+ and constant.private_method_defined?(:initialize) \
143
+ and constant.instance_method(:initialize).source_location
144
+ methods = methods | [:initialize]
145
+ end
136
146
 
137
- return diff | constant.send(getter, false)
147
+ return methods
138
148
  end
139
149
 
140
150
  ##
@@ -144,7 +144,7 @@ module RubyLint
144
144
  :level => :error,
145
145
  :message => diagnostic.message,
146
146
  :line => diagnostic.location.line,
147
- :column => diagnostic.location.column,
147
+ :column => diagnostic.location.column + 1,
148
148
  :file => diagnostic.location.source_buffer.name
149
149
  )
150
150
  end
@@ -170,7 +170,11 @@ module RubyLint
170
170
  # @param [RubyLint::Report] report
171
171
  #
172
172
  def run_analysis(ast, vm, report)
173
- configuration.analysis_classes.each do |const|
173
+ classes = configuration.analysis_classes.select do |const|
174
+ const.analyze?(ast, vm)
175
+ end
176
+
177
+ classes.each do |const|
174
178
  instance = const.new(:vm => vm, :report => report)
175
179
  instance.iterate(ast)
176
180
  end
@@ -1,3 +1,3 @@
1
1
  module RubyLint
2
- VERSION = '0.9.1'
2
+ VERSION = '1.0.0-preview1'
3
3
  end # RubyLint
@@ -70,8 +70,6 @@ module RubyLint
70
70
  # @return [RubyLint::Docstring::Mapping]
71
71
  #
72
72
  class VirtualMachine < Iterator
73
- include Helper::ConstantPaths
74
-
75
73
  attr_reader :associations,
76
74
  :comments,
77
75
  :definitions,
@@ -99,7 +97,17 @@ module RubyLint
99
97
  #
100
98
  # @return [Array]
101
99
  #
102
- PRIMITIVES = [:int, :float, :str, :sym, :true, :false, :nil]
100
+ PRIMITIVES = [
101
+ :int,
102
+ :float,
103
+ :str,
104
+ :sym,
105
+ :true,
106
+ :false,
107
+ :nil,
108
+ :erange,
109
+ :irange
110
+ ]
103
111
 
104
112
  ##
105
113
  # Returns a Hash containing the method call evaluators to use for `(send)`
@@ -241,7 +249,7 @@ module RubyLint
241
249
  scope = current_scope
242
250
 
243
251
  if node.children[0]
244
- scope = resolve_constant_path(node.children[0])
252
+ scope = ConstantPath.new(node.children[0]).resolve(current_scope)
245
253
 
246
254
  return unless scope
247
255
  end
@@ -881,6 +889,12 @@ Received: #{arguments.length}
881
889
 
882
890
  buffer_assignment_value(variable.value)
883
891
 
892
+ # Primarily used by #after_send to support variable assignments as method
893
+ # call arguments.
894
+ if value and !value_stack.empty?
895
+ value_stack.push(value)
896
+ end
897
+
884
898
  add_variable(variable)
885
899
  end
886
900
 
@@ -969,7 +983,7 @@ Received: #{arguments.length}
969
983
  #
970
984
  def definition_for_node(node)
971
985
  if node.const? and node.children[0]
972
- definition = resolve_constant_path(node)
986
+ definition = ConstantPath.new(node).resolve(current_scope)
973
987
  else
974
988
  definition = current_scope.lookup(node.type, node.name)
975
989
  end
@@ -30,15 +30,13 @@ using the handle "yorickpeterse".
30
30
  s.required_ruby_version = '>= 1.9.3'
31
31
 
32
32
  s.add_dependency 'parser', ['>= 2.0.0']
33
- s.add_dependency 'racc', ['>= 1.4.10']
34
- s.add_dependency 'slop'
33
+ s.add_dependency 'slop', ['~> 3.4', '>= 3.4.7']
35
34
 
36
35
  s.add_development_dependency 'rake'
37
36
  s.add_development_dependency 'rspec', ['>= 2.14']
38
37
  s.add_development_dependency 'yard'
39
38
  s.add_development_dependency 'pry-rescue'
40
39
  s.add_development_dependency 'simplecov'
41
- s.add_development_dependency 'rubygems-openpgp'
42
40
  s.add_development_dependency 'coveralls'
43
41
  s.add_development_dependency 'json'
44
42
  s.add_development_dependency 'kramdown'
@@ -15,7 +15,7 @@ example
15
15
  entry.is_a?(RubyLint::Report::Entry).should == true
16
16
 
17
17
  entry.line.should == 4
18
- entry.column.should == 0
18
+ entry.column.should == 1
19
19
  entry.message.should == 'wrong number of arguments (expected 2 but got 0)'
20
20
  end
21
21
 
@@ -33,7 +33,7 @@ example
33
33
  entry.is_a?(RubyLint::Report::Entry).should == true
34
34
 
35
35
  entry.line.should == 4
36
- entry.column.should == 0
36
+ entry.column.should == 1
37
37
  entry.message.should == 'wrong number of arguments ' \
38
38
  '(expected 2..3 but got 0)'
39
39
  end
@@ -52,7 +52,7 @@ example
52
52
  entry.is_a?(RubyLint::Report::Entry).should == true
53
53
 
54
54
  entry.line.should == 4
55
- entry.column.should == 0
55
+ entry.column.should == 1
56
56
  entry.message.should == 'wrong number of arguments ' \
57
57
  '(expected 2 but got 0)'
58
58
  end
@@ -107,11 +107,11 @@ Person.new(10, 20)
107
107
  first, second = report.entries
108
108
 
109
109
  first.line.should == 6
110
- first.column.should == 0
110
+ first.column.should == 1
111
111
  first.message.should == 'wrong number of arguments (expected 1 but got 0)'
112
112
 
113
113
  second.line.should == 7
114
- second.column.should == 0
114
+ second.column.should == 1
115
115
  second.message.should == 'wrong number of arguments (expected 1 but got 2)'
116
116
  end
117
117
  end
@@ -9,4 +9,8 @@ describe RubyLint::Analysis::Base do
9
9
 
10
10
  blk.should_not raise_error
11
11
  end
12
+
13
+ example 'enable analysis by default' do
14
+ RubyLint::Analysis::Base.analyze?(double(:ast), double(:vm)).should == true
15
+ end
12
16
  end
@@ -16,7 +16,7 @@ end
16
16
  entry.is_a?(RubyLint::Report::Entry).should == true
17
17
 
18
18
  entry.line.should == 3
19
- entry.column.should == 18
19
+ entry.column.should == 19
20
20
  entry.message.should == 'shadowing outer local variable number'
21
21
  end
22
22
 
@@ -53,7 +53,7 @@ end
53
53
  entry.is_a?(RubyLint::Report::Entry).should == true
54
54
 
55
55
  entry.line.should == 5
56
- entry.column.should == 18
56
+ entry.column.should == 19
57
57
  entry.message.should == 'shadowing outer local variable number'
58
58
  end
59
59
 
@@ -77,9 +77,9 @@ end
77
77
  first, second = report.entries
78
78
 
79
79
  first.line.should == 3
80
- first.column.should == 17
80
+ first.column.should == 18
81
81
 
82
82
  second.line.should == 7
83
- second.column.should == 17
83
+ second.column.should == 18
84
84
  end
85
85
  end
@@ -8,7 +8,7 @@ describe RubyLint::Analysis::UndefinedMethods do
8
8
  entry.is_a?(RubyLint::Report::Entry).should == true
9
9
 
10
10
  entry.line.should == 1
11
- entry.column.should == 0
11
+ entry.column.should == 1
12
12
  entry.message.should == 'undefined method example_method'
13
13
  end
14
14
 
@@ -28,7 +28,7 @@ String.example_method
28
28
  entry.is_a?(RubyLint::Report::Entry).should == true
29
29
 
30
30
  entry.line.should == 6
31
- entry.column.should == 0
31
+ entry.column.should == 1
32
32
  entry.message.should == 'undefined method example_method on String'
33
33
  end
34
34
 
@@ -40,7 +40,7 @@ String.example_method
40
40
  entry.is_a?(RubyLint::Report::Entry).should == true
41
41
 
42
42
  entry.line.should == 1
43
- entry.column.should == 0
43
+ entry.column.should == 1
44
44
  entry.message.should == 'undefined method example_method ' \
45
45
  'on an instance of String'
46
46
  end
@@ -69,7 +69,7 @@ name
69
69
  entry.is_a?(RubyLint::Report::Entry).should == true
70
70
 
71
71
  entry.line.should == 11
72
- entry.column.should == 0
72
+ entry.column.should == 1
73
73
  entry.message.should == 'undefined method name'
74
74
  end
75
75
 
@@ -132,7 +132,7 @@ name.downcasex
132
132
  entry = report.entries[0]
133
133
 
134
134
  entry.line.should == 4
135
- entry.column.should == 0
135
+ entry.column.should == 1
136
136
  entry.message.should == 'undefined method downcasex on an instance of String'
137
137
  end
138
138
 
@@ -156,7 +156,7 @@ user.invalid
156
156
  entry = report.entries[0]
157
157
 
158
158
  entry.line.should == 9
159
- entry.column.should == 0
159
+ entry.column.should == 1
160
160
  entry.message.should == 'undefined method invalid on an instance of User'
161
161
  end
162
162
 
@@ -8,7 +8,7 @@ describe RubyLint::Analysis::UndefinedVariables do
8
8
  entry.is_a?(RubyLint::Report::Entry).should == true
9
9
 
10
10
  entry.line.should == 1
11
- entry.column.should == 0
11
+ entry.column.should == 1
12
12
  entry.message.should == 'undefined instance variable @number'
13
13
  end
14
14
 
@@ -19,7 +19,7 @@ describe RubyLint::Analysis::UndefinedVariables do
19
19
  entry.is_a?(RubyLint::Report::Entry).should == true
20
20
 
21
21
  entry.line.should == 1
22
- entry.column.should == 0
22
+ entry.column.should == 1
23
23
  entry.message.should == 'undefined class variable @@number'
24
24
  end
25
25
 
@@ -30,7 +30,7 @@ describe RubyLint::Analysis::UndefinedVariables do
30
30
  entry.is_a?(RubyLint::Report::Entry).should == true
31
31
 
32
32
  entry.line.should == 1
33
- entry.column.should == 0
33
+ entry.column.should == 1
34
34
  entry.message.should == 'undefined global variable $number'
35
35
  end
36
36
 
@@ -41,7 +41,7 @@ describe RubyLint::Analysis::UndefinedVariables do
41
41
  entry.is_a?(RubyLint::Report::Entry).should == true
42
42
 
43
43
  entry.line.should == 1
44
- entry.column.should == 0
44
+ entry.column.should == 1
45
45
  entry.message.should == 'undefined constant NUMBER'
46
46
  end
47
47
 
@@ -63,7 +63,7 @@ A::B
63
63
  entry.is_a?(RubyLint::Report::Entry).should == true
64
64
 
65
65
  entry.line.should == 8
66
- entry.column.should == 0
66
+ entry.column.should == 1
67
67
  entry.message.should == 'undefined constant A::B'
68
68
  end
69
69
 
@@ -8,7 +8,7 @@ describe RubyLint::Analysis::UnusedVariables do
8
8
  entry.is_a?(RubyLint::Report::Entry).should == true
9
9
 
10
10
  entry.line.should == 1
11
- entry.column.should == 0
11
+ entry.column.should == 1
12
12
  entry.message.should == 'unused local variable number'
13
13
  end
14
14
 
@@ -17,7 +17,7 @@ describe RubyLint::Analysis::UnusedVariables do
17
17
  entry = report.entries[0]
18
18
 
19
19
  entry.line.should == 1
20
- entry.column.should == 0
20
+ entry.column.should == 1
21
21
  entry.message.should == 'unused instance variable @number'
22
22
  end
23
23
 
@@ -40,7 +40,7 @@ number
40
40
  entry.is_a?(RubyLint::Report::Entry).should == true
41
41
 
42
42
  entry.line.should == 1
43
- entry.column.should == 0
43
+ entry.column.should == 1
44
44
  entry.message.should == 'unused constant NUMBER'
45
45
  end
46
46
 
@@ -73,7 +73,7 @@ A::B = 10
73
73
  entry.is_a?(RubyLint::Report::Entry).should == true
74
74
 
75
75
  entry.line.should == 4
76
- entry.column.should == 0
76
+ entry.column.should == 1
77
77
  entry.message.should == 'unused constant A::B'
78
78
  end
79
79
 
@@ -90,7 +90,7 @@ end
90
90
  entry.is_a?(RubyLint::Report::Entry).should == true
91
91
 
92
92
  entry.line.should == 2
93
- entry.column.should == 2
93
+ entry.column.should == 3
94
94
  entry.message.should == 'unused local variable number'
95
95
  end
96
96
 
@@ -107,7 +107,7 @@ second = first
107
107
  entry = report.entries[0]
108
108
 
109
109
  entry.line.should == 2
110
- entry.column.should == 0
110
+ entry.column.should == 1
111
111
  entry.message.should == 'unused local variable second'
112
112
  end
113
113
 
@@ -155,7 +155,7 @@ end
155
155
 
156
156
  entry.message.should == 'unused argument number'
157
157
  entry.line.should == 1
158
- entry.column.should == 13
158
+ entry.column.should == 14
159
159
  end
160
160
 
161
161
  example 'warn for a unused optional argument' do
@@ -169,7 +169,7 @@ end
169
169
 
170
170
  entry.message.should == 'unused argument amount'
171
171
  entry.line.should == 1
172
- entry.column.should == 13
172
+ entry.column.should == 14
173
173
  end
174
174
 
175
175
  example 'warn for a unused rest argument' do
@@ -183,7 +183,7 @@ end
183
183
 
184
184
  entry.message.should == 'unused argument args'
185
185
  entry.line.should == 1
186
- entry.column.should == 13
186
+ entry.column.should == 14
187
187
  end
188
188
 
189
189
  example 'warn for a unused block argument' do
@@ -197,7 +197,7 @@ end
197
197
 
198
198
  entry.message.should == 'unused argument block'
199
199
  entry.line.should == 1
200
- entry.column.should == 13
200
+ entry.column.should == 14
201
201
  end
202
202
 
203
203
  specific_ruby_version '2.0' do
@@ -212,7 +212,7 @@ end
212
212
 
213
213
  entry.message.should == 'unused argument amount'
214
214
  entry.line.should == 1
215
- entry.column.should == 13
215
+ entry.column.should == 14
216
216
  end
217
217
  end
218
218
 
@@ -241,7 +241,7 @@ end
241
241
 
242
242
  entry.message.should == 'unused argument number'
243
243
  entry.line.should == 1
244
- entry.column.should == 18
244
+ entry.column.should == 19
245
245
  end
246
246
 
247
247
  example 'do not warn for a used argument' do