use 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/CHANGES +6 -0
  2. data/MANIFEST +2 -1
  3. data/README +9 -0
  4. data/lib/use.rb +67 -98
  5. data/test/tc_use.rb +75 -87
  6. data/test/test_data.rb +72 -0
  7. metadata +22 -17
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ == 1.2.0 - 24-Feb-2006
2
+ * Method is now redefined within Class instead of Module in order to make
3
+ the ability to use 'include' and 'alias' more flexible and work more nicely
4
+ together.
5
+ * Updated the test suite.
6
+
1
7
  == 1.1.0 - 20-Jan-2006
2
8
  * Using 'use' with no arguments is now the same as if you used 'include',
3
9
  i.e. all methods are mixed in. Previously, this would not mixin any methods.
data/MANIFEST CHANGED
@@ -8,4 +8,5 @@ examples/example_use.rb
8
8
 
9
9
  lib/use.rb
10
10
 
11
- test/tc_use.rb
11
+ test/tc_use.rb
12
+ test/test_data.rb
data/README CHANGED
@@ -53,6 +53,10 @@
53
53
  m = MyKlass.new
54
54
  m.test # "hello"
55
55
  m.bar # NoMethodError
56
+
57
+ == Constants
58
+ USE_VERSION
59
+ The version of this package, returned as a String.
56
60
 
57
61
  == Acknowledgements
58
62
  Thanks go to Ara Howard for providing the original solution and to
@@ -62,6 +66,11 @@
62
66
  == Known Bugs
63
67
  None that I'm aware of. If you find any, please log them on the project
64
68
  page at http://www.rubyforge.org/projects/shards.
69
+
70
+ == Questions?
71
+ Please post your comment or question on one of the forums on the project
72
+ page at http://www.rubyforge.org/projects/shards. Just click the 'Forums'
73
+ link.
65
74
 
66
75
  == License
67
76
  Ruby's
data/lib/use.rb CHANGED
@@ -1,122 +1,91 @@
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 = []
1
+ class Class
2
+ USE_VERSION = '1.2.0'
3
+ def use(*args)
4
+ valid_keys = %w/include exclude alias/
38
5
  excluded = []
6
+ included = []
39
7
  aliased = []
40
8
 
41
- m = Module.new
9
+ mod = args.shift.clone
42
10
 
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
11
+ # If no arguments follow the module name, treat it as a standard include
12
+ if args.empty?
13
+ included.concat(mod.instance_methods)
14
+ end
52
15
 
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
16
+ m = Module.new
60
17
 
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)
18
+ args.each{ |arg|
19
+ if arg.kind_of?(Hash)
20
+ arg.each{ |key, val|
21
+ case key.to_s
22
+ when "include"
23
+ if val.respond_to?(:each)
24
+ val.each{ |arg| included.push(arg.to_s) }
25
+ else
26
+ included.push(val.to_s)
27
+ end
28
+ when "exclude"
29
+ if val.respond_to?(:each)
30
+ val.each{ |arg| excluded.push(arg.to_s) }
31
+ else
32
+ excluded.push(val.to_s)
33
+ end
34
+ when "alias"
35
+ aliased.push(val)
36
+ else
37
+ raise "invalid key '#{key}'"
66
38
  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
39
+ }
76
40
  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 }
41
+ included.push(arg.to_s)
84
42
  end
85
- return
86
- end
43
+ }
87
44
 
88
45
  unless included.empty? || excluded.empty?
89
46
  err = "you cannot include and exclude in the same statement"
90
47
  raise ArgumentError, err
91
48
  end
92
49
 
93
- m.module_eval{
94
- include mod
50
+ imethods = mod.instance_methods
95
51
 
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
- }
52
+ # Remove excluded methods
53
+ unless excluded.empty?
54
+ (imethods & excluded).each{ |meth|
55
+ mod.module_eval{ remove_method(meth) }
102
56
  }
