autoloaded 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +8 -4
  3. data/.rspec +1 -1
  4. data/.travis.yml +1 -14
  5. data/Gemfile +10 -11
  6. data/Guardfile +22 -21
  7. data/History.md +12 -27
  8. data/README.md +48 -58
  9. data/Rakefile +0 -4
  10. data/autoloaded.gemspec +37 -41
  11. data/lib/autoloaded.rb +0 -40
  12. data/lib/autoloaded/autoloader.rb +8 -31
  13. data/lib/autoloaded/deprecation.rb +20 -11
  14. data/lib/autoloaded/inflection.rb +9 -7
  15. data/lib/autoloaded/load_pathed_directory.rb +4 -2
  16. data/lib/autoloaded/specification.rb +0 -2
  17. data/lib/autoloaded/specifications.rb +10 -16
  18. data/lib/autoloaded/version.rb +1 -1
  19. data/lib/autoloaded/warning.rb +44 -26
  20. data/lib/tasks/lib_each.rake +3 -15
  21. data/lib/tasks/spec.rake +6 -3
  22. data/spec/autoloaded/autoloader_spec.rb +469 -0
  23. data/spec/autoloaded/inflection_spec.rb +30 -0
  24. data/spec/autoloaded/load_pathed_directory_spec.rb +120 -0
  25. data/spec/autoloaded/specification_spec.rb +98 -0
  26. data/spec/autoloaded/specifications_spec.rb +191 -0
  27. data/spec/autoloaded/version_spec.rb +3 -0
  28. data/spec/autoloaded/warning_spec.rb +115 -0
  29. data/spec/autoloaded_macro_sharedspec.rb +24 -0
  30. data/spec/autoloaded_spec.rb +173 -0
  31. data/spec/fixtures/autoloaded_with_conventional_filename.rb +12 -0
  32. data/spec/fixtures/autoloaded_with_conventional_filename/N-est-ed.rb +1 -0
  33. data/spec/fixtures/autoloaded_with_conventional_filename/nest_ed.rb +1 -0
  34. data/spec/fixtures/autoloaded_with_conventional_filename/nested.rb +16 -0
  35. data/spec/fixtures/autoloaded_with_conventional_filename/nested/doubly_nested.rb +9 -0
  36. data/spec/fixtures/autoloaded_with_conventional_filename/old_school_autoload.rb +5 -0
  37. data/spec/fixtures/autoloaded_with_unconventional_filename.rb +12 -0
  38. data/spec/fixtures/autoloaded_with_unconventional_filename/N-est-ed.rb +7 -0
  39. data/spec/fixtures/autoloaded_with_unconventional_filename/nest_ed.rb +1 -0
  40. data/spec/fixtures/autoloaded_with_unconventional_filename/old_school_autoload.rb +5 -0
  41. data/spec/fixtures/filenames/AFilename.rb +0 -0
  42. data/spec/fixtures/filenames/a-file-name.rb +0 -0
  43. data/spec/fixtures/filenames/a-filename.rb +0 -0
  44. data/spec/fixtures/filenames/a_file_name.rb +0 -0
  45. data/spec/fixtures/filenames/a_filename.rb +0 -0
  46. data/spec/fixtures/filenames/afile-name.rb +0 -0
  47. data/spec/fixtures/filenames/afile_name.rb +0 -0
  48. data/spec/fixtures/not_autoloaded.rb +5 -0
  49. data/spec/fixtures/not_autoloaded/nested.rb +1 -0
  50. data/spec/fixtures/not_autoloaded/old_school_autoload.rb +5 -0
  51. data/spec/matchers.rb +85 -0
  52. data/spec/spec_helper.rb +91 -0
  53. data/spec/support/util.rb +42 -0
  54. data/spec/support/without_side_effects.rb +37 -0
  55. metadata +86 -22
  56. data/bin/console +0 -10
  57. data/bin/setup +0 -8
  58. data/lib/autoloaded/compatibility/refine_and_using.rb +0 -19
  59. data/lib/autoloaded/constant.rb +0 -94
  60. data/lib/autoloaded/refine.rb +0 -16
  61. data/lib/autoloaded/refine/string.rb +0 -20
  62. data/lib/autoloaded/refine/string/to_source_filename.rb +0 -58
