use 1.0.0 → 1.1.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.
- data/CHANGES +11 -2
- data/MANIFEST +2 -0
- data/README +76 -54
- data/lib/use.rb +122 -18
- data/test/tc_use.rb +115 -49
- metadata +5 -5
data/CHANGES
CHANGED
@@ -1,2 +1,11 @@
|
|
1
|
-
== 1-
|
2
|
-
*
|
1
|
+
== 1.1.0 - 20-Jan-2006
|
2
|
+
* Using 'use' with no arguments is now the same as if you used 'include',
|
3
|
+
i.e. all methods are mixed in. Previously, this would not mixin any methods.
|
4
|
+
* Added finer control of mixed in methods by allowing the use of three keyword
|
5
|
+
arguments - 'include', 'exclude' and 'alias'. See the documentation for
|
6
|
+
more details.
|
7
|
+
* Added more inline documentation.
|
8
|
+
* More tests and examples.
|
9
|
+
|
10
|
+
== 1.0.0 - 1-Aug-2005
|
11
|
+
* Initial release
|
data/MANIFEST
CHANGED
data/README
CHANGED
@@ -1,54 +1,76 @@
|
|
1
|
-
== Description
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
== Prerequisites
|
6
|
-
|
7
|
-
|
8
|
-
== Installation
|
9
|
-
=== Standard
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
=== Gem install
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
== Synopsis
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
1
|
+
== Description
|
2
|
+
The 'use' package allows you to selectively mixin methods from a given
|
3
|
+
module.
|
4
|
+
|
5
|
+
== Prerequisites
|
6
|
+
Ruby 1.8.0 or later
|
7
|
+
|
8
|
+
== Installation
|
9
|
+
=== Standard
|
10
|
+
ruby test/tc_use.rb (optional)
|
11
|
+
ruby install.rb
|
12
|
+
|
13
|
+
=== Gem install
|
14
|
+
ruby test/tc_use.rb (optional)
|
15
|
+
ruby use.gemspec
|
16
|
+
gem install use.gem
|
17
|
+
|
18
|
+
== Synopsis
|
19
|
+
module Foo
|
20
|
+
def bar
|
21
|
+
"hello"
|
22
|
+
end
|
23
|
+
def baz
|
24
|
+
"world"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Test
|
29
|
+
def bar
|
30
|
+
"goodbye"
|
31
|
+
end
|
32
|
+
def blah
|
33
|
+
"new york"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Zap
|
38
|
+
use Foo, :bar
|
39
|
+
use Test, :blah
|
40
|
+
end
|
41
|
+
|
42
|
+
z = Zap.new
|
43
|
+
|
44
|
+
z.bar # "hello"
|
45
|
+
z.baz # NoMethodError
|
46
|
+
z.blah # "new york"
|
47
|
+
|
48
|
+
# Using the new keywords
|
49
|
+
class MyKlass
|
50
|
+
use Foo :alias => {:bar, :test}
|
51
|
+
end
|
52
|
+
|
53
|
+
m = MyKlass.new
|
54
|
+
m.test # "hello"
|
55
|
+
m.bar # NoMethodError
|
56
|
+
|
57
|
+
== Acknowledgements
|
58
|
+
Thanks go to Ara Howard for providing the original solution and to
|
59
|
+
Mauricio Fernandez, who's blog I plagiarized to get the spoonful style
|
60
|
+
mixins.
|
61
|
+
|
62
|
+
== Known Bugs
|
63
|
+
None that I'm aware of. If you find any, please log them on the project
|
64
|
+
page at http://www.rubyforge.org/projects/shards.
|
65
|
+
|
66
|
+
== License
|
67
|
+
Ruby's
|
68
|
+
|
69
|
+
== Copyright
|
70
|
+
(C) 2005-2006, Daniel J. Berger
|
71
|
+
All Rights Reserved
|
72
|
+
|
73
|
+
== Author
|
74
|
+
Daniel J. Berger
|
75
|
+
djberg96 at gmail dot com
|
76
|
+
IRC nickname: imperator/mok (freenode)
|
data/lib/use.rb
CHANGED
@@ -1,18 +1,122 @@
|
|
1
|
-
class Module
|
2
|
-
# VERSION 1.
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
1
|
+
class Module
|
2
|
+
# VERSION = "1.1.0"
|
3
|
+
|
4
|
+
# :call-seq:
|
5
|
+
# use module, methods
|
6
|
+
# # or
|
7
|
+
# use module, option => value, ...
|
8
|
+
#
|
9
|
+
# The 'use' directive allows you to selectively mixin +methods+ from the
|
10
|
+
# given +module+. The +methods+ may be either strings or symbols. If
|
11
|
+
# no methods are provided then 'use' is effectively the same thing as
|
12
|
+
# 'include', i.e. all methods are mixed in.
|
13
|
+
#
|
14
|
+
# If a Hash is provided, there are three keywords available to you:
|
15
|
+
#
|
16
|
+
# * 'include'
|
17
|
+
# This option lets you specify one or more methods to explicitly include.
|
18
|
+
# If you wish to include more than one method, use an array as the value.
|
19
|
+
#
|
20
|
+
# * 'exclude'
|
21
|
+
# This option lets you specify one or more methods to explicitly exclude.
|
22
|
+
# If you wish to exclude more than one method, use an array as the value.
|
23
|
+
#
|
24
|
+
# * 'alias'
|
25
|
+
# This option lets you include a method, but as a different method name.
|
26
|
+
# Use a hash as the value to +alias+, e.g. :alias => {:old, :new, ... }.
|
27
|
+
# Using this option doubles as an explicit include, so you do not need
|
28
|
+
# to both include and alias in the same statement.
|
29
|
+
#
|
30
|
+
# Note that the original method name is NOT included if aliased this way.
|
31
|
+
#
|
32
|
+
# Also note that you cannot include and exclude in the same statement,
|
33
|
+
# or an ArgumentError is raised. You can, however, exclude and alias.
|
34
|
+
#
|
35
|
+
def use(mod, *methods)
|
36
|
+
valid = %w/include exclude alias/
|
37
|
+
included = []
|
38
|
+
excluded = []
|
39
|
+
aliased = []
|
40
|
+
|
41
|
+
m = Module.new
|
42
|
+
|
43
|
+
# If the first argument is a Hash, verify the keywords and push values
|
44
|
+
# onto the appropriate array for later processing.
|
45
|
+
#
|
46
|
+
if methods.first.kind_of?(Hash)
|
47
|
+
methods = methods.first
|
48
|
+
methods.each{ |key, val|
|
49
|
+
unless valid.include?(key.to_s.downcase)
|
50
|
+
raise ArgumentError, "invalid key: #{key}"
|
51
|
+
end
|
52
|
+
|
53
|
+
if key.to_s == "include"
|
54
|
+
if val.respond_to?(:each)
|
55
|
+
val.each{ |arg| included.push(arg.to_sym) }
|
56
|
+
else
|
57
|
+
included.push(val.to_sym)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if key.to_s == "exclude"
|
62
|
+
if val.respond_to?(:each)
|
63
|
+
val.each{ |arg| excluded.push(arg.to_sym) }
|
64
|
+
else
|
65
|
+
excluded.push(val.to_sym)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if key.to_s == "alias"
|
70
|
+
aliased.push(val)
|
71
|
+
end
|
72
|
+
}
|
73
|
+
else
|
74
|
+
if methods.empty?
|
75
|
+
module_eval{ include mod } # Mixin all methods if no arguments
|
76
|
+
else
|
77
|
+
m.module_eval do
|
78
|
+
include mod
|
79
|
+
all_methods = mod.instance_methods
|
80
|
+
unn_methods = all_methods - methods.map{ |method| method.to_s }
|
81
|
+
undef_method(*unn_methods)
|
82
|
+
end
|
83
|
+
module_eval{ include m }
|
84
|
+
end
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
unless included.empty? || excluded.empty?
|
89
|
+
err = "you cannot include and exclude in the same statement"
|
90
|
+
raise ArgumentError, err
|
91
|
+
end
|
92
|
+
|
93
|
+
m.module_eval{
|
94
|
+
include mod
|
95
|
+
|
96
|
+
aliased.each{ |pair|
|
97
|
+
pair.each{ |old, new|
|
98
|
+
included.push(old) # Aliased methods automatically included
|
99
|
+
alias_method(new, old) # Alias the old method
|
100
|
+
undef_method(old) # Then remove the old method
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
# Undef all methods not in the 'included' array
|
105
|
+
unless included.empty?
|
106
|
+
mod.instance_methods.each{ |method|
|
107
|
+
method = method.to_sym
|
108
|
+
unless included.include?(method)
|
109
|
+
undef_method(method) if method_defined?(method)
|
110
|
+
end
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
# Undef all methods in the 'excluded' array
|
115
|
+
excluded.each{ |method|
|
116
|
+
undef_method(method) if method_defined?(method)
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
module_eval{ include m }
|
121
|
+
end
|
122
|
+
end
|
data/test/tc_use.rb
CHANGED
@@ -1,49 +1,115 @@
|
|
1
|
-
###############################################
|
2
|
-
# tc_use.rb
|
3
|
-
#
|
4
|
-
# Test suite for the "use" package.
|
5
|
-
###############################################
|
6
|
-
base = File.basename(Dir.pwd)
|
7
|
-
|
8
|
-
if base == "test" || base =~ /use/
|
9
|
-
Dir.chdir("..") if base == "test"
|
10
|
-
$LOAD_PATH.unshift(Dir.pwd)
|
11
|
-
$LOAD_PATH.unshift(Dir.pwd + "/lib")
|
12
|
-
Dir.chdir("test") rescue nil
|
13
|
-
end
|
14
|
-
|
15
|
-
require "
|
16
|
-
require "
|
17
|
-
|
18
|
-
module Foo
|
19
|
-
def bar; self; end
|
20
|
-
def baz;
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
1
|
+
###############################################
|
2
|
+
# tc_use.rb
|
3
|
+
#
|
4
|
+
# Test suite for the "use" package.
|
5
|
+
###############################################
|
6
|
+
base = File.basename(Dir.pwd)
|
7
|
+
|
8
|
+
if base == "test" || base =~ /use/
|
9
|
+
Dir.chdir("..") if base == "test"
|
10
|
+
$LOAD_PATH.unshift(Dir.pwd)
|
11
|
+
$LOAD_PATH.unshift(Dir.pwd + "/lib")
|
12
|
+
Dir.chdir("test") rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
require "use"
|
16
|
+
require "test/unit"
|
17
|
+
|
18
|
+
module Foo
|
19
|
+
def bar; self; end
|
20
|
+
def baz; "hello"; end
|
21
|
+
def zap; "world"; end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Bar
|
25
|
+
def bar; "bar!"; end
|
26
|
+
def baz; "baz!"; end
|
27
|
+
end
|
28
|
+
|
29
|
+
class User
|
30
|
+
use Foo, :bar
|
31
|
+
end
|
32
|
+
|
33
|
+
class Temp
|
34
|
+
use Foo,
|
35
|
+
:include => :zap,
|
36
|
+
:alias => {:baz, :test}
|
37
|
+
end
|
38
|
+
|
39
|
+
class Zapr
|
40
|
+
use Foo, :exclude => [:bar, :baz]
|
41
|
+
use Bar
|
42
|
+
|
43
|
+
def zap
|
44
|
+
"zap"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Bogus
|
49
|
+
use Foo,
|
50
|
+
:alias => {"zap", :test1, :baz, :test2},
|
51
|
+
:exclude => :bar
|
52
|
+
end
|
53
|
+
|
54
|
+
class TC_Use < Test::Unit::TestCase
|
55
|
+
def setup
|
56
|
+
@user = User.new
|
57
|
+
@temp = Temp.new
|
58
|
+
@zapr = Zapr.new
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_user_mod_methods
|
62
|
+
assert_equal(["bar","baz","zap"], Foo.instance_methods.sort)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_zapr_legal_methods
|
66
|
+
assert_respond_to(@zapr, :zap)
|
67
|
+
assert_respond_to(@zapr, :bar)
|
68
|
+
assert_equal("zap", @zapr.zap) # Existing method not overridden
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_temp_legal_methods
|
72
|
+
assert_respond_to(@temp, :zap)
|
73
|
+
assert_respond_to(@temp, :test)
|
74
|
+
assert_equal("world", @temp.zap)
|
75
|
+
assert_equal("hello", @temp.test)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_temp_expected_errors
|
79
|
+
assert_raises(NoMethodError){ @temp.bar }
|
80
|
+
assert_raises(NoMethodError){ @temp.baz } # Aliased
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_user_legal_methods
|
84
|
+
assert_respond_to(@user, :bar)
|
85
|
+
assert_nothing_raised{ @user.bar }
|
86
|
+
assert_kind_of(User, @user.bar)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_user_expected_errors
|
90
|
+
assert_raises(NoMethodError){ @user.baz }
|
91
|
+
assert_raises(NoMethodError){ @user.zap }
|
92
|
+
end
|
93
|
+
|
94
|
+
# Don't allow exclude and include
|
95
|
+
def test_mutual_exclusion
|
96
|
+
assert_raises(ArgumentError){
|
97
|
+
eval{
|
98
|
+
"class Bogus
|
99
|
+
use Foo, :include => :bar, :exclude => :zap
|
100
|
+
end"
|
101
|
+
}
|
102
|
+
}
|
103
|
+
assert_raises(ArgumentError){
|
104
|
+
eval{
|
105
|
+
"class Bogus
|
106
|
+
use Foo, :alias => {:bar,:blah}, :exclude => :zap
|
107
|
+
end"
|
108
|
+
}
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def teardown
|
113
|
+
@user = nil
|
114
|
+
end
|
115
|
+
end
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.11
|
3
3
|
specification_version: 1
|
4
4
|
name: use
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date:
|
6
|
+
version: 1.1.0
|
7
|
+
date: 2006-01-20 00:00:00 -07:00
|
8
8
|
summary: Selectively mixin methods from a given module
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -24,15 +24,15 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
24
24
|
version: 0.0.0
|
25
25
|
version:
|
26
26
|
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
27
29
|
authors:
|
28
30
|
- Daniel J. Berger
|
29
31
|
files:
|
30
32
|
- lib/use.rb
|
31
33
|
- CHANGES
|
32
|
-
- CVS
|
33
34
|
- MANIFEST
|
34
35
|
- README
|
35
|
-
- test/CVS
|
36
36
|
- test/tc_use.rb
|
37
37
|
test_files:
|
38
38
|
- test/tc_use.rb
|