ruby-lint 0.0.5 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.asc +14 -14
  3. data/.gitignore +1 -0
  4. data/.yardopts +1 -1
  5. data/Gemfile +3 -3
  6. data/MANIFEST +16 -3
  7. data/benchmark/virtual_machine.rb +17 -0
  8. data/checksum/ruby-lint-0.0.5.gem.sha512 +1 -0
  9. data/doc/changelog.md +42 -0
  10. data/doc/configuration.md +133 -13
  11. data/lib/ruby-lint/analysis/shadowing_variables.rb +8 -14
  12. data/lib/ruby-lint/analysis/unused_variables.rb +17 -0
  13. data/lib/ruby-lint/ast/node.rb +18 -3
  14. data/lib/ruby-lint/cache.rb +121 -0
  15. data/lib/ruby-lint/cache_entry.rb +44 -0
  16. data/lib/ruby-lint/cli/analyze.rb +37 -18
  17. data/lib/ruby-lint/cli/plot.rb +94 -0
  18. data/lib/ruby-lint/cli.rb +1 -0
  19. data/lib/ruby-lint/configuration.rb +48 -3
  20. data/lib/ruby-lint/definition/ruby_method.rb +28 -1
  21. data/lib/ruby-lint/definition/ruby_object.rb +37 -3
  22. data/lib/ruby-lint/definition_builder/ruby_method.rb +4 -1
  23. data/lib/ruby-lint/definition_builder/ruby_module.rb +4 -1
  24. data/lib/ruby-lint/definition_generator.rb +3 -2
  25. data/lib/ruby-lint/definitions/core/arg0.rb +3 -1
  26. data/lib/ruby-lint/definitions/core/argf.rb +3 -1
  27. data/lib/ruby-lint/definitions/core/argument_error.rb +3 -1
  28. data/lib/ruby-lint/definitions/core/argv.rb +3 -1
  29. data/lib/ruby-lint/definitions/core/array.rb +3 -1
  30. data/lib/ruby-lint/definitions/core/autoload.rb +3 -1
  31. data/lib/ruby-lint/definitions/core/basic_object.rb +2 -0
  32. data/lib/ruby-lint/definitions/core/bignum.rb +3 -1
  33. data/lib/ruby-lint/definitions/core/binding.rb +3 -1
  34. data/lib/ruby-lint/definitions/core/class.rb +2 -0
  35. data/lib/ruby-lint/definitions/core/comparable.rb +3 -1
  36. data/lib/ruby-lint/definitions/core/complex.rb +3 -1
  37. data/lib/ruby-lint/definitions/core/condition_variable.rb +3 -1
  38. data/lib/ruby-lint/definitions/core/continuation.rb +3 -1
  39. data/lib/ruby-lint/definitions/core/data.rb +3 -1
  40. data/lib/ruby-lint/definitions/core/date.rb +3 -1
  41. data/lib/ruby-lint/definitions/core/date_time.rb +3 -1
  42. data/lib/ruby-lint/definitions/core/default_record_separator.rb +3 -1
  43. data/lib/ruby-lint/definitions/core/digest.rb +3 -1
  44. data/lib/ruby-lint/definitions/core/dir.rb +3 -1
  45. data/lib/ruby-lint/definitions/core/encoding.rb +3 -1
  46. data/lib/ruby-lint/definitions/core/encoding_error.rb +3 -1
  47. data/lib/ruby-lint/definitions/core/enumerable.rb +3 -1
  48. data/lib/ruby-lint/definitions/core/enumerator.rb +3 -1
  49. data/lib/ruby-lint/definitions/core/env.rb +4 -1
  50. data/lib/ruby-lint/definitions/core/eoferror.rb +3 -1
  51. data/lib/ruby-lint/definitions/core/erb.rb +2 -0
  52. data/lib/ruby-lint/definitions/core/errno.rb +3 -1
  53. data/lib/ruby-lint/definitions/core/etc.rb +3 -1
  54. data/lib/ruby-lint/definitions/core/exception.rb +3 -1
  55. data/lib/ruby-lint/definitions/core/false.rb +3 -1
  56. data/lib/ruby-lint/definitions/core/false_class.rb +3 -1
  57. data/lib/ruby-lint/definitions/core/fatal_error.rb +3 -1
  58. data/lib/ruby-lint/definitions/core/fiber.rb +3 -1
  59. data/lib/ruby-lint/definitions/core/fiber_error.rb +3 -1
  60. data/lib/ruby-lint/definitions/core/file.rb +3 -1
  61. data/lib/ruby-lint/definitions/core/file_list.rb +3 -1
  62. data/lib/ruby-lint/definitions/core/file_test.rb +3 -1
  63. data/lib/ruby-lint/definitions/core/file_utils.rb +3 -1
  64. data/lib/ruby-lint/definitions/core/fixnum.rb +3 -1
  65. data/lib/ruby-lint/definitions/core/float.rb +3 -1
  66. data/lib/ruby-lint/definitions/core/float_domain_error.rb +3 -1
  67. data/lib/ruby-lint/definitions/core/gc.rb +3 -1
  68. data/lib/ruby-lint/definitions/core/gem.rb +3 -1
  69. data/lib/ruby-lint/definitions/core/hash.rb +3 -1
  70. data/lib/ruby-lint/definitions/core/immediate_value.rb +3 -1
  71. data/lib/ruby-lint/definitions/core/index_error.rb +3 -1
  72. data/lib/ruby-lint/definitions/core/integer.rb +3 -1
  73. data/lib/ruby-lint/definitions/core/interrupt.rb +3 -1
  74. data/lib/ruby-lint/definitions/core/io.rb +3 -1
  75. data/lib/ruby-lint/definitions/core/ioerror.rb +3 -1
  76. data/lib/ruby-lint/definitions/core/kernel.rb +2 -0
  77. data/lib/ruby-lint/definitions/core/key_error.rb +3 -1
  78. data/lib/ruby-lint/definitions/core/load_error.rb +3 -1
  79. data/lib/ruby-lint/definitions/core/local_jump_error.rb +3 -1
  80. data/lib/ruby-lint/definitions/core/marshal.rb +3 -1
  81. data/lib/ruby-lint/definitions/core/match_data.rb +3 -1
  82. data/lib/ruby-lint/definitions/core/math.rb +3 -1
  83. data/lib/ruby-lint/definitions/core/memory_segmention_error.rb +3 -1
  84. data/lib/ruby-lint/definitions/core/method.rb +3 -1
  85. data/lib/ruby-lint/definitions/core/module.rb +2 -0
  86. data/lib/ruby-lint/definitions/core/monitor.rb +3 -1
  87. data/lib/ruby-lint/definitions/core/monitor_mixin.rb +3 -1
  88. data/lib/ruby-lint/definitions/core/mutex.rb +3 -1
  89. data/lib/ruby-lint/definitions/core/name_error.rb +3 -1
  90. data/lib/ruby-lint/definitions/core/nil.rb +3 -1
  91. data/lib/ruby-lint/definitions/core/nil_class.rb +3 -1
  92. data/lib/ruby-lint/definitions/core/no_memory_error.rb +3 -1
  93. data/lib/ruby-lint/definitions/core/no_method_error.rb +3 -1
  94. data/lib/ruby-lint/definitions/core/not_implemented_error.rb +3 -1
  95. data/lib/ruby-lint/definitions/core/numeric.rb +3 -1
  96. data/lib/ruby-lint/definitions/core/object.rb +3 -1
  97. data/lib/ruby-lint/definitions/core/object_space.rb +3 -1
  98. data/lib/ruby-lint/definitions/core/open_struct.rb +3 -1
  99. data/lib/ruby-lint/definitions/core/option_parser.rb +3 -1
  100. data/lib/ruby-lint/definitions/core/precision.rb +3 -1
  101. data/lib/ruby-lint/definitions/core/primitive_failure.rb +3 -1
  102. data/lib/ruby-lint/definitions/core/proc.rb +3 -1
  103. data/lib/ruby-lint/definitions/core/process.rb +3 -1
  104. data/lib/ruby-lint/definitions/core/queue.rb +3 -1
  105. data/lib/ruby-lint/definitions/core/rake.rb +3 -1
  106. data/lib/ruby-lint/definitions/core/rake_file_utils.rb +3 -1
  107. data/lib/ruby-lint/definitions/core/rakeversion.rb +3 -1
  108. data/lib/ruby-lint/definitions/core/random.rb +3 -1
  109. data/lib/ruby-lint/definitions/core/range.rb +3 -1
  110. data/lib/ruby-lint/definitions/core/range_error.rb +3 -1
  111. data/lib/ruby-lint/definitions/core/rational.rb +3 -1
  112. data/lib/ruby-lint/definitions/core/rb_config.rb +3 -1
  113. data/lib/ruby-lint/definitions/core/regexp.rb +3 -1
  114. data/lib/ruby-lint/definitions/core/regexp_error.rb +3 -1
  115. data/lib/ruby-lint/definitions/core/ruby_copyright.rb +3 -1
  116. data/lib/ruby-lint/definitions/core/ruby_description.rb +3 -1
  117. data/lib/ruby-lint/definitions/core/ruby_engine.rb +3 -1
  118. data/lib/ruby-lint/definitions/core/ruby_patchlevel.rb +3 -1
  119. data/lib/ruby-lint/definitions/core/ruby_platform.rb +3 -1
  120. data/lib/ruby-lint/definitions/core/ruby_release_date.rb +3 -1
  121. data/lib/ruby-lint/definitions/core/ruby_version.rb +3 -1
  122. data/lib/ruby-lint/definitions/core/runtime_error.rb +3 -1
  123. data/lib/ruby-lint/definitions/core/scan_error.rb +3 -1
  124. data/lib/ruby-lint/definitions/core/script_error.rb +3 -1
  125. data/lib/ruby-lint/definitions/core/security_error.rb +3 -1
  126. data/lib/ruby-lint/definitions/core/shellwords.rb +3 -1
  127. data/lib/ruby-lint/definitions/core/signal.rb +3 -1
  128. data/lib/ruby-lint/definitions/core/signal_exception.rb +3 -1
  129. data/lib/ruby-lint/definitions/core/singleton.rb +3 -1
  130. data/lib/ruby-lint/definitions/core/sized_queue.rb +3 -1
  131. data/lib/ruby-lint/definitions/core/standard_error.rb +3 -1
  132. data/lib/ruby-lint/definitions/core/stderr.rb +2 -0
  133. data/lib/ruby-lint/definitions/core/stdin.rb +2 -0
  134. data/lib/ruby-lint/definitions/core/stdout.rb +2 -0
  135. data/lib/ruby-lint/definitions/core/stop_iteration.rb +3 -1
  136. data/lib/ruby-lint/definitions/core/string.rb +3 -1
  137. data/lib/ruby-lint/definitions/core/string_io.rb +3 -1
  138. data/lib/ruby-lint/definitions/core/string_scanner.rb +3 -1
  139. data/lib/ruby-lint/definitions/core/struct.rb +3 -1
  140. data/lib/ruby-lint/definitions/core/syck.rb +3 -1
  141. data/lib/ruby-lint/definitions/core/symbol.rb +3 -1
  142. data/lib/ruby-lint/definitions/core/syntax_error.rb +3 -1
  143. data/lib/ruby-lint/definitions/core/system_call_error.rb +3 -1
  144. data/lib/ruby-lint/definitions/core/system_exit.rb +3 -1
  145. data/lib/ruby-lint/definitions/core/system_stack_error.rb +3 -1
  146. data/lib/ruby-lint/definitions/core/thread.rb +3 -1
  147. data/lib/ruby-lint/definitions/core/thread_error.rb +3 -1
  148. data/lib/ruby-lint/definitions/core/thread_group.rb +3 -1
  149. data/lib/ruby-lint/definitions/core/time.rb +3 -1
  150. data/lib/ruby-lint/definitions/core/toplevel_binding.rb +3 -1
  151. data/lib/ruby-lint/definitions/core/true.rb +3 -1
  152. data/lib/ruby-lint/definitions/core/true_class.rb +3 -1
  153. data/lib/ruby-lint/definitions/core/type_error.rb +3 -1
  154. data/lib/ruby-lint/definitions/core/unbound_method.rb +3 -1
  155. data/lib/ruby-lint/definitions/core/unmarshalable.rb +3 -1
  156. data/lib/ruby-lint/definitions/core/unsupported_library_error.rb +3 -1
  157. data/lib/ruby-lint/definitions/core/weak_ref.rb +3 -1
  158. data/lib/ruby-lint/definitions/core/yaml.rb +1 -0
  159. data/lib/ruby-lint/definitions/core/zero_division_error.rb +3 -1
  160. data/lib/ruby-lint/definitions/core/zlib.rb +8840 -0
  161. data/lib/ruby-lint/definitions/rails/abstract_controller.rb +1 -0
  162. data/lib/ruby-lint/definitions/rails/action_controller.rb +1 -0
  163. data/lib/ruby-lint/definitions/rails/action_dispatch.rb +1 -0
  164. data/lib/ruby-lint/definitions/rails/action_mailer.rb +1 -0
  165. data/lib/ruby-lint/definitions/rails/action_pack.rb +1 -0
  166. data/lib/ruby-lint/definitions/rails/action_view.rb +1 -0
  167. data/lib/ruby-lint/definitions/rails/active_model.rb +1 -0
  168. data/lib/ruby-lint/definitions/rails/active_record.rb +1 -0
  169. data/lib/ruby-lint/definitions/rails/active_support.rb +1 -0
  170. data/lib/ruby-lint/definitions/rails/arel.rb +1 -0
  171. data/lib/ruby-lint/definitions/rails/rails.rb +1 -0
  172. data/lib/ruby-lint/definitions/rails/sprockets.rb +1 -0
  173. data/lib/ruby-lint/file_scanner.rb +2 -0
  174. data/lib/ruby-lint/iterator.rb +21 -12
  175. data/lib/ruby-lint/method_call_info.rb +31 -0
  176. data/lib/ruby-lint/node_hash.rb +105 -0
  177. data/lib/ruby-lint/parser.rb +4 -2
  178. data/lib/ruby-lint/runner.rb +62 -6
  179. data/lib/ruby-lint/template/definition.erb +2 -0
  180. data/lib/ruby-lint/version.rb +1 -1
  181. data/lib/ruby-lint/virtual_machine.rb +75 -43
  182. data/lib/ruby-lint.rb +20 -2
  183. data/profiling/virtual_machine.rb +20 -0
  184. data/ruby-lint.gemspec +2 -1
  185. data/spec/fixtures/complex/rcap.rb +29 -0
  186. data/spec/fixtures/complex/slop.rb +21 -0
  187. data/spec/fixtures/file_scanner/lib/ruby-lint/definition/constant_proxy.rb +6 -0
  188. data/spec/fixtures/file_scanner/lib/ruby-lint/global_scope.rb +6 -0
  189. data/spec/ruby-lint/analysis/unused_variables_spec.rb +114 -0
  190. data/spec/ruby-lint/cache_entry_spec.rb +25 -0
  191. data/spec/ruby-lint/cache_spec.rb +53 -0
  192. data/spec/ruby-lint/definition/ruby_method_spec.rb +4 -4
  193. data/spec/ruby-lint/definition/ruby_object_spec.rb +33 -0
  194. data/spec/ruby-lint/iterator_spec.rb +15 -0
  195. data/spec/ruby-lint/node_hash_spec.rb +56 -0
  196. data/spec/ruby-lint/runner_spec.rb +6 -1
  197. data/spec/ruby-lint/virtual_machine/assignments/variables_spec.rb +2 -2
  198. data/spec/ruby-lint/virtual_machine/location_spec.rb +64 -0
  199. data/spec/ruby-lint/virtual_machine/method_call_tracking_spec.rb +64 -0
  200. data/spec/spec_helper.rb +7 -0
  201. data/task/generate.rake +1 -1
  202. data.tar.gz.asc +14 -14
  203. metadata +34 -7
  204. metadata.gz.asc +14 -14
  205. data/debug/memory_usage.rb +0 -14
  206. data/debug/profile.rb +0 -18
  207. data/task/profile.rake +0 -27
