ruby-lint 0.9.1 → 1.0.0.pre.preview1

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 939921e3e0b0860d74f54f2ddaefe22108be2b0c
4
- data.tar.gz: 940ca31c4345114f3a7cd864acda3fd4d64a8b34
3
+ metadata.gz: 24fc661993350c12969fcf32d98a88a3539a1f71
4
+ data.tar.gz: 4ae7f0b1589d953aef60c3d027aa38e6de6dc17b
5
5
  SHA512:
6
- metadata.gz: 8d4341b6d719cc515b69fa16eb2e76d5515a40655e63fbf88f60a6bd9bdcdfec59184ac62a151ce6e42920ff039206fc359a47e131ac2ab76de2a8a83f69fd2b
7
- data.tar.gz: 3e3dfa77c8a7a0cad2c7ab54839f870c124cc1685c661de5881b6980678a498cc5a339772bb4800c93d6da85ebef7f71f57a522cb987b1e02c876cc6976aa1a7
6
+ metadata.gz: 053bc9734416821c16a410eef0b8b49bfcf16b84b29fb08f82a3d1ac73dfc41b5b144bc0695e681cc556a127e2af010abb501d4e45dfd5cbf3baecfcc725999d
7
+ data.tar.gz: 61a61089a5f673979e0fc696e2e36e0595dfaea73c29b7aaba677ce9134ac0c6f77375d9ea3c67bfe5074eb21a7e2b5843fc957d507ba3834daa532fc01afbdf
@@ -4,7 +4,7 @@ script: rake travis
4
4
  rvm:
5
5
  - 1.9.3
6
6
  - 2.0.0
7
- - rbx-19mode
7
+ - rbx-2.2.1
8
8
  - jruby-19mode
9
9
 
10
10
  notifications:
@@ -4,22 +4,20 @@ Those that wish to contribute to ruby-lint are more than welcome. However, to
4
4
  make the lifes of both me and others easier there are a few things one should
5
5
  keep in mind.
6
6
 
7
- The basic set of guidelines is described at
8
- <http://yorickpeterse.com/articles/contributing-to-my-code/>. The article looks
9
- a bit daunting but most of what this article describes is already common
10
- practise in Ruby land. In short:
7
+ The gist of this is as following:
11
8
 