@@ -5,53 +5,13 @@
5
5
  module Autoloaded
6
6
 
7
7
  autoload :Autoloader, 'autoloaded/autoloader'
8
- autoload :Constant, 'autoloaded/constant'
9
- autoload :Deprecation, 'autoloaded/deprecation'
10
8
  autoload :Inflection, 'autoloaded/inflection'
11
9
  autoload :LoadPathedDirectory, 'autoloaded/load_pathed_directory'
12
- autoload :Refine, 'autoloaded/refine'
13
10
  autoload :Specification, 'autoloaded/specification'
14
11
  autoload :Specifications, 'autoloaded/specifications'
15
12
  autoload :VERSION, 'autoloaded/version'
16
13
  autoload :Warning, 'autoloaded/warning'
17
14
 
18
- def self.extended(other_module)
19
- caller_file_path = caller_locations.first.absolute_path
20
- Deprecation.deprecate deprecated_usage: "extend #{name}",
21
- sanctioned_usage: "#{name}.module { }",
22
- source_filename: caller_file_path
23
- dir_path = "#{::File.dirname caller_file_path}/#{::File.basename caller_file_path, '.rb'}"
24
- other_module.module_eval <<-end_module_eval, __FILE__, __LINE__
25
- def self.autoload?(symbol)
26
- if (old_school = super)
27
- return old_school
28
- end
29
-
30
- require 'autoloaded/constant'
31
- filenames = []
32
- ::Autoloaded::Constant.new(symbol).each_matching_filename_in #{dir_path.inspect} do |filename|
33
- filenames << filename
34
- end
35
- (filenames.length <= 1) ? filenames.first : filenames
36
- end
37
-
38
- def self.const_missing(symbol)
39
- require 'autoloaded/constant'
40
- ::Autoloaded::Constant.new(symbol).each_matching_filename_in #{dir_path.inspect} do |filename|
41
- require filename
42
- if const_defined?(symbol)
43
- begin
44
- return const_get(symbol)
45
- rescue ::NameError
46
- end
47
- end
48
- end
49
-
50
- super
51
- end
52
- end_module_eval
53
- end
54
-
55
15
  # @!method self.module
56
16
  # Autoloads constants that match files in the source directory.
57
17
  #
@@ -1,9 +1,3 @@
1
- require 'autoloaded/inflection'
2
- require 'autoloaded/load_pathed_directory'
3
- require 'autoloaded/specification'
4
- require 'autoloaded/specifications'
5
- require 'autoloaded/warning'
6
-
7
1
  module Autoloaded
8
2
 
9
3
  # Autoloads files in a source directory.
@@ -13,7 +7,7 @@ module Autoloaded
13
7
 
14
8
  # The source code context in which autoloading is to occur.
15
9
  #
16
- # @return [Binding]
10
+ # @return [Binding] the source code context in which autoloading is to occur.
17
11
  #
18
12
  # @see #autoload!
19
13
  #
@@ -41,8 +35,8 @@ module Autoloaded
41
35
  # @return [Array of Array] the arguments passed to each +autoload+ statement
42
36
  # made
43
37
  #
44
- # @see https://ruby-doc.org/core/Module.html#method-i-autoload Module#autoload
45
- # @see https://ruby-doc.org/core/Kernel.html#method-i-autoload Kernel#autoload
38
+ # @see http://ruby-doc.org/core/Module.html#method-i-autoload Module#autoload
39
+ # @see http://ruby-doc.org/core/Kernel.html#method-i-autoload Kernel#autoload
46
40
  # @see #from
47
41
  # @see #except
48
42
  # @see #only
@@ -85,11 +79,6 @@ module Autoloaded
85
79
  constant_names.each do |const|
86
80
  next unless existing_constant?(const)
87
81
 
88
- # Don't warn about an existing MyAwesomeGem::VERSION constant since
89
- # probably it was loaded by a `require 'my_awesome_gem/version'`
90
- # statement in 'my_awesome_gem.gemspec'.
91
- next if (const == :VERSION)
92
-
93
82
  Warning.existing_constant constant_name: constant_full_name(const),
94
83
  source_filename: source_filename,
95
84
  host_source_location: host_source_location