@@ -11,21 +11,21 @@ module RubyLint
11
11
  # @return [Numeric]
12
12
  #
13
13
  def line
14
- return location.expression.line
14
+ return location.expression.line if location
15
15
  end
16
16
 
17
17
  ##
18
18
  # @return [Numeric]
19
19
  #
20
20
  def column
21
- return location.expression.column
21
+ return location.expression.column if location
22
22
  end
23
23
 
24
24
  ##
25
25
  # @return [String]
26
26
  #
27
27
  def file
28
- return location.expression.source_buffer.name
28
+ return location.expression.source_buffer.name if location
29
29
  end
30
30
 
31
31
  ##
@@ -44,6 +44,21 @@ module RubyLint
44
44
  def inspect_oneline
45
45
  return inspect.gsub(/\s*\n\s*/, ' ')
46
46
  end
47
+
48
+ ##
49
+ # Generates a unique SHA1 digest hash based on the current node.
50
+ #
51
+ # @return [String]
52
+ #
53
+ def sha1
54
+ input = inspect
55
+
56
+ if location and location.expression
57
+ input << "#{file}#{line}#{column}"
58
+ end
59
+
60
+ return Digest::SHA1.hexdigest(input)
61
+ end
47
62
  end # Node
48
63
  end # AST
49
64
  end # RubyLint