57
+ end
103
58
 
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
59
+ # Alias methods
60
+ aliased.each{ |pair|
61
+ pair.each{ |old, new|
62
+ included.push(old) # Aliased methods automatically included
63
+ mod.module_eval{
64
+ alias_method(new, old)
65
+ remove_method(old)
111
66
  }
112
- end
113
-
114
- # Undef all methods in the 'excluded' array
115
- excluded.each{ |method|
116
- undef_method(method) if method_defined?(method)
117
67
  }
118
68
  }
119
69
 
120
- module_eval{ include m }
70
+ # Remove all methods not specifically included. The rescue was needed
71
+ # for those cases where a module included another module.
72
+ unless included.empty?
73
+ (imethods - included).each{ |meth|
74
+ mod.module_eval{ undef_method(meth) rescue nil }
75
+ }
76
+ end
77
+
78
+ m.module_eval{ include mod }
79
+
80
+ # Raise a warning if methods are shadowed (in $VERBOSE mode)
81
+ if $VERBOSE
82
+ imethods = instance_methods(true)
83
+ m.instance_methods.each{ |meth|
84
+ next unless imethods.include?(meth)
85
+ warn "method '#{meth}' aliased, shadows old '#{meth}'"
86
+ }
87
+ end
88
+
89
+ include m
121
90
  end
122
91
  end
data/test/tc_use.rb CHANGED
@@ -1,115 +1,103 @@
1
- ###############################################
1
+ #######################################################################
2
2
  # tc_use.rb
3
3
  #
4
- # Test suite for the "use" package.
5
- ###############################################
4
+ # Test cases for the 'use' package. The relevant modules and classes
5
+ # are stored in the 'test_data.rb' file.
6
+ #######################################################################
6
7
  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
8
+ if base == 'test' || base =~ /use/i
9
+ Dir.chdir '..' if base == 'test'
10
+ $LOAD_PATH.unshift Dir.pwd + '/lib'
11
+ Dir.chdir 'test' rescue nil
12
+ $LOAD_PATH.unshift Dir.pwd
22
13
  end
23
14
 
24
- module Bar
25
- def bar; "bar!"; end
26
- def baz; "baz!"; end
27
- end
15
+ require 'use'
16
+ require 'test_data'
17
+ require 'test/unit'
28
18
 
29
- class User
30
- use Foo, :bar
31
- end
19
+ class TC_Use < Test::Unit::TestCase
20
+ def setup
21
+ @a = ClassA.new
22
+ @b = ClassB.new
23
+ @c = ClassC.new
24
+ @d = ClassD.new
25
+ end
32
26
 
33
- class Temp
34
- use Foo,
35
- :include => :zap,
36
- :alias => {:baz, :test}
37
- end
27
+ def test_version
28
+ assert_equal('1.2.0', Class::USE_VERSION)
29
+ end
38
30
 
39
- class Zapr
40
- use Foo, :exclude => [:bar, :baz]
41
- use Bar
31
+ def test_mod_a_methods
32
+ assert_equal(['meth_a', 'meth_b', 'meth_c'], ModA.instance_methods.sort)
33
+ end
42
34
 
43
- def zap
44
- "zap"
35
+ def test_mod_b_methods
36
+ assert_equal(['meth_a', 'meth_b', 'meth_c'], ModB.instance_methods.sort)
45
37
  end
46
- end
47
38
 
48
- class Bogus
49
- use Foo,
50
- :alias => {"zap", :test1, :baz, :test2},
51
- :exclude => :bar
52
- end
39
+ def test_mod_c_methods
40
+ assert_equal(['meth_x', 'meth_y', 'meth_z'], ModC.instance_methods.sort)
41
+ end
53
42
 
54
- class TC_Use < Test::Unit::TestCase
55
- def setup
56
- @user = User.new
57
- @temp = Temp.new
58
- @zapr = Zapr.new
43
+ def test_class_a_methods
44
+ assert_respond_to(@a, :meth_a)
45
+ assert_equal('ModA#meth_a', @a.meth_a)
59
46
  end
60
47
 
61
- def test_user_mod_methods
62
- assert_equal(["bar","baz","zap"], Foo.instance_methods.sort)
48
+ def test_class_a_expected_errors
49
+ assert_raises(NoMethodError){ @a.meth_b }
50
+ assert_raises(NoMethodError){ @a.meth_c }
63
51
  end
64
52
 
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
53
+ def test_class_b_methods
54
+ assert_respond_to(@b, :meth_c)
55
+ assert_respond_to(@b, :meth_z)
56
+ assert_equal('ModA#meth_c', @b.meth_c)
57
+ assert_equal('ModB#meth_b', @b.meth_z)
69
58
  end
70
59
 
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)
60
+ def test_class_b_expected_errors
61
+ assert_raises(NoMethodError){ @b.meth_a }
62
+ assert_raises(NoMethodError){ @b.meth_b }
76
63
  end
77
64
 
78
- def test_temp_expected_errors
79
- assert_raises(NoMethodError){ @temp.bar }
80
- assert_raises(NoMethodError){ @temp.baz } # Aliased
65
+ def test_class_c_methods
66
+ assert_respond_to(@c, :meth_a)
67
+ assert_respond_to(@c, :meth_c)
68
+ assert_respond_to(@c, :meth_x)
69
+ assert_respond_to(@c, :meth_y)
70
+ assert_respond_to(@c, :meth_z)
71
+
72
+ assert_equal('ModA#meth_a', @c.meth_a)
73
+ assert_equal('ClassC#meth_c', @c.meth_c)
74
+ assert_equal('ModC#meth_x', @c.meth_x)
75
+ assert_equal('ModC#meth_y', @c.meth_y)
76
+ assert_equal('ModC#meth_z', @c.meth_z)
81
77
  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)
78
+
79
+ def test_class_c_expected_errors
80
+ assert_raises(NoMethodError){ @c.meth_b }
87
81
  end