@@ -177,7 +166,7 @@ module Autoloaded
177
166
  #
178
167
  # @see #autoload!
179
168
  # @see #from
180
- %i(except only with).each do |attr|
169
+ [:except, :only, :with].each do |attr|
181
170
  define_method attr do |*arguments|
182
171
  attr_specs = specifications.send(attr)
183
172
  if arguments.empty?
@@ -213,10 +202,7 @@ module Autoloaded
213
202
  # @see #autoload!
214
203
  # @see #host_binding
215
204
  def from(value=nil)
216
- if value.nil?
217
- return (instance_variable_defined?(:@from) && @from && @from.path) ||
218
- default_from
219
- end
205
+ return((@from && @from.path) || default_from) if value.nil?
220
206
 
221
207
  # Validate value.
222
208
  @from = LoadPathedDirectory.new(value)
@@ -252,8 +238,7 @@ module Autoloaded
252
238
  end
253
239
 
254
240
  def from_load_pathed_directory
255
- (instance_variable_defined?(:@from) && @from) ||
256
- LoadPathedDirectory.new(default_from)
241
+ @from || LoadPathedDirectory.new(default_from)
257
242
  end
258
243
 
259
244
  def host_eval(statement)
@@ -263,19 +248,11 @@ module Autoloaded
263
248
  end
264
249
 
265
250
  def host_source_filename
266
- if host_binding.respond_to?(:source_location)
267
- host_eval "::File.expand_path '#{host_binding.source_location.first}'"
268
- else
269
- host_eval '::File.expand_path __FILE__'
270
- end
251
+ host_eval '::File.expand_path __FILE__'
271
252
  end
272
253
 
273
254
  def host_source_location
274
- if host_binding.respond_to?(:source_location)
275
- host_binding.source_location
276
- else
277
- host_eval('[__FILE__, __LINE__]')
278
- end.collect(&:to_s).join ':'
255
+ host_eval('[__FILE__, __LINE__]').collect(&:to_s).join ':'
279
256
  end
280
257
 
281
258
  end
@@ -1,3 +1,5 @@
1
+ module Autoloaded; end
2
+
1
3
  # Prints deprecation messages to _stderr_.
2
4
  #
3
5
  # @since 1.3
@@ -22,21 +24,28 @@ module Autoloaded::Deprecation
22
24
  # Prints a deprecation message to _#io_ regarding the specified
23
25
  # _deprecated_usage_.
24
26
  #
25
- # @param [String] deprecated_usage API usage that is soon to be discontinued
26
- # @param [String] sanctioned_usage API usage that will succeed
27
- # _deprecated_usage_
28
- # @param [String] source_filename the file path of the source invoking the
29
- # deprecated API
27
+ # @param [Hash] keywords the parameters of the deprecation message
28
+ # @option keywords [String] :deprecated_usage API usage that is soon to be
29
+ # discontinued
30
+ # @option keywords [String] :sanctioned_usage API usage that will succeed
31
+ # _:deprecated_usage_
32
+ # @option keywords [String] :source_filename the file path of the source
33
+ # invoking the deprecated API
30
34
  #
31
35
  # @return [Module] _Deprecation_
32
36
  #
33
37
  # @raise [ArgumentError] one or more keywords are missing
34
- def deprecate(deprecated_usage: raise(::ArgumentError,
35
- 'missing keyword: deprecated_usage'),
36
- sanctioned_usage: raise(::ArgumentError,
37
- 'missing keyword: sanctioned_usage'),
38
- source_filename: raise(::ArgumentError,
39
- 'missing keyword: source_filename'))
38
+ def deprecate(keywords)
39
+ deprecated_usage = keywords.fetch :deprecated_usage do
40
+ raise ::ArgumentError, 'missing keyword: deprecated_usage'
41
+ end
42
+ sanctioned_usage = keywords.fetch :sanctioned_usage do
43
+ raise ::ArgumentError, 'missing keyword: sanctioned_usage'
44
+ end
45
+ source_filename = keywords.fetch :source_filename do
46
+ raise ::ArgumentError, 'missing keyword: source_filename'
47
+ end
48
+
40
49
  deprecation = "\e[33m*** \e[7m DEPRECATED \e[0m " +
41
50
  "\e[4m#{deprecated_usage}\e[0m -- use " +