@@ -0,0 +1,121 @@
1
+ module RubyLint
2
+ ##
3
+ # The Cache class is used for storing arbitrary Ruby objects in a cache
4
+ # directory. The primary use case of this class is to store cached ASTs and
5
+ # their comment associations (as is done by {RubyLint::Runner}).
6
+ #
7
+ # @!attribute [r] directory
8
+ # @return [String]
9
+ #
10
+ class Cache
11
+ attr_reader :directory
12
+
13
+ ##
14
+ # The version of the cache format.
15
+ #
16
+ # @return [String]
17
+ #
18
+ FORMAT_VERSION = '1'
19
+
20
+ ##
21
+ # @param [String] directory Path to the cache directory.
22
+ #
23
+ def initialize(directory)
24
+ @directory = directory
25
+ end
26
+
27
+ ##
28
+ # Creates the directory specified in {#directory} unless it already exists.
29
+ #
30
+ def create_directory!
31
+ Dir.mkdir(directory) unless File.directory?(directory)
32
+ end
33
+
34
+ ##
35
+ # Checks if there's a cache entry for the given name.
36
+ #
37
+ # @return [TrueClass|FalseClass]
38
+ #
39
+ def exists?(name)
40
+ return File.file?(entry_filepath(name))
41
+ end
42
+
43
+ ##
44
+ # Returns the cache entry for the given name or `nil` if the entry doesn't
45
+ # exist.
46
+ #
47
+ # @param [String] name
48
+ # @return [Mixed]
49
+ #
50
+ def get(name)
51
+ return unless exists?(name)
52
+
53
+ data = File.read(entry_filepath(name))
54
+
55
+ return decode(data)
56
+ end
57
+
58
+ ##
59
+ # Sets the cache entry to the given value. Existing cache entries are
60
+ # overwritten.
61
+ #
62
+ # @param [String] name
63
+ # @param [Mixed] value
64
+ #
65
+ def set(name, value)
66
+ File.open(entry_filepath(name), 'w') do |handle|
67
+ handle.write(encode(value))
68
+ end
69
+ end
70
+
71
+ ##
72
+ # Removes a cache entry.
73
+ #
74
+ # @param [String] name
75
+ #
76
+ def delete(name)
77
+ File.unlink(entry_filepath(name)) if exists?(name)
78
+ end
79
+
80
+ private
81
+
82
+ ##
83
+ # Returns the filename for the given entry name.
84
+ #
85
+ # @param [String] name
86
+ # @return [String]
87
+ #
88
+ def entry_filename(name)
89
+ return "#{name}.#{FORMAT_VERSION}.cache"
90
+ end
91
+
92
+ ##
93
+ # Returns the full filename of the cache entry's name.
94
+ #
95
+ # @param [String] name
96
+ # @return [String]
97
+ #
98
+ def entry_filepath(name)
99
+ return File.join(directory, entry_filename(name))
100
+ end
101
+
102
+ ##
103
+ # Decodes a cache entry.
104
+ #
105
+ # @param [String] input
106
+ # @return [Mixed]
107
+ #
108
+ def decode(input)
109
+ return Marshal.load(Zlib::Inflate.inflate(input))
110
+ end
111
+
112
+ ##
113
+ # Encodes a cache entry.
114
+ #
115
+ # @param [String] input
116
+ #
117
+ def encode(input)
118
+ return Zlib::Deflate.deflate(Marshal.dump(input))
119
+ end
120
+ end # Cache
121
+ end # RubyLint
@@ -0,0 +1,44 @@
1
+ module RubyLint
2
+ ##
3
+ # The CacheEntry class is used to store nodes, comments and file modification
4
+ # times that belong to a certain root AST. It's primarily used by
5
+ # {RubyLint::Runner}.
6
+ #
7
+ # @!attribute [r] nodes
8
+ # @return [Array]
9
+ #
10
+ # @!attribute [r] comments
11
+ # @return [Hash]
12
+ #
13
+ # @!attribute [r] mtimes
14
+ # @return [Hash]
15
+ #
16
+ class CacheEntry
17
+ attr_reader :nodes, :comments, :mtimes
18
+
19
+ ##
20
+ # @param [Array] nodes
21
+ # @param [Hash] comments
22
+ # @param [Hash] mtimes
23
+ #
24
+ def initialize(nodes, comments, mtimes)
25
+ @nodes = nodes
26
+ @comments = comments
27
+ @mtimes = mtimes
28
+ end
29
+
30
+ ##
31
+ # Returns `true` if none of the associated files have been modified,
32
+ # `false` otherwise.
33
+ #
34
+ # @return [TrueClass|FalseClass]
35
+ #
36
+ def valid?
37
+ mtimes.each do |file, mtime|
38
+ return false if File.mtime(file) != mtime
39
+ end
40
+
41
+ return true
42
+ end
43
+ end # CacheEntry
44
+ end # RubyLint
@@ -61,6 +61,8 @@ Examples:
61
61
  on :b, :benchmark, 'Enables benchmarking mode'