88
-
89
- def test_user_expected_errors
90
- assert_raises(NoMethodError){ @user.baz }
91
- assert_raises(NoMethodError){ @user.zap }
82
+
83
+ def test_class_d_methods
84
+ assert_respond_to(@d, :meth_x)
85
+ assert_respond_to(@d, :meth_z)
86
+
87
+ assert_equal('ModA#meth_a', @d.meth_x)
88
+ assert_equal('ModA#meth_c', @d.meth_z)
92
89
  end
93
90
 
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
- }
91
+ def test_class_d_expected_errors
92
+ assert_raises(NoMethodError){ @d.meth_a }
93
+ assert_raises(NoMethodError){ @d.meth_b }
94
+ assert_raises(NoMethodError){ @d.meth_c }
110
95
  end
111
-
96
+
112
97
  def teardown
113
- @user = nil
98
+ @a = nil
99
+ @b = nil
100
+ @c = nil
101
+ @d = nil
114
102
  end
115
103
  end
data/test/test_data.rb ADDED
@@ -0,0 +1,72 @@
1
+ ##################################################
2
+ # test_data.rb
3
+ #
4
+ # Test modules and classes for the 'use' package.
5
+ ##################################################
6
+ #if File.basename(Dir.pwd) == "test"
7
+ # Dir.chdir(".."){
8
+ # $LOAD_PATH.unshift(Dir.pwd)
9
+ # $LOAD_PATH.unshift(Dir.pwd + "/lib")
10
+ # }
11
+ #end
12
+ #$LOAD_PATH.unshift(Dir.pwd + "/lib")
13
+
14
+ module ModA
15
+ def meth_a
16
+ "ModA#meth_a"
17
+ end
18
+
19
+ def meth_b
20
+ "ModA#meth_b"
21
+ end
22
+
23
+ def meth_c
24
+ "ModA#meth_c"
25
+ end
26
+ end
27
+
28
+ module ModB
29
+ include ModA
30
+ def meth_a
31
+ "ModB#meth_a"
32
+ end
33
+
34
+ def meth_b
35
+ "ModB#meth_b"
36
+ end
37
+ end
38
+
39
+ module ModC
40
+ def meth_x
41
+ "ModC#meth_x"
42
+ end
43
+
44
+ def meth_y
45
+ "ModC#meth_y"
46
+ end
47
+
48
+ def meth_z
49
+ "ModC#meth_z"
50
+ end
51
+ end
52
+
53
+ class ClassA
54
+ use ModA, :meth_a
55
+ end
56
+
57
+ class ClassB
58
+ use ModB, :include => :meth_c, :alias => {:meth_b, :meth_z}
59
+ end
60
+
61
+ class ClassC
62
+ use ModA, :exclude => [:meth_b, :meth_c]
63
+ use ModC
64
+
65
+ def meth_c
66
+ "ClassC#meth_c"
67
+ end
68
+ end
69
+
70
+ class ClassD
71
+ use ModA, :alias => {:meth_a, :meth_x, :meth_c, :meth_z}, :exclude => :meth_b
72
+ end
metadata CHANGED
@@ -3,11 +3,11 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: use
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.1.0
7
- date: 2006-01-20 00:00:00 -07:00
6
+ version: 1.2.0
7
+ date: 2006-02-24 00:00:00 -07:00
8
8
  summary: Selectively mixin methods from a given module
9
9
  require_paths:
10
- - lib
10
+ - lib
11
11
  email: djberg96@gmail.com
12
12
  homepage: http://www.rubyforge.org/projects/shards
13
13
  rubyforge_project:
@@ -18,29 +18,34 @@ bindir: bin
18
18
  has_rdoc: true
19
19
  required_ruby_version: !ruby/object:Gem::Version::Requirement
20
20
  requirements:
21
- -
22
- - ">"
23
- - !ruby/object:Gem::Version
24
- version: 0.0.0
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
25
24
  version:
26
25
  platform: ruby
27
26
  signing_key:
28
27
  cert_chain:
29
28
  authors:
30
- - Daniel J. Berger
29
+ - Daniel J. Berger
31
30
  files:
32
- - lib/use.rb
33
- - CHANGES
34
- - MANIFEST
35
- - README
36
- - test/tc_use.rb
31
+ - lib/use.rb
32
+ - CHANGES
33
+ - MANIFEST
34
+ - README
35
+ - test/tc_use.rb
36
+ - test/test_data.rb
37
37
  test_files:
38
- - test/tc_use.rb
38
+ - test/tc_use.rb
39
39
  rdoc_options: []
40
+
40
41
  extra_rdoc_files:
41
- - README
42
- - CHANGES
42
+ - README
43
+ - CHANGES
43
44
  executables: []
45
+
44
46
  extensions: []
47
+
45
48
  requirements: []
46
- dependencies: []
49
+
50
+ dependencies: []
51
+