42
51
  "\e[4m#{sanctioned_usage}\e[0m instead in #{source_filename}"
@@ -1,6 +1,8 @@
1
+ module Autoloaded; end
2
+
1
3
  # Translates source filenames into constants.
2
- #
3
- # @since 1.3
4
+ #
5
+ # @since 1.3
4
6
  #
5
7
  # @api private
6
8
  module Autoloaded::Inflection
@@ -19,11 +21,11 @@ module Autoloaded::Inflection
19
21
  source_filename = source_filename.to_s
20
22
  raise(::ArgumentError, "can't be blank") if source_filename.empty?
21
23
 
22
- translate(source_filename, *%i(file_basename
23
- camelize_if_lowercase
24
- nonalphanumeric_to_underscore
25
- delete_leading_nonalphabetic
26
- capitalize_first)).to_sym
24
+ translate(source_filename, *[:file_basename,
25
+ :camelize_if_lowercase,
26
+ :nonalphanumeric_to_underscore,
27
+ :delete_leading_nonalphabetic,
28
+ :capitalize_first]).to_sym
27
29
  end
28
30
 
29
31
  private
@@ -1,5 +1,7 @@
1
1
  require 'pathname'
2
2
 
3
+ module Autoloaded; end
4
+
3
5
  # Enumerates the source files in a directory, relativizing their paths using the
4
6
  # Ruby load path.
5
7
  #
@@ -61,7 +63,7 @@ public
61
63
  # @return [LoadPathedDirectory] the _LoadPathedDirectory_
62
64
  #
63
65
  # @see #path
64
- # @see https://ruby-doc.org/core/Kernel.html#method-i-require Kernel#require
66
+ # @see http://ruby-doc.org/core/Kernel.html#method-i-require Kernel#require
65
67
  def each_source_filename
66
68
  if (ruby_load_path = closest_ruby_load_path)
67
69
  ::Dir.chdir ruby_load_path do
@@ -95,7 +97,7 @@ private
95
97
  # Don't use Pathname#relative_path_from because we want to avoid introducing
96
98
  # double dots. The intent is to render the path as relative, if and only if
97
99
  # it is a subdirectory of 'other_path'.
98
- pattern = /^#{::Regexp.escape other_path.to_s.chomp(::File::SEPARATOR)}#{::Regexp.escape ::File::SEPARATOR}?/
100
+ pattern = /^#{::Regexp.escape other_path.chomp(::File::SEPARATOR)}#{::Regexp.escape ::File::SEPARATOR}?/
99
101
  path.gsub pattern, ''
100
102
  end
101
103
 
@@ -1,5 +1,3 @@
1
- require 'autoloaded/inflection'
2
-
3
1
  module Autoloaded
4
2
 
5
3
  # Describes regulations for autoloading.
@@ -1,3 +1,5 @@
1
+ module Autoloaded; end
2
+
1
3
  # Holds regulations for autoloading.
2
4
  #
3
5
  # @since 1.3
@@ -6,40 +8,32 @@
6
8
  class Autoloaded::Specifications
7
9
 
8
10
  # @!method except
9
- # _Specifications_ for excluding source files from being autoloaded.
10
- #
11
- # @return [Array of Specification]
11
+ # Specifications for excluding source files from being autoloaded.
12
12
  #
13
- # @see Specification
13
+ # @return [Array of Specification] a list of specifications
14
14
  #
15
15
  # @api private
16
16
  #
17
17
  # @!method only
18
- # _Specifications_ for narrowing the set of source files being autoloaded as
18
+ # Specifications for narrowing the set of source files being autoloaded as
19
19
  # well as optionally renaming and/or reorganizing their corresponding
20
20
  # constants.
21
21
  #
22
- # @return [Array of Specification]
23
- #
24
- # @see Specification
22
+ # @return [Array of Specification] a list of specifications
25
23
  #
26
24
  # @api private
27
25
  #
28
26
  # @!method with
29
- # _Specifications_ for renaming and/or reorganizing the constants corresponding
27
+ # Specifications for renaming and/or reorganizing the constants corresponding
30
28
  # to source files being autoloaded.
31
29
  #
32
- # @return [Array of Specification]
33
- #
34
- # @see Specification
30
+ # @return [Array of Specification] a list of specifications
35
31
  #