62
62
  on :d, :debug, 'Displays debugging output in STDERR'
63
63
 
64
+ on :'disable-cache', 'Disables caching of external files'
65
+
64
66
  ##
65
67
  # Returns an Array containing the file paths that exist. If a non existing
66
68
  # file is encountered `abort` is called.
@@ -110,6 +112,36 @@ Examples:
110
112
  @output_destination = destination
111
113
  end
112
114
 
115
+ ##
116
+ # @param [RubyLint::Configuration] configuration
117
+ # @param [Hash] opts
118
+ #
119
+ def configure(configuration, options)
120
+ option_mapping.each do |key, setter|
121
+ configuration.send(setter, options[key]) if options[key]
122
+ end
123
+
124
+ if options[:'disable-cache']
125
+ configuration.enable_cache = false
126
+ end
127
+ end
128
+
129
+ ##
130
+ # @param [String] output
131
+ # @param [Float] exec_time
132
+ #
133
+ def show_benchmark_info(output, exec_time)
134
+ memory_kb = `ps -o rss= #{Process.pid}`.strip.to_f
135
+ memory_mb = memory_kb / 1024
136
+
137
+ output_destination.puts unless output.empty?
138
+
139
+ output_destination.puts "Execution time: #{exec_time.round(4)} seconds"
140
+
141
+ output_destination.puts "Memory usage: #{memory_mb.round(2)} MB " \
142
+ "(#{memory_kb.round(2)} KB)"
143
+ end
144
+
113
145
  run do |opts, args|
