use 1.1.0 → 1.2.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.
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
+