36
32
  # @api private
37
- %i(except only with).each do |attribute_name|
33
+ [:except, :only, :with].each do |attribute_name|
38
34
  define_method attribute_name do
39
35
  variable_name = "@#{attribute_name}"
40
- ((instance_variable_defined?(variable_name) &&
41
- instance_variable_get(variable_name)) ||
42
- []).tap do |value|
36
+ (instance_variable_get(variable_name) || []).tap do |value|
43
37
  instance_variable_set variable_name, value
44
38
  end
45
39
  end
@@ -3,6 +3,6 @@ module Autoloaded
3
3
  # The current version of the _Autoloaded_ project.
4
4
  #
5
5
  # @since 0.0.1
6
- VERSION = '1.6.0'
6
+ VERSION = '2.0.0'
7
7
 
8
8
  end
@@ -1,3 +1,5 @@
1
+ module Autoloaded; end
2
+
1
3
  # Prints warning messages to _stderr_.
2
4
  #
3
5
  # @since 1.3
@@ -22,25 +24,33 @@ module Autoloaded::Warning
22
24
  # Prints a warning message to _#io_ concerning an existing autoloaded
23
25
  # constant for which the autoloaded source file is being changed.
24
26
  #
25
- # @param [Symbol] constant_name the name of the constant
26
- # @param [String] old_source_filename the name of the existing autoloaded
27
- # source file
28
- # @param [String] new_source_filename the name of the new autoloaded source
29
- # file
30
- # @param [String] host_source_location the file and line number of the source
31
- # establishing autoloading
27
+ # @param [Hash] keywords the parameters of the warning message
28
+ # @option keywords [Symbol] :constant_name the name of the constant
29
+ # @option keywords [String] :old_source_filename the name of the existing
30
+ # autoloaded source file
31
+ # @option keywords [String] :new_source_filename the name of the new
32
+ # autoloaded source file
33
+ # @option keywords [String] :host_source_location the file and line number of
34
+ # the source establishing
35
+ # autoloading
32
36
  #
33
37
  # @return [Module] _Warning_
34
38
  #
35
39
  # @raise [ArgumentError] one or more keywords are missing
36
- def changing_autoload(constant_name: raise(::ArgumentError,
37
- 'missing keyword: constant_name'),
38
- old_source_filename: raise(::ArgumentError,
39
- 'missing keyword: old_source_filename'),
40
- new_source_filename: raise(::ArgumentError,
41
- 'missing keyword: new_source_filename'),
42
- host_source_location: raise(::ArgumentError,
43
- 'missing keyword: host_source_location'))
40
+ def changing_autoload(keywords)
41
+ constant_name = keywords.fetch :constant_name do
42
+ raise ::ArgumentError, 'missing keyword: constant_name'
43
+ end
44
+ old_source_filename = keywords.fetch :old_source_filename do
45
+ raise ::ArgumentError, 'missing keyword: old_source_filename'
46
+ end
47
+ new_source_filename = keywords.fetch :new_source_filename do
48
+ raise ::ArgumentError, 'missing keyword: new_source_filename'
49
+ end
50
+ host_source_location = keywords.fetch :host_source_location do
51
+ raise ::ArgumentError, 'missing keyword: host_source_location'
52
+ end
53
+
44
54
  message = "Existing autoload of \e[4m#{constant_name}\e[0m from " +
45
55
  "#{old_source_filename.inspect} is being overridden to " +
46
56
  "autoload from #{new_source_filename.inspect} -- avoid this " +
@@ -62,7 +72,7 @@ module Autoloaded::Warning
62
72
  #
63
73
  # @see .enabled?
64
74
  def enable(enabling)
65
- previous_value = instance_variable_defined?(:@disabled) && @disabled
75
+ previous_value = @disabled
66
76
  @disabled = not!(enabling)
67
77
  if block_given?
68
78
  begin
@@ -88,20 +98,28 @@ module Autoloaded::Warning
88
98
  # Prints a warning message to _#io_ concerning a defined constant for which
89
99
  # autoloading is being established.
90
100
  #