114
146
  abort 'You must specify at least one file to analyze' if args.empty?
115
147
 
@@ -117,27 +149,14 @@ Examples:
117
149
  files = extract_files(args)
118
150
  configuration = RubyLint::Configuration.load_from_file
119
151
 
120
- option_mapping.each do |key, setter|
121
- configuration.send(setter, opts[key]) if opts[key]
122
- end
123
-
124
- runner = RubyLint::Runner.new(configuration)
125
- output = runner.analyze(files)
126
-
127
- output_destination.puts output unless output.empty?
152
+ configure(configuration, opts)
128
153
 
154
+ runner = RubyLint::Runner.new(configuration)
155
+ output = runner.analyze(files)
129
156
  exec_time = Time.now.to_f - start_time
130
157
 
131
- if opts[:benchmark]
132
- memory_kb = `ps -o rss= #{Process.pid}`.strip.to_f
133
- memory_mb = memory_kb / 1024
134
-
135
- output_destination.puts unless output.empty?
136
-
137
- output_destination.puts "Execution time: #{exec_time.round(2)} seconds"
158
+ output_destination.puts output unless output.empty?
138
159
 
139
- output_destination.puts "Memory usage: #{memory_mb.round(2)} MB " \
140
- "(#{memory_kb.round(2)} KB)"
141
- end
160
+ show_benchmark_info(output, exec_time) if opts[:benchmark]
142
161
  end # run do |opts, args|
