mixin 0.4.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/LICENSE +19 -0
- data/README +6 -0
- data/lib/metable.rb +8 -0
- data/lib/metable/class_methods.rb +77 -0
- data/lib/metable/instance_methods.rb +93 -0
- data/lib/mixin.rb +152 -0
- data/test/mixin_case.rb +220 -0
- data/test/test_subjects/extenders.rb +33 -0
- data/test/test_subjects/hopons.rb +20 -0
- data/test/test_subjects/includers.rb +34 -0
- data/test/test_subjects/meepers.rb +76 -0
- data/test/test_subjects/nudgers.rb +21 -0
- data/test/test_subjects/scopers.rb +50 -0
- data/test/test_subjects/sleepers.rb +18 -0
- data/test/test_subjects/soopers.rb +120 -0
- metadata +68 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2008 Christian Herschel Stevenson, Persapient Systems
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
data/lib/metable.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'metable/instance_methods'
|
2
|
+
|
3
|
+
|
4
|
+
module Metable
|
5
|
+
module ClassMethods
|
6
|
+
include InstanceMethods
|
7
|
+
|
8
|
+
# Returns +true+ if the named class method is defined by the invoking class
|
9
|
+
# (or its extended modules or ancestors). Public and protected (yes,
|
10
|
+
# _protected_) class methods are matched.
|
11
|
+
def class_method_defined?(method_name)
|
12
|
+
eigenclass.method_defined? method_name
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns +true+ if the named public class method is defined by the invoking
|
16
|
+
# class (or its extended modules or ancestors).
|
17
|
+
def public_class_method_defined?(method_name)
|
18
|
+
eigenclass.public_method_defined? method_name
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns +true+ if the named protected class method is defined by the invoking
|
22
|
+
# class (or its extended modules or ancestors).
|
23
|
+
def protected_class_method_defined?(method_name)
|
24
|
+
eigenclass.protected_method_defined? method_name
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns +true+ if the named private class method is defined by the invoking
|
28
|
+
# class (or its extended modules or ancestors).
|
29
|
+
def private_class_method_defined?(method_name)
|
30
|
+
eigenclass.private_method_defined? method_name
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
alias protected_class_method protected_singleton_method
|
35
|
+
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
alias alias_class_method alias_singleton_method
|
40
|
+
|
41
|
+
alias define_class_method define_singleton_method
|
42
|
+
alias define_public_class_method define_singleton_method
|
43
|
+
alias define_protected_class_method define_protected_singleton_method
|
44
|
+
alias define_private_class_method define_private_singleton_method
|
45
|
+
|
46
|
+
|
47
|
+
# Defines an instance method for _name_ which becomes an enclosure around
|
48
|
+
# a given object. The enclosed object is the result of the given block,
|
49
|
+
# which is evaluated within the context of the invoking instance object
|
50
|
+
# using +instance_eval+ at the time in which the enclosure method is first
|
51
|
+
# invoked on that instance. The _access_ argument can be a symbol or string
|
52
|
+
# representing the access level for the enclosure method (public, private,
|
53
|
+
# or protected). The default access level is +private+.
|
54
|
+
def enclosed_attr(name, access = :private, &block) # :doc:
|
55
|
+
define_method name do
|
56
|
+
ea = instance_eval &block
|
57
|
+
eigen_eval { define_method(name) { ea } && __send__(access, name) }
|
58
|
+
ea
|
59
|
+
end
|
60
|
+
__send__ access, name
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def public_enclosure(*names, &block) # :doc:
|
65
|
+
names.each { |name| enclosed_attr name, :public, &block }
|
66
|
+
end
|
67
|
+
|
68
|
+
def private_enclosure(*names, &block) # :doc:
|
69
|
+
names.each { |name| enclosed_attr name, :private, &block }
|
70
|
+
end
|
71
|
+
|
72
|
+
def protected_enclosure(*names, &block) # :doc:
|
73
|
+
names.each { |name| enclosed_attr name, :protected, &block }
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Metable
|
2
|
+
module InstanceMethods
|
3
|
+
|
4
|
+
# Returns the invoking object's eigenclass.
|
5
|
+
def eigenclass
|
6
|
+
class << self
|
7
|
+
self
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
alias metaclass eigenclass
|
12
|
+
|
13
|
+
|
14
|
+
# Evaluates a string containing Ruby source code, or the given block within
|
15
|
+
# the context of the invoking object's eigenclass.
|
16
|
+
#
|
17
|
+
# <tt>_obj_.eigen_eval { _block_ }</tt> would be equivalent to
|
18
|
+
# <tt>_obj_.eigenclass.instance_eval { _block_ }</tt>
|
19
|
+
#
|
20
|
+
# :call-seq:
|
21
|
+
# eigen_eval(<em>string</em> <, <em>file</em> <, <em>line</em>>>) -> <em>other_obj</em>
|
22
|
+
# eigen_eval { <em>block</em> } -> <em>other_obj</em>
|
23
|
+
#
|
24
|
+
def eigen_eval(*args, &block)
|
25
|
+
eigenclass.instance_eval(*args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# Makes the invoking object's existing singleton methods private.
|
30
|
+
def private_singleton_method(*method_ids)
|
31
|
+
eigen_eval { private *method_ids }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Makes the invoking object's existing singleton methods protected.
|
35
|
+
def protected_singleton_method(*method_ids)
|
36
|
+
eigen_eval { protected *method_ids }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Makes the invoking object's existing singleton methods public.
|
40
|
+
def public_singleton_method(*method_ids)
|
41
|
+
eigen_eval { public *method_ids }
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Makes _new_id_ an alias of the singleton method _old_id_ within the
|
48
|
+
# invoking object.
|
49
|
+
def alias_singleton_method(new_id, old_id) # :doc:
|
50
|
+
eigen_eval { alias_method new_id, old_id }
|
51
|
+
end
|
52
|
+
|
53
|
+
# Defines a public singleton method on the invoking object (similar to
|
54
|
+
# +define_method+).
|
55
|
+
#
|
56
|
+
# <em>Aliased as</em> +define_public_singleton_method+
|
57
|
+
#
|
58
|
+
# :call-seq:
|
59
|
+
# define_singleton_method(<em>symbol</em>, <em>method</em>) -> <em>method</em>
|
60
|
+
# define_singleton_method(<em>symbol</em>) { <em>block</em> } -> <em>proc</em>
|
61
|
+
#
|
62
|
+
def define_singleton_method(*args, &block) # :doc:
|
63
|
+
eigen_eval { define_method(*args, &block) }
|
64
|
+
end
|
65
|
+
|
66
|
+
alias define_public_singleton_method define_singleton_method # :doc:
|
67
|
+
|
68
|
+
# Defines a private singleton method on the invoking object (similar to
|
69
|
+
# +define_method+).
|
70
|
+
#
|
71
|
+
# :call-seq:
|
72
|
+
# define_private_singleton_method(<em>symbol</em>, <em>method</em>) -> <em>method</em>
|
73
|
+
# define_private_singleton_method(<em>symbol</em>) { <em>block</em> } -> <em>proc</em>
|
74
|
+
#
|
75
|
+
def define_private_singleton_method(*args, &block) # :doc:
|
76
|
+
define_singleton_method(*args, &block)
|
77
|
+
private_singleton_method(args.first)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Defines a protected singleton method on the invoking object (similar to
|
81
|
+
# +define_method+).
|
82
|
+
#
|
83
|
+
# :call-seq:
|
84
|
+
# define_protected_singleton_method(<em>symbol</em>, <em>method</em>) -> <em>method</em>
|
85
|
+
# define_protected_singleton_method(<em>symbol</em>) { <em>block</em> } -> <em>proc</em>
|
86
|
+
#
|
87
|
+
def define_protected_singleton_method(*args, &block) # :doc:
|
88
|
+
define_singleton_method(*args, &block)
|
89
|
+
protected_singleton_method(args.first)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
data/lib/mixin.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'metable/class_methods'
|
2
|
+
|
3
|
+
|
4
|
+
# Mixin is an extension to +Module+ that is intended to ease the development
|
5
|
+
# of mixins that involve both class and instance methods.
|
6
|
+
#
|
7
|
+
module Mixin
|
8
|
+
include Metable::InstanceMethods
|
9
|
+
extend Metable::ClassMethods
|
10
|
+
|
11
|
+
class ModuleMixin < Module # :nodoc:
|
12
|
+
include Metable::InstanceMethods
|
13
|
+
|
14
|
+
def initialize(mixin)
|
15
|
+
define_private_singleton_method(:mixin) { mixin }
|
16
|
+
super()
|
17
|
+
end
|
18
|
+
|
19
|
+
def module_eval(*args, &block)
|
20
|
+
mixin.eigenclass.module_eval *args, &block
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
alias class_eval module_eval
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
enclosed_attr(:__class_mixin__) { Module.new }
|
29
|
+
enclosed_attr(:__module_mixin__) { ModuleMixin.new(self) }
|
30
|
+
|
31
|
+
|
32
|
+
# Extends the given modules to the classes that subsequently include the
|
33
|
+
# invoking module or one of its submodules.
|
34
|
+
#
|
35
|
+
# Calling <tt>SomeMixin.extend_class_mixin(SomeClassMethods)</tt>
|
36
|
+
# would be equivalent to:
|
37
|
+
#
|
38
|
+
# module SomeMixin
|
39
|
+
# class_mixin do
|
40
|
+
# include SomeClassMethods
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
def extend_class_mixin(*modules)
|
45
|
+
class_mixin { include *modules }
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Works like +extend_class_mixin+ except that the given modules are instead
|
50
|
+
# extended to the invoking module and the modules that subsequently include
|
51
|
+
# it rather than their including classes.
|
52
|
+
def extend_module_mixin(*modules)
|
53
|
+
module_mixin { include *modules }
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Returns the invoking modules's +class_mixin+ module object. When a block is
|
60
|
+
# passed, it is evaluated in the context of the +class_mixin+ module.
|
61
|
+
#
|
62
|
+
# Given the module M, M's +class_mixin+ module is included by the +class_mixin+
|
63
|
+
# module of any module that includes M and is extended to any class that
|
64
|
+
# includes M.
|
65
|
+
#
|
66
|
+
# module Active
|
67
|
+
# class_mixin do
|
68
|
+
# def active?; true; end
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# module Hyper
|
73
|
+
# include Active
|
74
|
+
# class_mixin do
|
75
|
+
# def hyper?; true; end
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# class HyperClass
|
80
|
+
# include Hyper
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# HyperClass.active? -> true
|
84
|
+
# HyperClass.hyper? -> true
|
85
|
+
#
|
86
|
+
# :call-seq:
|
87
|
+
# class_mixin { <em>block</em> } -> <em>module</em>
|
88
|
+
# class_mixin -> <em>module</em>
|
89
|
+
#
|
90
|
+
def class_mixin(&block) # :doc:
|
91
|
+
__class_mixin__.module_eval(&block) if block_given?
|
92
|
+
__class_mixin__
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# Works the same as +class_mixin+ except that the invoking module's
|
97
|
+
# +module_mixin+ is instead extended to the invoking module its self rather
|
98
|
+
# than its including classes.
|
99
|
+
#
|
100
|
+
# module Active
|
101
|
+
# module_mixin do
|
102
|
+
# def active_mixin?; true; end
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# module Hyper
|
107
|
+
# include Active
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# class ActiveClass
|
111
|
+
# include Active
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# Active.active_mixin? -> true
|
115
|
+
# Hyper.active_mixin? -> true
|
116
|
+
# ActiveClass.respond_to?(:active_mixin?) -> false
|
117
|
+
#
|
118
|
+
# :call-seq:
|
119
|
+
# module_mixin { <em>block</em> } -> <em>module</em>
|
120
|
+
# module_mixin -> <em>module</em>
|
121
|
+
#
|
122
|
+
def module_mixin(&block) # :doc:
|
123
|
+
__module_mixin__.module_eval(&block) if block_given?
|
124
|
+
__module_mixin__
|
125
|
+
end
|
126
|
+
|
127
|
+
# Call the DRY Police! ;)
|
128
|
+
|
129
|
+
|
130
|
+
def included(submodule)
|
131
|
+
if submodule.kind_of? Class
|
132
|
+
submodule.extend __class_mixin__
|
133
|
+
else
|
134
|
+
submodule.extend_module_mixin __module_mixin__
|
135
|
+
submodule.extend_class_mixin __class_mixin__
|
136
|
+
end
|
137
|
+
super
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
[:module_mixin, :extend_module_mixin, :class_mixin, :extend_class_mixin].each do |name|
|
145
|
+
Module.class_eval %Q{
|
146
|
+
def #{name}(*args, &block)
|
147
|
+
extend ::Mixin
|
148
|
+
send :#{name}, *args, &block
|
149
|
+
end
|
150
|
+
}
|
151
|
+
end
|
152
|
+
Module.class_eval { private :module_mixin, :class_mixin }
|
data/test/mixin_case.rb
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
2
|
+
$:.unshift "#{File.dirname(__FILE__)}/test_subjects"
|
3
|
+
|
4
|
+
require 'mixin'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
|
8
|
+
class MixinTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
|
11
|
+
def meeper_mxns
|
12
|
+
[Meeper, ActiveMeeper, HyperMeeper]
|
13
|
+
end
|
14
|
+
|
15
|
+
def meeper_clss
|
16
|
+
[MeeperCls, ActiveMeeperCls, HyperMeeperCls]
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def assert_no_response(obj, msg, message = nil)
|
21
|
+
assert !obj.respond_to?(msg), message
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def test_respond_to
|
26
|
+
load 'meepers.rb'
|
27
|
+
|
28
|
+
[:meeper_mixin?, :meep].each do |meth|
|
29
|
+
meeper_mxns.each { |mxn| assert_respond_to mxn, meth }
|
30
|
+
meeper_clss.each { |cls| assert_no_response cls, meth }
|
31
|
+
end
|
32
|
+
[:meeper_class?, :says].each do |meth|
|
33
|
+
meeper_mxns.each { |mxn| assert_no_response mxn, meth }
|
34
|
+
meeper_clss.each { |cls| assert_respond_to cls, meth }
|
35
|
+
end
|
36
|
+
|
37
|
+
meeper_mxns[1..-1].each do |mxn|
|
38
|
+
assert_respond_to mxn, :active?
|
39
|
+
assert_no_response mxn, :active_meeper?
|
40
|
+
end
|
41
|
+
meeper_clss[1..-1].each do |cls|
|
42
|
+
assert_no_response cls, :active?
|
43
|
+
assert_respond_to cls, :active_meeper?
|
44
|
+
end
|
45
|
+
assert_no_response Meeper, :active
|
46
|
+
assert_no_response MeeperCls, :active_meeper?
|
47
|
+
|
48
|
+
assert_respond_to HyperMeeper, :hyperactive?
|
49
|
+
assert_no_response HyperMeeperCls, :hyperactive?
|
50
|
+
assert_respond_to HyperMeeperCls, :hyper_meeper?
|
51
|
+
assert_no_response HyperMeeper, :hyper_meeper?
|
52
|
+
meeper_mxns[0..-2].each { |mxn| assert_no_response mxn, :hyperactive? }
|
53
|
+
meeper_clss[0..-2].each { |cls| assert_no_response cls, :hyper_meeper? }
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def test_scope
|
58
|
+
load 'scopers.rb'
|
59
|
+
|
60
|
+
assert M.class_variables.empty?
|
61
|
+
assert M.instance_variables.empty?
|
62
|
+
|
63
|
+
[M::Scoper, M::XScoper, M::ScoperCls, M::XScoperCls].each do |mod|
|
64
|
+
assert_same mod, mod.me
|
65
|
+
assert_same :cls, mod.cls_attr
|
66
|
+
end
|
67
|
+
assert_same :inst, M::Scoper.inst_attr
|
68
|
+
[M::XScoper, M::ScoperCls].each { |mod| assert_nil mod.inst_attr }
|
69
|
+
assert_same :xinst, M::XScoperCls.inst_attr
|
70
|
+
M::XScoper.instance_variable_set :@inst_attr, :woot
|
71
|
+
assert_same :woot, M::XScoper.inst_attr
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def test_hopons
|
76
|
+
load 'meepers.rb'
|
77
|
+
load 'hopons.rb'
|
78
|
+
|
79
|
+
Meeper.module_eval do
|
80
|
+
module_mixin do
|
81
|
+
def newb
|
82
|
+
:newbie
|
83
|
+
end
|
84
|
+
end
|
85
|
+
class_mixin do
|
86
|
+
def noob
|
87
|
+
:nooby
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
meeper_mxns.each { |mxn| assert_respond_to mxn, :newb }
|
93
|
+
meeper_clss.each { |cls| assert_respond_to cls, :noob }
|
94
|
+
|
95
|
+
Meeper.module_eval do
|
96
|
+
include Duck
|
97
|
+
module_mixin do
|
98
|
+
include Plain
|
99
|
+
end
|
100
|
+
class_mixin do
|
101
|
+
include Plain
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
assert_respond_to Meeper, :quack
|
106
|
+
assert_respond_to Meeper, :flavor
|
107
|
+
(meeper_mxns[1..-1] + meeper_clss).each do |mod|
|
108
|
+
assert_no_response mod, :quack
|
109
|
+
assert_no_response mod, :flavor
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def test_extenders
|
115
|
+
load 'extenders.rb'
|
116
|
+
load 'hopons.rb'
|
117
|
+
|
118
|
+
assert_same :module, Xtendr.nudge
|
119
|
+
assert_same :module, Xtendrer.nudge
|
120
|
+
assert_same :class, Xtended.nudge
|
121
|
+
assert_same :class, Xtendedr.nudge
|
122
|
+
assert_same :mod_mxn_ping, Xtendr.ping
|
123
|
+
assert_same :mod_mxn_ping, Xtendrer.ping
|
124
|
+
assert_same :cls_mxn_ping, Xtended.ping
|
125
|
+
assert_same :cls_mxn_ping, Xtendedr.ping
|
126
|
+
|
127
|
+
Xtendr.extend_module_mixin Plain
|
128
|
+
Xtendr.extend_class_mixin Plain
|
129
|
+
|
130
|
+
assert_same :vanilla, Xtendr.flavor
|
131
|
+
assert_no_response Xtendrer, :flavor
|
132
|
+
assert_no_response Xtended, :flavor
|
133
|
+
|
134
|
+
xhaustv = Module.new { include Xtendr }
|
135
|
+
xhausted = Class.new { include Xtendr }
|
136
|
+
assert_same :vanilla, xhaustv.flavor
|
137
|
+
assert_same :vanilla, xhausted.flavor
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
def test_includers
|
142
|
+
load 'includers.rb'
|
143
|
+
load 'hopons.rb'
|
144
|
+
|
145
|
+
assert_same :module, Includr.nudge
|
146
|
+
assert_same :module, Includrer.nudge
|
147
|
+
assert_same :class, Included.nudge
|
148
|
+
assert_same :class, Includedr.nudge
|
149
|
+
assert_same :mod_mxn_ping, Includr.ping
|
150
|
+
assert_same :mod_mxn_ping, Includrer.ping
|
151
|
+
assert_same :cls_mxn_ping, Included.ping
|
152
|
+
assert_same :cls_mxn_ping, Includedr.ping
|
153
|
+
|
154
|
+
Includr.module_eval do
|
155
|
+
module_mixin { include Plain }
|
156
|
+
end
|
157
|
+
Includr.module_eval do
|
158
|
+
class_mixin { include Plain }
|
159
|
+
end
|
160
|
+
|
161
|
+
assert_same :vanilla, Includr.flavor
|
162
|
+
assert_no_response Includrer, :flavor
|
163
|
+
assert_no_response Included, :flavor
|
164
|
+
|
165
|
+
xhaustv = Module.new { include Includr }
|
166
|
+
xhausted = Class.new { include Includr }
|
167
|
+
assert_same :vanilla, xhaustv.flavor
|
168
|
+
assert_same :vanilla, xhausted.flavor
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
def test_supers
|
173
|
+
load 'soopers.rb'
|
174
|
+
|
175
|
+
assert_equal [0,1], Soopr1.giv_er
|
176
|
+
assert_equal [0,1,2], Soopr2.giv_er
|
177
|
+
assert_equal [0,1,2,3], Soopr3.giv_er
|
178
|
+
|
179
|
+
assert_equal [1,0], SooprC1.giv_em
|
180
|
+
assert_equal [2,1,0], SooprC2.giv_em
|
181
|
+
assert_equal [3,2,1,0], SooprC3.giv_em
|
182
|
+
|
183
|
+
assert_equal [0,1,2,3,7,9], Soopr4.giv_er
|
184
|
+
assert_equal [666,9,7,3,2,1,0], SooprC4.giv_em
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def test_laziness
|
189
|
+
load 'sleepers.rb'
|
190
|
+
|
191
|
+
[LazyModExt, LazyClsExt, LazyModMxn, LazyClsMxn].each do |mxn|
|
192
|
+
assert_kind_of Mixin, mxn
|
193
|
+
end
|
194
|
+
assert SansMxn.private_methods.include?('module_mixin')
|
195
|
+
assert SansMxn.private_methods.include?('class_mixin')
|
196
|
+
assert !SansMxn.kind_of?(Mixin)
|
197
|
+
SansMxn.extend_class_mixin Module.new
|
198
|
+
assert_kind_of Mixin, SansMxn
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
def test_module_mixin_module_eval
|
203
|
+
load 'meepers.rb'
|
204
|
+
|
205
|
+
Meeper.module_eval do
|
206
|
+
module_mixin.module_eval do
|
207
|
+
def rico?
|
208
|
+
true
|
209
|
+
end
|
210
|
+
end
|
211
|
+
module_mixin.class_eval %Q{
|
212
|
+
def suave?
|
213
|
+
true
|
214
|
+
end
|
215
|
+
}
|
216
|
+
end
|
217
|
+
assert Meeper.rico? && Meeper.suave?
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'nudgers'
|
2
|
+
|
3
|
+
|
4
|
+
module Xtendr
|
5
|
+
extend_module_mixin ModNudgr
|
6
|
+
extend_class_mixin ClsNudgr
|
7
|
+
|
8
|
+
module_mixin do
|
9
|
+
def ping
|
10
|
+
:mod_mxn_ping
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class_mixin do
|
15
|
+
def ping
|
16
|
+
:cls_mxn_ping
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
module Xtendrer
|
23
|
+
include Xtendr
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
class Xtended
|
28
|
+
include Xtendr
|
29
|
+
end
|
30
|
+
|
31
|
+
class Xtendedr
|
32
|
+
include Xtendrer
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'nudgers'
|
2
|
+
|
3
|
+
|
4
|
+
module Includr
|
5
|
+
module_mixin do
|
6
|
+
include ModNudgr
|
7
|
+
|
8
|
+
def ping
|
9
|
+
:mod_mxn_ping
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class_mixin do
|
14
|
+
include ClsNudgr
|
15
|
+
|
16
|
+
def ping
|
17
|
+
:cls_mxn_ping
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
module Includrer
|
24
|
+
include Includr
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
class Included
|
29
|
+
include Includr
|
30
|
+
end
|
31
|
+
|
32
|
+
class Includedr
|
33
|
+
include Includrer
|
34
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
[:Meeper, :MeeperCls, :ActiveMeeper, :ActiveMeeperCls, :HyperMeeper, :HyperMeeperCls].each do |mod|
|
2
|
+
if Object.const_defined?(mod)
|
3
|
+
Object.send(:remove_const, mod)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
module Meeper
|
9
|
+
|
10
|
+
module_mixin do
|
11
|
+
def meeper_mixin?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def meep
|
16
|
+
:meep
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class_mixin do
|
21
|
+
def meeper_class?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def says
|
26
|
+
:meep
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
module ActiveMeeper
|
33
|
+
include Meeper
|
34
|
+
|
35
|
+
module_mixin do
|
36
|
+
def active?
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class_mixin do
|
42
|
+
def active_meeper?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
module HyperMeeper
|
50
|
+
include ActiveMeeper
|
51
|
+
|
52
|
+
module_mixin do
|
53
|
+
def hyperactive?
|
54
|
+
true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class_mixin do
|
59
|
+
def hyper_meeper?
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
class MeeperCls
|
67
|
+
include Meeper
|
68
|
+
end
|
69
|
+
|
70
|
+
class ActiveMeeperCls
|
71
|
+
include ActiveMeeper
|
72
|
+
end
|
73
|
+
|
74
|
+
class HyperMeeperCls
|
75
|
+
include HyperMeeper
|
76
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module M
|
2
|
+
|
3
|
+
module Scoper
|
4
|
+
@@cls_attr = :cls
|
5
|
+
@inst_attr = :inst
|
6
|
+
|
7
|
+
module_mixin do
|
8
|
+
def cls_attr
|
9
|
+
@@cls_attr
|
10
|
+
end
|
11
|
+
|
12
|
+
def inst_attr
|
13
|
+
@inst_attr
|
14
|
+
end
|
15
|
+
|
16
|
+
def me
|
17
|
+
self
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class_mixin do
|
22
|
+
def cls_attr
|
23
|
+
@@cls_attr
|
24
|
+
end
|
25
|
+
|
26
|
+
def inst_attr
|
27
|
+
@inst_attr
|
28
|
+
end
|
29
|
+
|
30
|
+
def me
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module XScoper
|
37
|
+
include Scoper
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
class ScoperCls
|
42
|
+
include Scoper
|
43
|
+
end
|
44
|
+
|
45
|
+
class XScoperCls
|
46
|
+
include XScoper
|
47
|
+
@inst_attr = :xinst
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module SooprMX
|
2
|
+
def giv_er
|
3
|
+
[0]
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
module SooprCX
|
8
|
+
def giv_em
|
9
|
+
[0]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
module Soopr1
|
15
|
+
extend_module_mixin SooprMX
|
16
|
+
|
17
|
+
module_mixin do
|
18
|
+
def giv_er
|
19
|
+
super + [1]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class_mixin do
|
24
|
+
include SooprCX
|
25
|
+
|
26
|
+
def giv_em
|
27
|
+
[1] + super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
module Soopr2
|
34
|
+
include Soopr1
|
35
|
+
|
36
|
+
module_mixin do
|
37
|
+
def giv_er
|
38
|
+
super + [2]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class_mixin do
|
43
|
+
def giv_em
|
44
|
+
[2] + super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
module Soopr3
|
51
|
+
include Soopr2
|
52
|
+
|
53
|
+
module_mixin do
|
54
|
+
def giv_er
|
55
|
+
super + [3]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class_mixin do
|
60
|
+
def giv_em
|
61
|
+
[3] + super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
class SooprC1
|
68
|
+
include Soopr1
|
69
|
+
end
|
70
|
+
|
71
|
+
class SooprC2
|
72
|
+
include Soopr2
|
73
|
+
end
|
74
|
+
|
75
|
+
class SooprC3
|
76
|
+
include Soopr3
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
module DooprMX
|
82
|
+
def giv_er
|
83
|
+
super + [7]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
module DooprCX
|
88
|
+
def giv_em
|
89
|
+
[7] + super
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
module Soopr4
|
95
|
+
include Soopr3
|
96
|
+
extend_class_mixin DooprCX
|
97
|
+
|
98
|
+
class_mixin do
|
99
|
+
def giv_em
|
100
|
+
[9] + super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module_mixin do
|
105
|
+
include DooprMX
|
106
|
+
|
107
|
+
def giv_er
|
108
|
+
super + [9]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
class SooprC4
|
115
|
+
include Soopr4
|
116
|
+
|
117
|
+
def self.giv_em
|
118
|
+
[666] + super
|
119
|
+
end
|
120
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mixin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Hersch Stevenson (xian)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-09-04 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: stevenson@persapient.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- LICENSE
|
25
|
+
files:
|
26
|
+
- lib/metable/instance_methods.rb
|
27
|
+
- lib/metable/class_methods.rb
|
28
|
+
- lib/mixin.rb
|
29
|
+
- lib/metable.rb
|
30
|
+
- test/test_subjects/scopers.rb
|
31
|
+
- test/test_subjects/meepers.rb
|
32
|
+
- test/test_subjects/extenders.rb
|
33
|
+
- test/test_subjects/sleepers.rb
|
34
|
+
- test/test_subjects/hopons.rb
|
35
|
+
- test/test_subjects/nudgers.rb
|
36
|
+
- test/test_subjects/includers.rb
|
37
|
+
- test/test_subjects/soopers.rb
|
38
|
+
- test/mixin_case.rb
|
39
|
+
- README
|
40
|
+
- LICENSE
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://www.persapient.com/mixin
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: mixin
|
63
|
+
rubygems_version: 1.2.0
|
64
|
+
signing_key:
|
65
|
+
specification_version: 2
|
66
|
+
summary: An extention to Module that is intended to ease the development of mixins that involve both class and instance methods.
|
67
|
+
test_files:
|
68
|
+
- test/mixin_case.rb
|