91
- # @param [Symbol] constant_name the name of the constant
92
- # @param [String] source_filename the name of the autoloaded source file
93
- # @param [String] host_source_location the file and line number of the source
94
- # establishing autoloading
101
+ # @param [Hash] keywords the parameters of the warning message
102
+ # @option keywords [Symbol] :constant_name the name of the constant
103
+ # @option keywords [String] :source_filename the name of the autoloaded
104
+ # source file
105
+ # @option keywords [String] :host_source_location the file and line number of
106
+ # the source establishing
107
+ # autoloading
95
108
  #
96
109
  # @return [Module] _Warning_
97
110
  #
98
111
  # @raise [ArgumentError] one or more keywords are missing
99
- def existing_constant(constant_name: raise(::ArgumentError,
100
- 'missing keyword: constant_name'),
101
- source_filename: raise(::ArgumentError,
102
- 'missing keyword: source_filename'),
103
- host_source_location: raise(::ArgumentError,
104
- 'missing keyword: host_source_location'))
112
+ def existing_constant(keywords)
113
+ constant_name = keywords.fetch :constant_name do
114
+ raise ::ArgumentError, 'missing keyword: constant_name'
115
+ end
116
+ source_filename = keywords.fetch :source_filename do
117
+ raise ::ArgumentError, 'missing keyword: source_filename'
118
+ end
119
+ host_source_location = keywords.fetch :host_source_location do
120
+ raise ::ArgumentError, 'missing keyword: host_source_location'
121
+ end
122
+
105
123
  message = "Existing definition of \e[4m#{constant_name}\e[0m obviates " +
106
124
  "autoloading from #{source_filename.inspect} -- avoid this " +
107
125
  "warning by using an \e[4monly\e[0m or an \e[4mexcept\e[0m " +
@@ -1,25 +1,13 @@
1
1
  namespace :lib do
2
- desc "Check the source for missing 'require' statements. Set the 'VERBOSE' " +
3
- 'environment variable to "t[rue]" to display the name of each file as ' +
4
- 'it is loaded.'
2
+ desc "Load each library file individually, looking for missing 'require' statements"
5
3
  task :each do
6
- def verbose?
7
- ENV['VERBOSE'].to_s =~ /^T/i
8
- end
9
-
10
4
  Dir.chdir 'lib' do
11
5
  Dir.glob( '**/*.rb' ) do |f|
12
6
  next if f == 'tasks.rb'
13
7
 
14
- if verbose?
15
- puts "* #{f}"
16
- else
17
- print "\e[32m.\e[0m"
18
- end
19
- command = "/usr/bin/env ruby -e 'require File.expand_path(#{f.inspect})'"
20
- break unless system(command)
8
+ puts "Loading #{f} ..."
9
+ fail unless system( "/usr/bin/env bundle exec ruby -e 'require #{f.inspect}'" )
21
10
  end
22
11
  end
23
- puts unless verbose?
24
12
  end
25
13
  end
@@ -44,8 +44,7 @@ else
44
44
  else
45
45
  noun_phrase = "#{uncommitted_spec_files.length} uncommitted spec file#{(uncommitted_spec_files.length == 1) ? nil : 's'}"
46
46
  desc = "Run #{noun_phrase}"
47
- define_spec_task :uncommitted, desc: desc,
48
- pattern: uncommitted_spec_files
47
+ define_spec_task :uncommitted, desc: desc, pattern: uncommitted_spec_files
49
48
  end
50
49
  else
51
50
  noun_phrase = "#{uncommitted_files_in_spec.length} uncommitted file#{uncommitted_files_in_spec.length == 1 ? nil : 's'}"
@@ -53,12 +52,16 @@ else
53
52
  define_spec_task :uncommitted, desc: desc, pattern: 'spec'
54
53
  end
55
54
 
56
- define_spec_task :warnings, desc: 'Run specs with Ruby warnings enabled',
55
+ define_spec_task :warnings, desc: 'Run specs with Ruby warnings enabled',
57
56
  format: :progress,
58
57
  profile: false,
59
58
  warnings: true
60
59
  end
61
60
 
61
+ desc 'Run specs'
62
+ task '' => :spec
63
+ task :default => :spec
64
+
62
65
  # Support the 'gem test' command.
63
66
  define_spec_task :test, desc: '', backtrace: true,
64
67
  debug: false,