143
162
  end # RubyLint::CLI.options.command
@@ -0,0 +1,94 @@
1
+ #:nocov:
2
+ RubyLint::CLI.options.command :plot do
3
+ banner 'Usage: ruby-lint plot [FILE] [OPTIONS]'
4
+ description 'Plots analysis time of a single file'
5
+
6
+ separator RubyLint::CLI::OPTIONS_HEADER
7
+
8
+ RubyLint::CLI.help_option(self)
9
+
10
+ on :i=, :iterations=,
11
+ 'The amount of iterations',
12
+ :as => Integer,
13
+ :default => 100
14
+
15
+ ##
16
+ # @param [String] basename
17
+ # @param [Array] no_cache
18
+ # @param [Array] cache
19
+ # @param [Hash] options
20
+ #
21
+ def plot_timings(basename, no_cache, cache, options)
22
+ x_points = (1..options[:iterations]).to_a
23
+
24
+ Gnuplot.open do |gp|
25
+ Gnuplot::Plot.new(gp) do |plot|
26
+ plot.title "#{basename} with #{options[:iterations]} iterations"
27
+
28
+ plot.xlabel 'Iteration'
29
+ plot.ylabel 'Time (ms)'
30
+
31
+ plot.data << Gnuplot::DataSet.new([x_points, no_cache]) do |ds|
32
+ ds.with = 'lines'
33
+ ds.title = 'No caching'
34
+ end
35
+
36
+ plot.data << Gnuplot::DataSet.new([x_points, cache]) do |ds|
37
+ ds.with = 'lines'
38
+ ds.title = 'Caching'
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ ##
45
+ # Measures the analysis time of a given file.
46
+ #
47
+ # @param [String] file
48
+ # @param [Fixnum] amount
49
+ # @param [TrueClass|FalseClass] caching
50
+ #
51
+ def measure_analysis(file, amount, caching = false)
52
+ configuration = RubyLint::Configuration.load_from_file
53
+ configuration.enable_cache = caching
54
+
55
+ FileUtils.rm_rf(configuration.cache_directory) if caching
56
+
57
+ files = [file]
58
+ runner = RubyLint::Runner.new(configuration)
59
+ timings = []
60
+
61
+ amount.times do
62
+ timing = Benchmark.measure { runner.analyze(files) }
63
+
64
+ timings << timing.real * 1000
65
+ end
66
+
67
+ return timings
68
+ end
69
+
70
+ run do |opts, args|
71
+ require 'gnuplot'
72
+ require 'fileutils'
73
+ require 'benchmark'
74
+
75
+ abort 'No files specified' if args.empty?
76
+
77
+ abort "The file #{args[0]} does not exist" unless File.file?(args[0])
78
+
79
+ puts 'Measuring, this will take a while...'
80
+
81
+ no_cache = measure_analysis(args[0], opts[:iterations])
82
+ cache = measure_analysis(args[0], opts[:iterations], true)
83
+
84
+ plot_timings(File.basename(args[0]), no_cache, cache, opts)
85
+
86
+ no_cache_avg = no_cache.inject(:+) / no_cache.length
87
+ cache_avg = cache.inject(:+) / cache.length
88
+
89
+ puts 'Averages:'
90
+ puts "Cache disabled: #{no_cache_avg} ms"
91
+ puts "Cache enabled: #{cache_avg} ms"
92
+ end
93
+ end
94
+ #:nocov:
data/lib/ruby-lint/cli.rb CHANGED
@@ -2,3 +2,4 @@ require 'slop'
2
2
  require_relative 'cli/base'
