lazy_load 0.0.2

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.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+
2
+ .rvmrc
3
+ .yardoc
4
+ doc
5
+ *.swp
6
+ *.gem
7
+ *.rbc
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+
2
+ 0.0.2
3
+ Initial version
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jostein Berre Eliassen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+
2
+ LazyLoad
3
+ ========
4
+
5
+ **Unobtrusively autoload code with callbacks and helpful errors**
6
+
7
+ ---
8
+
9
+ LazyLoad is a more elaborate alternative to the [autoload](http://ruby-doc.org/core/classes/Module.html#M000443) method. For instance, it allows setting up callbacks to be invoked when a certain constant is referenced. It is used in scenarios where you need to "soft require" something -- typically to find the "best available" implementation, or fail gracefully when dependencies are not met.
10
+
11
+ Unlike autoload, LazyLoad is scoped, and it does therefore not pollute or monkey patch. What this means is: When you register a callback for the `Foo` constant, referencing `LazyLoad::Foo` will trigger the callback. Simply referencing `Foo` will not trigger the callback.
12
+
13
+ ### Samples
14
+
15
+ ```bash
16
+
17
+ gem install lazy_load`
18
+
19
+ ```
20
+
21
+ ```ruby
22
+
23
+ LazyLoad.map(:Tilt, 'tilt',
24
+ 'Tilt not found. Possible fix: gem install tilt')
25
+
26
+ # or equivalent with a callback:
27
+
28
+ LazyLoad.map(:Tilt) do
29
+ begin
30
+ require 'tilt'
31
+ Tilt
32
+ rescue LoadError
33
+ raise(LazyLoad::DependencyError,
34
+ 'Tilt not found. Possible fix: gem install tilt')
35
+ end
36
+ end
37
+
38
+ Tilt
39
+ # => NameError: uninitialized constant Object::Tilt
40
+
41
+ LazyLoad::Tilt
42
+ # => Tilt
43
+
44
+ # or if Tilt is not available:
45
+
46
+ LazyLoad::Tilt
47
+ # => LazyLoad::DependencyError: Tilt not found. Possible fix: gem install tilt'
48
+
49
+ LazyLoad::Foo
50
+ # => NameError: uninitialized constant LazyLoad::Foo
51
+
52
+ ```
53
+
54
+ Notice how, when a block is used, it must return the constant. The help message is optional. LazyLoad has no mappings by default.
55
+
56
+
57
+ ### Errors
58
+
59
+ Referencing constant beneath `LazyLoad` for which there is no mapping, resuslts in the usual `NameError`. Referencing an unavailable constant typically gives a `LazyLoad::DependencyError`, which conveniently is also a subclass of `NameError`.
60
+
61
+
62
+ ### Best available
63
+
64
+ You can use the `best` method to return the first constant from a list of names, or else raise a `LazyLoad::DependencyError` for the first (most preferred) one.
65
+
66
+ ```ruby
67
+ LazyLoad.best(:Kramdown, :RDiscount, :Redcarpet)
68
+
69
+ ```
70
+
71
+
72
+ ### Scopes
73
+
74
+ Use the `scope` method if you need more than one scope (typically for gem interoperability).
75
+
76
+ ```ruby
77
+ module SomeProject
78
+ Lazy = LazyLoad.scope do
79
+ map(:StringIO, 'stringio')
80
+ end
81
+
82
+ Lazy.map(:Tilt, 'tilt')
83
+
84
+ Lazy::StringIO # => StringIO
85
+ Lazy::Tilt # => Tilt
86
+ end
87
+ ```
88
+
89
+ Feedback and suggestions are welcome through Github.
90
+
91
+ ---
92
+
93
+ © 2011 Jostein Berre Eliassen. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+
2
+ task :test do
3
+ $LOAD_PATH.unshift './lib'
4
+ require 'lazy_load'
5
+ require 'minitest/autorun'
6
+ begin; require 'turn'; rescue LoadError; end
7
+ Dir.glob("test/**/*_test.rb").each { |test| require "./#{test}" }
8
+ end
9
+
10
+ task :shell do
11
+ system 'pry -I lib -r lazy_load --trace'
12
+ end
13
+
14
+ task :default => :test
15
+
16
+
17
+
data/lazy_load.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'lazy_load'
3
+
4
+ Gem::Specification.new do |s|
5
+
6
+ s.name = 'lazy_load'
7
+
8
+ s.author = 'Jostein Berre Eliassen'
9
+ s.email = 'josteinpost@gmail.com'
10
+ s.homepage = "http://github.com/jbe/lazy_load"
11
+ s.license = "MIT"
12
+
13
+ s.version = LazyLoad::VERSION
14
+ s.platform = Gem::Platform::RUBY
15
+
16
+ s.summary = 'An unobtrusive way to autoload code with callbacks ' +
17
+ 'and helpful errors.'
18
+
19
+ s.description = 'LazyLoad is a more elaborate alternative to the ' +
20
+ 'autoload method. For instance, it allows setting ' +
21
+ 'up callbacks to be invoked when a certain constant ' +
22
+ 'is referenced. It does not monkey patch or ' +
23
+ 'pollute the global namespace.'
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- test/*`.split("\n")
27
+ s.require_path = 'lib'
28
+ end
data/lib/lazy_load.rb ADDED
@@ -0,0 +1,74 @@
1
+
2
+
3
+
4
+ module LazyLoad
5
+
6
+ VERSION = '0.0.2'
7
+
8
+ class DependencyError < NameError; end
9
+
10
+ module Methods
11
+
12
+ def reset!
13
+ @messages = {}
14
+ @actions = {}
15
+ self
16
+ end
17
+
18
+ def scope(&blk)
19
+ mod = Module.new.extend(LazyLoad::Methods).reset!
20
+ mod.module_eval(&blk) if blk
21
+ mod
22
+ end
23
+
24
+ def map(name, action=nil, msg=nil, &blk)
25
+ @messages[name] = msg
26
+ @actions[name] = blk || action || raise(
27
+ ArgumentError, "missing require path or callback")
28
+ end
29
+
30
+ def unmap(name)
31
+ @messages.delete(name)
32
+ @actions.delete(name)
33
+ end
34
+
35
+ def const_missing(name)
36
+ k = case action = @actions[name]
37
+ when String then helpful_require(name)
38
+ when Proc then action.call
39
+ when nil then super
40
+ else raise "Invalid action for dependency #{action.inspect}"
41
+ end
42
+ const_set(name, k)
43
+ end
44
+
45
+ def helpful_require(name)
46
+ begin
47
+ require @actions[name]
48
+ Kernel.const_get(name)
49
+ rescue LoadError
50
+ raise(DependencyError, @messages[name] ||
51
+ "failed to require #{@actions[name].inspect}.")
52
+ end
53
+ end
54
+
55
+ # Return the first available dependency from the
56
+ # list of constant names.
57
+ #
58
+ def best(*names)
59
+ names.each do |name|
60
+ begin
61
+ return const_get(name)
62
+ rescue NameError; end
63
+ end
64
+ const_get(names.first)
65
+ end
66
+ alias :first_available :best
67
+
68
+ end
69
+
70
+ extend Methods
71
+ reset!
72
+
73
+ end
74
+
data/test/helper.rb ADDED
@@ -0,0 +1,15 @@
1
+
2
+ class TestCase < MiniTest::Unit::TestCase
3
+
4
+ def self.test(name, &block)
5
+ test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
6
+ defined = instance_method(test_name) rescue false
7
+ #raise "#{test_name} already defined in #{self}" if defined
8
+
9
+ block ||= proc { skip }
10
+ define_method(test_name, &block)
11
+ end
12
+
13
+ end
14
+
15
+
@@ -0,0 +1,103 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+
3
+ class LazyLoadTest < TestCase
4
+
5
+
6
+ # helpers:
7
+
8
+ def with_mappings(*args)
9
+ LazyLoad.map(:StringIO, 'stringio', 'stringio not in stdlib?')
10
+ LazyLoad.map(:Bogus, 'thishastobebogusnow', 'bogus lib not found')
11
+ LazyLoad.map(:Message) { 'love' }
12
+ LazyLoad.map(:Unavailable) do
13
+ raise LazyLoad::DependencyError, 'not available'
14
+ end
15
+ yield
16
+ LazyLoad.reset!
17
+ end
18
+
19
+
20
+ # basic
21
+
22
+ test 'raises name error' do
23
+ assert_raises(NameError) do
24
+ LazyLoad::Nonexistant
25
+ end
26
+ end
27
+
28
+ test 'requires existing' do
29
+ with_mappings do
30
+ assert LazyLoad::StringIO == StringIO
31
+ end
32
+ end
33
+
34
+ test 'require fails with message when unavailable' do
35
+ with_mappings do
36
+ assert_raises(LazyLoad::DependencyError) do
37
+ LazyLoad::Bogus
38
+ end
39
+ end
40
+ end
41
+
42
+ test 'callback' do
43
+ with_mappings do
44
+ assert LazyLoad::Message == "love"
45
+ end
46
+ end
47
+
48
+ test 'callback with dependency error' do
49
+ with_mappings do
50
+ assert_raises(LazyLoad::DependencyError) do
51
+ LazyLoad::Unavailable
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+ # first_available
58
+
59
+ test 'returns first when first available is first' do
60
+ with_mappings do
61
+ assert_equal(
62
+ 'love',
63
+ LazyLoad.best(:Message, :StringIO, :Unavailable)
64
+ )
65
+ end
66
+ end
67
+
68
+ test 'returns third when first available is third' do
69
+ with_mappings do
70
+ assert_equal(
71
+ 'StringIO',
72
+ LazyLoad.best(:Bogus, :Unavailable, :StringIO, :Message).name
73
+ )
74
+ end
75
+ end
76
+
77
+ test 'fails with first message when none available' do
78
+ with_mappings do
79
+ assert_raises LazyLoad::DependencyError do
80
+ LazyLoad.best(:Bogus, :Unavailable, :Bogus)
81
+ end
82
+ end
83
+ end
84
+
85
+
86
+ # new_scope
87
+
88
+ test 'scope independent of source' do
89
+ with_mappings do
90
+ scope = LazyLoad.scope
91
+ scope.map(:StringIO, 'not_anymore')
92
+
93
+ assert_equal('StringIO', LazyLoad::StringIO.name)
94
+ assert_raises(LazyLoad::DependencyError) do
95
+ scope::StringIO
96
+ end
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+
103
+
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lazy_load
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Jostein Berre Eliassen
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-06-06 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: LazyLoad is a more elaborate alternative to the autoload method. For instance, it allows setting up callbacks to be invoked when a certain constant is referenced. It does not monkey patch or pollute the global namespace.
22
+ email: josteinpost@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - .gitignore
31
+ - CHANGELOG
32
+ - LICENSE
33
+ - README.md
34
+ - Rakefile
35
+ - lazy_load.gemspec
36
+ - lib/lazy_load.rb
37
+ - test/helper.rb
38
+ - test/lazy_load_test.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/jbe/lazy_load
41
+ licenses:
42
+ - MIT
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.7
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: An unobtrusive way to autoload code with callbacks and helpful errors.
71
+ test_files:
72
+ - test/helper.rb
73
+ - test/lazy_load_test.rb