ruby-lint 0.0.5 → 0.9.0

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 (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