3
3
  require_relative 'cli/analyze'
4
4
  require_relative 'cli/ast'
5
+ require_relative 'cli/plot'
@@ -22,9 +22,20 @@ module RubyLint
22
22
  # @!attribute [rw] ignore_paths
23
23
  # @return [Array]
24
24
  #
25
+ # @!attribute [rw] enable_cache
26
+ # When set to `true` external files and their associated data will be
27
+ # cached.
28
+ # @return [TrueClass|FalseClass]
29
+ #
30
+ # @!attribute [r] cache_directory
31
+ # The path to the directory to use for storing cache files.
32
+ # @return [String]
33
+ #
25
34
  class Configuration
26
- attr_reader :analysis_classes, :report_levels, :presenter, :directories
27
- attr_accessor :debug, :ignore_paths
35
+ attr_reader :analysis_classes, :report_levels, :presenter, :directories,
36
+ :cache_directory
37
+
38
+ attr_accessor :debug, :ignore_paths, :enable_cache
28
39
 
29
40
  ##
30
41
  # Returns an Array of locations from which to load configuration files.
@@ -86,7 +97,8 @@ module RubyLint
86
97
  # @param [Hash] options
87
98
  #
88
99
  def initialize(options = {})
89
- @debug = false
100
+ @debug = false
101
+ @enable_cache = default_cache_value
90
102
 