12
- * write tests
13
- * write documentation using YARD (at the very least arguments and return values
9
+ * Write tests
10
+ * Write documentation using YARD (at the very least arguments and return values
14
11
  should be documented)
15
- * wrap lines at 79 characters per line
12
+ * Wrap lines at 79 characters per line
16
13
  * Git commits should have a <= 50 character summary, optionally followed by a
17
14
  blank line and a more in depth description of 79 characters per line.
18
15
 
19
- These are the most important bits, the rest is all described in the above
20
- article. If you have any questions or whatsoever don't hesitate to ask and
21
- don't worry about making mistakes (e.g. missing some documentation), I'll help
22
- wherever I can and won't slap you with a large trout.
16
+ More information can be found here:
17
+ <http://yorickpeterse.com/articles/contributing-to-my-code/>. If you have any
18
+ questions or whatsoever don't hesitate to ask and don't worry about making
19
+ mistakes (e.g. missing some documentation), I'll help wherever I can and won't
20
+ slap you with a large trout.
23
21
 
24
22
  ## Legal
25
23
 
data/Gemfile CHANGED
@@ -2,6 +2,9 @@ source 'https://rubygems.org/'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'racc', :platforms => :rbx
6
-
7
- gem 'ruby-prof', :platforms => :mri
5
+ group :testing do
6
+ gem 'rubysl', :platform => :rbx
7
+ gem 'rubinius-developer_tools', :platform => :rbx
8
+ gem 'racc', :platform => :rbx
9
+ gem 'ruby-prof', :platform => :mri
10
+ end
data/MANIFEST CHANGED
@@ -8,6 +8,7 @@ LICENSE
8
8
  MANIFEST
9
9
  README.md
10
10
  Rakefile
11
+ benchmark/bootup.rb
11
12
  benchmark/virtual_machine.rb
12
13
  bin/ruby-lint
13
14
  checksum/.gitkeep
@@ -15,6 +16,7 @@ checksum/ruby-lint-0.0.3.gem.sha512
15
16
  checksum/ruby-lint-0.0.4.gem.sha512
16
17
  checksum/ruby-lint-0.0.5.gem.sha512
17
18
  checksum/ruby-lint-0.9.0.gem.sha512
19
+ checksum/ruby-lint-0.9.1.gem.sha512
18
20
  doc/.gitkeep
19
21
  doc/DCO.md
20
22
  doc/architecture.md
@@ -36,6 +38,7 @@ lib/ruby-lint/analysis/undefined_variables.rb
36
38
  lib/ruby-lint/analysis/unused_variables.rb
37
39
  lib/ruby-lint/ast/builder.rb
38
40
  lib/ruby-lint/ast/node.rb
41
+ lib/ruby-lint/benchmark/average.rb
39
42
  lib/ruby-lint/cache.rb
40
43
  lib/ruby-lint/cache_entry.rb
41
44
  lib/ruby-lint/cli.rb
@@ -45,6 +48,7 @@ lib/ruby-lint/cli/base.rb
45
48
  lib/ruby-lint/cli/plot.rb
46
49
  lib/ruby-lint/configuration.rb
47
50
  lib/ruby-lint/constant_loader.rb
51
+ lib/ruby-lint/constant_path.rb
48
52
  lib/ruby-lint/default_names.rb
49
53
  lib/ruby-lint/definition/constant_proxy.rb
50
54
  lib/ruby-lint/definition/ruby_method.rb
@@ -218,7 +222,6 @@ lib/ruby-lint/file_loader.rb
218
222
  lib/ruby-lint/file_scanner.rb
219
223
  lib/ruby-lint/generated_constant.rb
220
224
  lib/ruby-lint/global_scope.rb
221
- lib/ruby-lint/helper/constant_paths.rb
222
225
  lib/ruby-lint/inspector.rb
223
226
  lib/ruby-lint/iterator.rb
224
227
  lib/ruby-lint/method_call/alias.rb
@@ -278,6 +281,7 @@ spec/ruby-lint/cache_spec.rb
278
281
  spec/ruby-lint/cli/analyze_spec.rb
279
282
  spec/ruby-lint/cli/ast_spec.rb
280
283
  spec/ruby-lint/configuration_spec.rb
284
+ spec/ruby-lint/constant_path.rb
281
285
  spec/ruby-lint/definition/constant_proxy_spec.rb
282
286
  spec/ruby-lint/definition/dsl_spec.rb
283
287
  spec/ruby-lint/definition/ruby_method_spec.rb
@@ -305,6 +309,8 @@ spec/ruby-lint/report_spec.rb
305
309
  spec/ruby-lint/runner_spec.rb
306
310
  spec/ruby-lint/virtual_machine/alias_spec.rb
307
311
  spec/ruby-lint/virtual_machine/assignments/arrays_spec.rb
312
+ spec/ruby-lint/virtual_machine/assignments/assignment_arguments_spec.rb
313
+ spec/ruby-lint/virtual_machine/assignments/constants_spec.rb
308
314
  spec/ruby-lint/virtual_machine/assignments/hashes_spec.rb
309
315
  spec/ruby-lint/virtual_machine/assignments/optional_spec.rb
310
316
  spec/ruby-lint/virtual_machine/assignments/return_values_spec.rb
data/README.md CHANGED
@@ -16,9 +16,9 @@ instead of focusing on semantics (e.g. the amount of characters per line).
16
16
 
17
17
  The following Ruby implementations/versions are officially supported:
18
18
 
19
- * Ruby 1.9.3 or 2.0 and newer
20
- * Rubinius head running in 1.9 mode
21
- * Jruby head running in 1.9 mode
19
+ * MRI 1.9.3 and newer
20
+ * Rubinius 2.0 and newer
21
+ * Jruby 1.7 and newer
22
22
 
23
23
  Ruby implementations running a 1.8 based version of Ruby are not supported.
24
24
 
@@ -40,25 +40,18 @@ This builds a new version of the Gem and saves it in the pkg/ directory.
40
40
 
41
41
  ## Security
42
42
 
43
- To ensure that people can't tamper with the ruby-lint Gem once it's being
44
- distributed as a `.gem` file the Gem is signed using GNUPG (using the
45
- [rubygems-openpgp][rubygems-openpgp] Gem). If you have this Gem installed it's
46
- recommended that you install ruby-lint as following:
43
+ As a basic form of security ruby-lint provides a set of SHA512 checksums for
44
+ every Gem release. These checksums can be found in the `checksum/` directory.
45
+ Although these checksums do not prevent malicious users from tampering with a
46
+ built Gem they can be used for basic integrity verification purposes.
47
47
 
48
- gem install ruby-lint --verify --trust
48
+ The checksum of a file can be checked using the `sha512sum` command. For
49
+ example:
49
50
 
50
- Unless you have my GPG public key and have marked it as trusted this process
51
- will fail. For signing Gems I use the public key **3649F444** registered to
52
- "Yorick Peterse" using Email address <yorickpeterse@gmail.com>.
51
+ $ sha512sum pkg/ruby-lint-0.9.1.gem
52
+ 10a51f27c455e5743fff7fefe29512cff20116b805bec148e09d4bade1727e3beab7f7f9ee97b020d290773edcb7bd1685858ccad0bbd1a35cc0282c00c760c6 pkg/ruby-lint-0.9.1.gem
53
53
 
54
- You can add this key by running the following command:
55
-
56
- gpg --recv-keys 3649F444
57
-
58
- In case you don't use GPG but still want some form of verification you can use
59
- the checksums that are located in the "checksum" directory. These checksums are
60
- SHA512 checksums of entire Gem files and can be verified using the `sha512sum`
61
- command.
54
+ In the past Gems were also signed using PGP, this is no longer the case.
62
55
 
63
56
  ## Usage
64
57
 
@@ -91,9 +84,9 @@ Given the following code:
91
84
  Analysing this file using ruby-lint (with the default settings) would result in
92
85
  the following output:
93
86
 
94
- test.rb: error: line 7, column 21: undefined instance variable @name
95
- test.rb: warning: line 12, column 0: unused local variable greeting
96
- test.rb: error: line 14, column 0: wrong number of arguments (expected 0 but got 1)
87
+ test.rb: error: line 7, column 22: undefined instance variable @name
88
+ test.rb: warning: line 12, column 1: unused local variable greeting
89
+ test.rb: error: line 14, column 1: wrong number of arguments (expected 0 but got 1)
97
90
 
98
91
  ## Documentation
99
92
 
@@ -107,5 +100,3 @@ the following output:
107
100
  All source code in this repository is licensed under the MIT license unless
108
101
  specified otherwise. A copy of this license can be found in the file "LICENSE"
109
102
  in the root directory of this repository.
110
-
111
- [rubygems-openpgp]: https://github.com/grant-olson/rubygems-openpgp
@@ -0,0 +1,13 @@
1
+ # This benchmark script measures the amount of time it takes to boot up the CLI
2
+ # and analyze the VM with caching disabled.
3
+
4
+ require_relative '../lib/ruby-lint/benchmark/average'
5
+
6
+ script = File.expand_path('../../bin/ruby-lint', __FILE__)
7
+ command = "#{script} analyze --disable-cache lib/ruby-lint/virtual_machine.rb"
8
+
9
+ RubyLint::Benchmark::Average.measure do
10
+ output = `#{command}`
11
+
12
+ raise "Command failed: #{output}" unless $?.success?
13
+ end
@@ -0,0 +1 @@
1
+ 10a51f27c455e5743fff7fefe29512cff20116b805bec148e09d4bade1727e3beab7f7f9ee97b020d290773edcb7bd1685858ccad0bbd1a35cc0282c00c760c6
@@ -8,6 +8,8 @@ example, the callback method `on_string` is used before a `(string)` node is
8
8
  processed. For more low level details see the API documentation of
9
9
  {RubyLint::Iterator} and {RubyLint::Analysis::Base} (which extends the former).
10
10
 
11
+ ## Example
12
+
11
13
  For this guide we'll be creating an analysis class that checks for local
12
14
  variables written in camelCase. Whenever it finds these variables a warning
13
15
  will be added informing the developer that he/she should use snake\_case
@@ -88,3 +90,21 @@ The full code of this exercise looks like the following:
88
90
  iterator.iterate(ast)
89
91
 
90
92
  puts presenter.present(report)
93
+
94
+ ## Conditional Analysis
95
+
96
+ In some cases you want to use a certain analysis class but only enable it if a
97
+ certain condition is met. In order to do so a analysis class should define a
98
+ class method called `analyze?` that returns a boolean that indicates if the
99
+ class should be used or not. The basic signature of this method can be seen at
100
+ {RubyLint::Analysis::Base.analyze?}.
101
+
102
+ For example, if you only want to analyze RSpec files:
103
+
104
+ class RSpecExample < RubyLint::Analysis::Base
105
+ def self.analyze?(ast, vm)
106
+ return ast.file =~ /_spec\.rb$/
107
+ end
108
+ end
109
+
110
+ By default all analysis classes are enabled.
@@ -17,6 +17,7 @@ pre.code
17
17
  {
18
18
  font-size: 13px;
19
19
  line-height: 1.4;
20
+ overflow: auto;
20
21
  }
21
22
 
22
23
  /**
Binary file
@@ -1,7 +1,5 @@
1
- gem 'racc', '>= 1.4.10'
2
1
  gem 'parser', '>= 2.0.0'
3
2
 
4
- require 'racc'
5
3
  require 'parser'
6
4
 
7
5
  # Try to load the latest parser and fall back to 2.0. This should only occur on
@@ -37,7 +35,7 @@ require_relative 'ruby-lint/node_hash'
37
35
  require_relative 'ruby-lint/cache'
38
36
  require_relative 'ruby-lint/cache_entry'
39
37
 
40
- require_relative 'ruby-lint/helper/constant_paths'
38
+ require_relative 'ruby-lint/constant_path'
41
39
 
42
40
  require_relative 'ruby-lint/definition_builder/base'
43
41
  require_relative 'ruby-lint/definition_builder/ruby_module'
@@ -11,8 +11,6 @@ module RubyLint
11
11
  # @return [RubyLint::VirtualMachine]
12
12
  #
13
13
  class Base < Iterator
14
- include Helper::ConstantPaths
15
-
16
14
  attr_reader :report, :vm
17
15
 
18
16
  ##
@@ -23,6 +21,18 @@ module RubyLint
23
21
  #
24
22
  SCOPES = [:root, :block, :class, :def, :module, :sclass]
25
23
 
24
+ ##
25
+ # Returns a boolean that indicates if the analysis class should be used
26
+ # or not.
27
+ #
28
+ # @param [RubyLint::AST::Node] ast
29
+ # @param [RubyLint::VirtualMachine] vm
30
+ # @return [TrueClass|FalseClass]
31
+ #
32
+ def self.analyze?(ast, vm)
33
+ return true
34
+ end
35
+
26
36
  ##
27
37
  # Called after a new instance of this class is created.
28
38
  #
@@ -36,8 +36,9 @@ module RubyLint
36
36
  # @param [RubyLint::AST::Node] node
37
37
  #
38
38
  def on_const(node)
39
- variable = resolve_constant_path(node)
40
- name = constant_segments(node).join('::')
39
+ path = ConstantPath.new(node)
40
+ variable = path.resolve(current_scope)
41
+ name = path.to_s
41
42
 
42
43
  error("undefined constant #{name}", node) unless variable
43
44
  end
@@ -49,8 +49,9 @@ module RubyLint
49
49
  # @param [RubyLint::AST::Node] node
50
50
  #
51
51
  def on_casgn(node)
52
- variable = resolve_constant_path(node)
53
- name = constant_segments(node).join('::')
52
+ path = ConstantPath.new(node)
53
+ variable = path.resolve(current_scope)
54
+ name = path.to_s
54
55
 
55
56
  if variable and !variable.used?
56
57
  warning("unused constant #{name}", node)
@@ -18,7 +18,7 @@ module RubyLint
18
18
  # @return [Numeric]
19
19
  #
20
20
  def column
21
- return location.expression.column if location
21
+ return location.expression.column + 1 if location
22
22
  end
23
23
 
24
24
  ##
@@ -0,0 +1,115 @@
1
+ require 'benchmark'
2
+
3
+ module RubyLint
4
+ module Benchmark
5
+ ##
6
+ # Benchmark class for measuring min/max/avg timings of a block of Ruby
7
+ # code.
8
+ #
9
+ # @!attribute [r] iterations
10
+ # @return [Numeric]
11
+ #
12
+ # @!attribute [r] precision
13
+ # @return [Numeric]
14
+ #
15
+ class Average
16
+ attr_reader :iterations, :precision
17
+
18
+ ##
19
+ # @return [Array]
20
+ #
21
+ AVERAGE_COLUMNS = %w(Iterations Minimum Maximum Average)
22
+
23
+ ##
24
+ # @return [String]
25
+ #
26
+ SEPARATOR = ' | '
27
+
28
+ ##
29
+ # Shorthand method for easily measuring a block.
30
+ #
31
+ # @see #measure
32
+ #
33
+ def self.measure(*args, &block)
34
+ new(*args).measure(&block)
35
+ end
36
+
37
+ ##
38
+ # @param [Numeric] iterations The amount of times to call the block.
39
+ # @param [Numeric] precision The amount of decimals to display.
40
+ #
41
+ def initialize(iterations = 100, precision = 6)
42
+ @iterations = iterations
43
+ @precision = precision
44
+ end
45
+
46
+ ##
47
+ # Runs the given block N times and displays the minimum, maximum and average
48
+ # execution times in secnds.
49
+ #
50
+ def measure
51
+ timings = []
52
+
53
+ iterations.times do
54
+ timings << ::Benchmark.measure { yield }.real
55
+ end
56
+
57
+ avg = timings.inject(:+) / iterations
58
+
59
+ show(timings.min, timings.max, avg)
60
+ end
61
+
62
+ ##
63
+ # @param [Numeric] min
64
+ # @param [Numeric] max
65
+ # @param [Numeric] avg
66
+ #
67
+ def show(min, max, avg)
68
+ values = [iterations.to_s] + format_values([min, max, avg])
69
+ padding = padding_length(AVERAGE_COLUMNS + values)
70
+
71
+ show_header(padding)
72
+
73
+ puts values.map { |val| val.ljust(padding) }.join(SEPARATOR)
74
+ end
75
+
76
+ private
77
+
78
+ ##
79
+ # Display the header.
80
+ #
81
+ # @param [Numeric] padding
82
+ #
83
+ def show_header(padding)
84
+ header = format_header(padding)
85
+
86
+ puts header
87
+ puts header.gsub('|', '+').gsub(/[^+]/, '-')
88
+ end
89
+
90
+ ##
91
+ # @param [Array] values
92
+ # @return [Array<String>]
93
+ #
94
+ def format_values(values)
95
+ return values.map { |val| "#{val.round(precision)} sec" }
96
+ end
97
+
98
+ ##
99
+ # @param [Numeric] padding
100
+ # @return [String]
101
+ #
102
+ def format_header(padding)
103
+ return AVERAGE_COLUMNS.map { |val| val.ljust(padding) }.join(SEPARATOR)
104
+ end
105
+
106
+ ##
107
+ # @param [Array] values
108
+ # @return [Numeric]
109
+ #
110
+ def padding_length(values)
111
+ return values.sort_by { |value| value.length }.last.length
112
+ end
113
+ end # Average
114
+ end # Benchmark
115
+ end # RubyLint
@@ -49,6 +49,10 @@ Examples:
49
49
  You can also specify multiple files:
50
50
 
51
51
  $ ruby-lint analyze first_file.rb second_file.rb
52
+
53
+ Run analysis on an entire directory:
54
+
55
+ $ ruby-lint analyze lib/
52
56
  EOF
53
57
 
54
58
  separator RubyLint::CLI::OPTIONS_HEADER
@@ -78,14 +82,28 @@ Examples:
78
82
 
79
83
  if File.file?(file)
80
84
  existing << file
85
+
86
+ elsif File.directory?(file)
87
+ existing = existing | glob_files(file)
88
+
81
89
  else
82
- abort "The file #{file} does not exist"
90
+ abort "The file/directory #{file} does not exist"
83
91
  end
84
92
  end
85
93
 
86
94
  return existing
87
95
  end
88
96
 
97
+ ##
98
+ # Returns a list of Ruby files in the given directory. This list includes
99
+ # deeply nested files.
100
+ #
101
+ # @return [Array]
102
+ #
103
+ def glob_files(directory)
104
+ return Dir.glob(File.join(directory, '**/*.rb'))
105
+ end
106
+
89
107
  ##
90
108
  # @return [Hash]
91
109
  #