91
103
  options.each do |key, value|
92
104
  setter = "#{key}="
@@ -101,6 +113,16 @@ module RubyLint
101
113
  @presenter ||= default_presenter
102
114
  @directories ||= default_directories
103
115
  @ignore_paths ||= []
116
+ @cache_directory ||= default_cache_directory
117
+ end
118
+
119
+ ##
120
+ # Expands and sets the path as the cache directory.
121
+ #
122
+ # @param [String] path
123
+ #
124
+ def cache_directory=(path)
125
+ @cache_directory = File.expand_path(path)
104
126
  end
105
127
 
106
128
  ##
@@ -217,5 +239,28 @@ module RubyLint
217
239
  def default_directories
218
240
  return [Dir.pwd]
219
241
  end
242
+
243
+ ##
244
+ # @return [TrueClass|FalseClass]
245
+ #
246
+ def default_cache_value
247
+ return ENV['RUBY_LINT_DISABLE_CACHE'] ? false : true
248
+ end
249
+
250
+ ##
251
+ # The default cache directory to use. Per the XDG specification
252
+ # (http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html)
253
+ # this is set to `$XDG_CACHE_HOME`/`$HOME/.cache` by default.
254
+ #
255
+ # @return [String]
256
+ #
257
+ def default_cache_directory
258
+ root = ENV['XDG_CACHE_HOME'] || File.join(ENV['HOME'], '.cache')
259
+
260
+ # ~/.cache might not exist on non Linux systems.
261
+ Dir.mkdir(root) unless File.directory?(root)
262
+
263
+ return File.join(root, 'ruby-lint')
264
+ end
220
265
  end # Configuration
221
266
  end # RubyLint