mixers 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +0 -0
- data/LICENSE +22 -0
- data/README +17 -0
- data/lib/mixers/advisable.rb +148 -0
- data/lib/mixers/cloneable.rb +54 -0
- data/lib/mixers/enumargs.rb +195 -0
- data/lib/mixers/equitable.rb +76 -0
- data/lib/mixers/expirable.rb +38 -0
- data/lib/mixers/hook.rb +38 -0
- data/lib/mixers/instantiable.rb +25 -0
- data/lib/mixers/ostructable.rb +179 -0
- data/lib/mixers/preinitilizable.rb +93 -0
- data/lib/mixers/registerable.rb +29 -0
- data/meta/contact +1 -0
- data/meta/description +6 -0
- data/meta/homepage +1 -0
- data/meta/name +1 -0
- data/meta/resource/development +1 -0
- data/meta/resource/homepage +1 -0
- data/meta/suite +1 -0
- data/meta/summary +1 -0
- data/meta/version +1 -0
- data/test/test_advisable.rb +69 -0
- data/test/test_cloneable.rb +41 -0
- data/test/test_enumargs.rb +70 -0
- data/test/test_equitable.rb +42 -0
- data/test/test_instantiable.rb +37 -0
- data/test/test_preinitilizable.rb +35 -0
- metadata +102 -0
data/HISTORY
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Thomas Sawyer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
22
|
+
|
data/README
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= Ruby Mixers
|
2
|
+
|
3
|
+
== DESCRIPTION
|
4
|
+
|
5
|
+
Ruby Mixers is collection mixin modules for the Ruby
|
6
|
+
programming language.
|
7
|
+
|
8
|
+
Mixers is a spin-off of Ruby Facets. When Ruby Facets
|
9
|
+
scaled back to extensions only project, it's mixin
|
10
|
+
modules were gathered to create this new project.
|
11
|
+
|
12
|
+
== COPYRIGHTS
|
13
|
+
|
14
|
+
Ruby Mixers Copyright (c) 2010 Thomas Sawyer
|
15
|
+
|
16
|
+
Ruby Mixers is distibuted under the terms of the MIT license.
|
17
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# Copyright (c) 2007 Thomas Sawyer
|
2
|
+
|
3
|
+
require 'facets/kernel/method'
|
4
|
+
require 'facets/module/instance_method'
|
5
|
+
require 'facets/unboundmethod/arguments'
|
6
|
+
|
7
|
+
# = Advisable
|
8
|
+
#
|
9
|
+
# Advisable provides a means of using before, after and
|
10
|
+
# around adivce in dynamic fashion.
|
11
|
+
#
|
12
|
+
module Advisable
|
13
|
+
|
14
|
+
def self.append_features(base)
|
15
|
+
base.extend self
|
16
|
+
end
|
17
|
+
|
18
|
+
def advice_before
|
19
|
+
@advice_before ||= {} #Hash.new{|h,k| h[k] = []}
|
20
|
+
end
|
21
|
+
|
22
|
+
def advice_after
|
23
|
+
@advice_after ||= {} #Hash.new{|h,k| h[k] = []}
|
24
|
+
end
|
25
|
+
|
26
|
+
def advice_around
|
27
|
+
@advice_around ||= {} #Hash.new{|h,k| h[k] = []}
|
28
|
+
end
|
29
|
+
|
30
|
+
def before(meth, &block)
|
31
|
+
name = "#{meth}:before:#{block.object_id}"
|
32
|
+
define_method(name, &block)
|
33
|
+
(advice_before[meth.to_sym] ||= []) << name
|
34
|
+
end
|
35
|
+
|
36
|
+
def after(meth, &block)
|
37
|
+
name = "#{meth}:after:#{block.object_id}"
|
38
|
+
define_method(name, &block)
|
39
|
+
(advice_after[meth.to_sym] ||= []) << name
|
40
|
+
end
|
41
|
+
|
42
|
+
def around(meth, &block)
|
43
|
+
name = "#{meth}:around:#{block.object_id}"
|
44
|
+
define_method(name, &block)
|
45
|
+
(advice_around[meth.to_sym] ||= []) << name
|
46
|
+
end
|
47
|
+
|
48
|
+
# Advise a method.
|
49
|
+
|
50
|
+
def advise(meth)
|
51
|
+
#return false if defined?(meth_origin)
|
52
|
+
args = instance_method(meth).arguments
|
53
|
+
|
54
|
+
module_eval(<<-END, __FILE__, __LINE__)
|
55
|
+
alias_method '#{meth}_origin', '#{meth}'
|
56
|
+
def #{meth}(#{args})
|
57
|
+
target = method!('#{meth}_origin')
|
58
|
+
|
59
|
+
unless target.advised
|
60
|
+
ancs = self.class.ancestors.select{ |anc| anc.respond_to?(:advice_before) }
|
61
|
+
target.advice_before = ancs.collect{ |anc| anc.advice_before[:'#{meth}'] }
|
62
|
+
target.advice_after = ancs.collect{ |anc| anc.advice_after[:'#{meth}'] }
|
63
|
+
target.advice_around = ancs.collect{ |anc| anc.advice_around[:'#{meth}'] }
|
64
|
+
target.advised = true
|
65
|
+
end
|
66
|
+
|
67
|
+
target.call_with_advice(self, *[#{args}])
|
68
|
+
end
|
69
|
+
END
|
70
|
+
end
|
71
|
+
|
72
|
+
#advise(:method_added)
|
73
|
+
|
74
|
+
#after :method_added do |meth|
|
75
|
+
# advise(meth) unless defined?("#{meth}_orig")
|
76
|
+
#end
|
77
|
+
|
78
|
+
def method_added(meth)
|
79
|
+
return if meth == :method_added
|
80
|
+
@added_stack ||= []
|
81
|
+
return if @added_stack.last == meth
|
82
|
+
return if /_(origin)$/ =~ meth.to_s
|
83
|
+
return if /:(before|after|around)/ =~ meth.to_s
|
84
|
+
@added_stack << meth
|
85
|
+
#return if instance_methods(false).include?("#{meth}_orig")
|
86
|
+
advise(meth)
|
87
|
+
@added_stack.pop
|
88
|
+
end
|
89
|
+
|
90
|
+
# Extensions for Method class.
|
91
|
+
|
92
|
+
module Method
|
93
|
+
|
94
|
+
attr_accessor :advised
|
95
|
+
|
96
|
+
attr_reader :advice_before
|
97
|
+
attr_reader :advice_after
|
98
|
+
attr_reader :advice_around
|
99
|
+
|
100
|
+
def advised?
|
101
|
+
@advised
|
102
|
+
end
|
103
|
+
|
104
|
+
def advice_before=(set); @advice_before = set.flatten.compact; end
|
105
|
+
def advice_after=(set) ; @advice_after = set.flatten.compact; end
|
106
|
+
def advice_around=(set); @advice_around = set.flatten.compact; end
|
107
|
+
|
108
|
+
# Call with advice.
|
109
|
+
|
110
|
+
def call_with_advice(obj, *args, &blk)
|
111
|
+
advice_before.each do |name|
|
112
|
+
#advice.call(*args, &blk)
|
113
|
+
obj.send(name, *args, &blk)
|
114
|
+
end
|
115
|
+
|
116
|
+
target = lambda{ call(*args, &blk) }
|
117
|
+
advice_around.each do |name|
|
118
|
+
target = lambda_target(obj, name, target, *args, &blk)
|
119
|
+
end
|
120
|
+
ret = target.call
|
121
|
+
|
122
|
+
advice_after.reverse_each do |name|
|
123
|
+
#advice.call(*args, &blk)
|
124
|
+
obj.send(name, *args, &blk)
|
125
|
+
end
|
126
|
+
|
127
|
+
return ret
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
# Using separate method for this prevents infinite loop.
|
133
|
+
|
134
|
+
def lambda_target(obj, name, target, *args, &blk)
|
135
|
+
lambda do
|
136
|
+
#advice.call(target, *args, &blk)
|
137
|
+
obj.send(name, target, *args, &blk)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
class Method #:nodoc:
|
146
|
+
include Advisable::Method
|
147
|
+
end
|
148
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# = Clonable
|
2
|
+
#
|
3
|
+
# Standard basis for adding deep #dup and #clone to a class.
|
4
|
+
# Provides a class with deep cloneablity via the standard
|
5
|
+
# #dup and #clone methods.
|
6
|
+
#
|
7
|
+
# == Credit
|
8
|
+
#
|
9
|
+
# Cloneable was originally ported from Jim Weirich's Rake.
|
10
|
+
# The current version is the work of Ken Bloom.
|
11
|
+
#
|
12
|
+
#--
|
13
|
+
# TODO: Is there a more robust means of determining if clone or dup is used?
|
14
|
+
#++
|
15
|
+
|
16
|
+
module Cloneable
|
17
|
+
|
18
|
+
def initialize_copy(sibling)
|
19
|
+
#first duplicate my superclass' state. Note that if it's duplicating
|
20
|
+
#instance variables, this will be overwritten, but this is important
|
21
|
+
#because we could be dealing with a C extension with state hidden from
|
22
|
+
#the Ruby interpreter
|
23
|
+
super
|
24
|
+
|
25
|
+
#we want to know if we're being dup'ed or clone'd, because we want to
|
26
|
+
#preserve the state of our internals the same way our state is being
|
27
|
+
#preserved. (If we can't figure it out, we'll just use #dup.)
|
28
|
+
operation = caller.find{|x| x !~ /'initialize_copy'/}.match(/`(dup|clone)'/)[1] or :dup
|
29
|
+
|
30
|
+
sibling.instance_variables.each do |ivar|
|
31
|
+
value = sibling.instance_variable_get(ivar)
|
32
|
+
|
33
|
+
#set my instance variable to be a #dup or #clone
|
34
|
+
#or my sibling, depending on what's happening to me right now
|
35
|
+
instance_variable_set(ivar, value.send(operation))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# OLD VERSION
|
42
|
+
|
43
|
+
#module Cloneable
|
44
|
+
# def clone
|
45
|
+
# sibling = self.class.new
|
46
|
+
# instance_variables.each do |ivar|
|
47
|
+
# value = self.instance_variable_get(ivar)
|
48
|
+
# sibling.instance_variable_set(ivar, value.dup) #rake_dup)
|
49
|
+
# end
|
50
|
+
# sibling
|
51
|
+
# end
|
52
|
+
# alias_method :dup, :clone
|
53
|
+
#end
|
54
|
+
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# Enumerable::Arguments
|
2
|
+
#
|
3
|
+
# Copyright (c) 2004 Thomas Sawyer
|
4
|
+
#
|
5
|
+
# LGPL(3) License
|
6
|
+
#
|
7
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
8
|
+
# software under the same terms as Ruby.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
12
|
+
# FOR A PARTICULAR PURPOSE.
|
13
|
+
|
14
|
+
begin
|
15
|
+
require 'enumerator'
|
16
|
+
rescue LoadError
|
17
|
+
end
|
18
|
+
|
19
|
+
# This is a simple reimplementation of the core Enumerable module
|
20
|
+
# to allow the methods to take and pass-on arbitrary arguments to the
|
21
|
+
# underlying #each call. This library uses Enumerator and scans
|
22
|
+
# Enumerable so it can alwasy stay in sync.
|
23
|
+
#
|
24
|
+
# NOTE Any Enumerable method with a negative arity cannot do pass arguments
|
25
|
+
# due to ambiguity in the argument count. So the methods #inject and #zip
|
26
|
+
# do NOT work this way, but simply work as they do in Enumerable.
|
27
|
+
# The method #find (and #detect) though has been made to work by removing
|
28
|
+
# its rarely used optional parameter and providing instead an optional
|
29
|
+
# keyword parameter (:ifnone => ...). Please keep these difference in mind.
|
30
|
+
#
|
31
|
+
# require 'enumargs'
|
32
|
+
#
|
33
|
+
# class T
|
34
|
+
# include Enumerable::Arguments
|
35
|
+
# def initialize(arr)
|
36
|
+
# @arr = arr
|
37
|
+
# end
|
38
|
+
# def each(n)
|
39
|
+
# arr.each{ |e| yield(e+n) }
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# t = T.new([1,2,3])
|
44
|
+
# t.collect(4)
|
45
|
+
# #=> [5,6,7]
|
46
|
+
#
|
47
|
+
module Enumerable
|
48
|
+
module Arguments
|
49
|
+
|
50
|
+
def self.wrap_enumerable_method( methodname )
|
51
|
+
|
52
|
+
m = methodname
|
53
|
+
meth = Enumerable.instance_method(m)
|
54
|
+
arity = meth.arity
|
55
|
+
|
56
|
+
case arity <=> 0
|
57
|
+
when 0
|
58
|
+
class_eval %{
|
59
|
+
def #{m}( *args, &yld )
|
60
|
+
enum_for(:each, *args).#{m}( &yld )
|
61
|
+
end
|
62
|
+
}
|
63
|
+
when 1
|
64
|
+
class_eval %{
|
65
|
+
def #{m}( *args, &yld )
|
66
|
+
args, each_args = args[0...#{arity}], args[#{arity}..-1]
|
67
|
+
enum_for(:each, *each_args).#{m}( *args, &yld )
|
68
|
+
end
|
69
|
+
}
|
70
|
+
else
|
71
|
+
class_eval %{
|
72
|
+
def #{m}( *args, &yld )
|
73
|
+
enum_for(:each).#{m}( *args, &yld )
|
74
|
+
end
|
75
|
+
}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
Enumerable.instance_methods(false).each do |m|
|
80
|
+
wrap_enumerable_method( m )
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
def to_a(*args)
|
85
|
+
map(*args){ |x| x }
|
86
|
+
end
|
87
|
+
|
88
|
+
# Make exception for #find (a negative arity method) to accept
|
89
|
+
# keyword argument.
|
90
|
+
#
|
91
|
+
# ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... }
|
92
|
+
# ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... }
|
93
|
+
#
|
94
|
+
def find(*args, &yld) # future use **keys ?
|
95
|
+
if Hash === args.last and args.last.key?(:ifnone)
|
96
|
+
ifnone = args.last.delete(:ifnone)
|
97
|
+
args.pop if args.last.empty?
|
98
|
+
enum_for(:each, *args).find( ifnone, &yld )
|
99
|
+
else
|
100
|
+
enum_for(:each, *args).find( &yld )
|
101
|
+
end
|
102
|
+
end
|
103
|
+
alias_method :detect, :find
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
=begin OLD CODE
|
110
|
+
module EnumerableArgs
|
111
|
+
|
112
|
+
def collect(*args) # :yield:
|
113
|
+
a = []
|
114
|
+
each(*args){ |n| a << yield(n) }
|
115
|
+
a
|
116
|
+
end
|
117
|
+
alias_method( :map, :collect )
|
118
|
+
|
119
|
+
def detect(*args) # :yield:
|
120
|
+
each(*args){ |n| return n if yield(n) }
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
alias_method( :find, :detect )
|
124
|
+
|
125
|
+
def each_with_index(*args)
|
126
|
+
i=0
|
127
|
+
each(*args){ |*n| n << i; yield(*n); i+=1 }
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def to_a(*args)
|
132
|
+
a = []
|
133
|
+
each(*args){ |n| a << n }
|
134
|
+
a
|
135
|
+
end
|
136
|
+
alias_method( :entries, :to_a )
|
137
|
+
|
138
|
+
# An additional method not part of standard Enumerable.
|
139
|
+
# The regular version of this method can be found in Facets,
|
140
|
+
# but it is a bit more advanced then this one.
|
141
|
+
# At some point they need to be put into sync.
|
142
|
+
def each_slice(*args, &yld)
|
143
|
+
a = []; s = []
|
144
|
+
ar = yld.arity.abs
|
145
|
+
each(*args){ |n|
|
146
|
+
s << n
|
147
|
+
if s.length >= ar
|
148
|
+
yld.call(*s)
|
149
|
+
s = []
|
150
|
+
end
|
151
|
+
}
|
152
|
+
a
|
153
|
+
end
|
154
|
+
alias_method( :each_by, :each_slice )
|
155
|
+
|
156
|
+
def select(*args) # :yield:
|
157
|
+
a = []
|
158
|
+
each(*args){ |n| a << n if yield(n) }
|
159
|
+
a
|
160
|
+
end
|
161
|
+
alias_method( :find_all, :select )
|
162
|
+
|
163
|
+
def grep(pattern, *args)
|
164
|
+
a = []
|
165
|
+
each(*args){ |n| a << (block_given? ? yield(n) : n) if pattern === n }
|
166
|
+
a
|
167
|
+
end
|
168
|
+
|
169
|
+
def include?(anObj, *args)
|
170
|
+
each(*args){ |n| return true if anObj == n }
|
171
|
+
false
|
172
|
+
end
|
173
|
+
alias_method( :member?, :include? )
|
174
|
+
|
175
|
+
def max(*args)
|
176
|
+
to_a(*args).max
|
177
|
+
end
|
178
|
+
|
179
|
+
def min(*args)
|
180
|
+
to_a(*args).min
|
181
|
+
end
|
182
|
+
|
183
|
+
def reject(*args)
|
184
|
+
a = []
|
185
|
+
each(*args){ |n| a << n if ! yield(n) }
|
186
|
+
a
|
187
|
+
end
|
188
|
+
|
189
|
+
def sort(*args)
|
190
|
+
# TODO
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
=end
|
195
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# = Equitable
|
2
|
+
#
|
3
|
+
# This mixin provides methods of equality based
|
4
|
+
# on a single #identity method which must return
|
5
|
+
# a list of accessors used as the identity keys.
|
6
|
+
#
|
7
|
+
# It also provides a "shortcut" for creating the
|
8
|
+
# #identity method based on given accessors and returns
|
9
|
+
# the Equitable module for inclusion.
|
10
|
+
#
|
11
|
+
# include Equitable(:a, :b)
|
12
|
+
#
|
13
|
+
# is equivalent to including a module containing:
|
14
|
+
#
|
15
|
+
# def ==(other)
|
16
|
+
# self.a == other.a && self.b == other.b
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# def eql?(other)
|
20
|
+
# self.a.eql?(other.a) && self.b.eql?(other.b)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def hash()
|
24
|
+
# self.a.hash ^ self.b.hash
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
module Equitable
|
28
|
+
|
29
|
+
def self.identify(base, *accessors)
|
30
|
+
base.send(:define_method, :identity){ accessors }
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def ==(o)
|
35
|
+
identity.all?{ |a| send(a) == o.send(a) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def eql?(o)
|
39
|
+
identity.all?{ |a| send(a).eql?(o.send(a)) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash
|
43
|
+
identity.inject(0){ |memo, a| memo ^ send(a).hash }
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class Module
|
49
|
+
|
50
|
+
# This function provided a "shortcut" for creating the
|
51
|
+
# #identity method based on given accessors and returns
|
52
|
+
# the Equitable module for inclusion.
|
53
|
+
#
|
54
|
+
# include Equitable(:a, :b)
|
55
|
+
#
|
56
|
+
# is equivalent to including a module containing:
|
57
|
+
#
|
58
|
+
# def ==(other)
|
59
|
+
# self.a == other.a && self.b == other.b
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# def eql?(other)
|
63
|
+
# self.a.eql?(other.a) && self.b.eql?(other.b)
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# def hash()
|
67
|
+
# self.a.hash ^ self.b.hash
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
|
71
|
+
def Equitable(*accessors)
|
72
|
+
Equitable.identify(self, *accessors)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# = Expirable
|
2
|
+
#
|
3
|
+
# Generic expirability mixin.
|
4
|
+
#
|
5
|
+
module Expirable
|
6
|
+
|
7
|
+
attr_accessor :expires
|
8
|
+
|
9
|
+
# Set the expires timeout for this entry.
|
10
|
+
|
11
|
+
def expires_after(timeout = (60*60*24))
|
12
|
+
@expires = Time.now + timeout
|
13
|
+
end
|
14
|
+
|
15
|
+
# Set the expire timeout for this entry. The timeout happens
|
16
|
+
# after (base + rand(spread)) seconds.
|
17
|
+
|
18
|
+
def expires_spread(base, spread)
|
19
|
+
@expires = Time.now + base + rand(spread)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Is this entry expired?
|
23
|
+
|
24
|
+
def expired?
|
25
|
+
if @expires.nil? or (Time.now > @expires)
|
26
|
+
return true
|
27
|
+
else
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Update the expiration period. Override in your application.
|
33
|
+
|
34
|
+
def touch!
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
data/lib/mixers/hook.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#require 'facets/kernel/instance_exec'
|
2
|
+
|
3
|
+
# TODO: hooks should be an inheritor
|
4
|
+
#
|
5
|
+
module Hook
|
6
|
+
|
7
|
+
def self.append_features(base)
|
8
|
+
base.extend self
|
9
|
+
end
|
10
|
+
|
11
|
+
def hooks
|
12
|
+
@hooks ||= Hash.new{ |h,k| h[k] = [] }
|
13
|
+
end
|
14
|
+
|
15
|
+
def hook(name)
|
16
|
+
name = name.to_sym
|
17
|
+
|
18
|
+
(class << self; self; end).class_eval %{
|
19
|
+
def #{name}(meth=nil, &blk)
|
20
|
+
hooks[:#{name}] << (meth || blk)
|
21
|
+
end
|
22
|
+
}
|
23
|
+
|
24
|
+
module_eval %{
|
25
|
+
def #{name}(*args)
|
26
|
+
self.class.hooks[:#{name}].each do |blk|
|
27
|
+
if Proc === blk
|
28
|
+
instance_exec(:#{name}, *args, &blk)
|
29
|
+
else
|
30
|
+
__send__(blk, :#{name}, *args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# = Instantiable
|
2
|
+
#
|
3
|
+
# Initialize modules, almost as if they were classes.
|
4
|
+
#
|
5
|
+
# Alows a module to be used much like a class, by defining
|
6
|
+
# a #new method that creates a class on demand.
|
7
|
+
#
|
8
|
+
module Instantiable
|
9
|
+
|
10
|
+
def self.append_features(mod)
|
11
|
+
mod.extend self
|
12
|
+
end
|
13
|
+
|
14
|
+
# Never use a class agian! ;)
|
15
|
+
|
16
|
+
def new(*args,&blk)
|
17
|
+
mod = self
|
18
|
+
@instantiable_class ||= Class.new{include mod}
|
19
|
+
@instantiable_class.new(*args,&blk)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# = Ostructable
|
2
|
+
#
|
3
|
+
# OpensStructable is a mixin module which can provide OpenStruct behavior to
|
4
|
+
# any class or object. OpenStructable allows extention of data objects
|
5
|
+
# with arbitrary attributes.
|
6
|
+
#
|
7
|
+
# == Usage
|
8
|
+
#
|
9
|
+
# require 'ostructable'
|
10
|
+
#
|
11
|
+
# class Record
|
12
|
+
# include OpenStructable
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# record = Record.new
|
16
|
+
# record.name = "John Smith"
|
17
|
+
# record.age = 70
|
18
|
+
# record.pension = 300
|
19
|
+
#
|
20
|
+
# puts record.name # -> "John Smith"
|
21
|
+
# puts record.address # -> nil
|
22
|
+
#
|
23
|
+
#--
|
24
|
+
# TODO: Keep this uptodate with ostruct.rb
|
25
|
+
#
|
26
|
+
# TODO: As with OpenStruct, marshalling is problematic at the moment.
|
27
|
+
#++
|
28
|
+
|
29
|
+
module OpenStructable
|
30
|
+
|
31
|
+
def initialize(hash=nil)
|
32
|
+
@__table__ = {}
|
33
|
+
if hash
|
34
|
+
for k,v in hash
|
35
|
+
@__table__[k.to_sym] = v
|
36
|
+
new_ostruct_member(k)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# duplicate an OpenStruct object members.
|
42
|
+
def initialize_copy(orig)
|
43
|
+
super
|
44
|
+
@__table__ = @__table__.dup
|
45
|
+
end
|
46
|
+
|
47
|
+
def marshal_dump
|
48
|
+
@table
|
49
|
+
end
|
50
|
+
def marshal_load(x)
|
51
|
+
@table = x
|
52
|
+
@table.each_key{|key| new_ostruct_member(key)}
|
53
|
+
end
|
54
|
+
|
55
|
+
def new_ostruct_member(name)
|
56
|
+
unless self.respond_to?(name)
|
57
|
+
self.instance_eval %{
|
58
|
+
def #{name}; @__table__[:#{name}]; end
|
59
|
+
def #{name}=(x); @__table__[:#{name}] = x; end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Generate additional attributes and values.
|
66
|
+
#
|
67
|
+
def update(hash)
|
68
|
+
@__table__ ||= {}
|
69
|
+
if hash
|
70
|
+
for k,v in hash
|
71
|
+
@__table__[k.to_sym] = v
|
72
|
+
new_ostruct_member(k)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing(mid, *args) # :nodoc:
|
78
|
+
mname = mid.to_s
|
79
|
+
len = args.length
|
80
|
+
if mname =~ /=$/
|
81
|
+
if len != 1
|
82
|
+
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
|
83
|
+
end
|
84
|
+
if self.frozen?
|
85
|
+
raise TypeError, "can't modify frozen #{self.class}", caller(1)
|
86
|
+
end
|
87
|
+
mname.chop!
|
88
|
+
@__table__ ||= {}
|
89
|
+
@__table__[mname.intern] = args[0]
|
90
|
+
self.new_ostruct_member(mname)
|
91
|
+
elsif len == 0
|
92
|
+
@__table__ ||= {}
|
93
|
+
@__table__[mid]
|
94
|
+
else
|
95
|
+
raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Remove the named field from the object.
|
101
|
+
#
|
102
|
+
def delete_field(name)
|
103
|
+
@__table__ ||= {}
|
104
|
+
@__table__.delete name.to_sym
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# Returns a string containing a detailed summary of the keys and values.
|
109
|
+
#
|
110
|
+
def inspect
|
111
|
+
str = "<#{self.class}"
|
112
|
+
for k,v in (@__table__ ||= {})
|
113
|
+
str << " #{k}=#{v.inspect}"
|
114
|
+
end
|
115
|
+
str << ">"
|
116
|
+
end
|
117
|
+
|
118
|
+
def __table__ # :nodoc:
|
119
|
+
@__table__ ||= {}
|
120
|
+
end
|
121
|
+
protected :__table__
|
122
|
+
|
123
|
+
# Compare this object and +other+ for equality.
|
124
|
+
def ==(other)
|
125
|
+
return false unless(other.kind_of?(OpenStruct))
|
126
|
+
return @__table__ == other.table
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
=begin
|
132
|
+
#
|
133
|
+
# It is possibe to implement OpenStruct itself with
|
134
|
+
# this OpenStructable module as follows:
|
135
|
+
#
|
136
|
+
class OpenStruct
|
137
|
+
include OpenStructable
|
138
|
+
end
|
139
|
+
=end
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
# _____ _
|
144
|
+
# |_ _|__ ___| |_
|
145
|
+
# | |/ _ \/ __| __|
|
146
|
+
# | | __/\__ \ |_
|
147
|
+
# |_|\___||___/\__|
|
148
|
+
#
|
149
|
+
|
150
|
+
=begin testing
|
151
|
+
|
152
|
+
require 'test/unit'
|
153
|
+
|
154
|
+
# fixture
|
155
|
+
|
156
|
+
class Record
|
157
|
+
include OpenStructable
|
158
|
+
end
|
159
|
+
|
160
|
+
# test
|
161
|
+
|
162
|
+
class TC_OpenStructable < Test::Unit::TestCase
|
163
|
+
|
164
|
+
def test_record
|
165
|
+
record = nil
|
166
|
+
assert_nothing_raised {
|
167
|
+
record = Record.new
|
168
|
+
record.name = "John Smith"
|
169
|
+
record.age = 70
|
170
|
+
record.pension = 300
|
171
|
+
}
|
172
|
+
assert_equal( "John Smith", record.name )
|
173
|
+
assert_equal( 70, record.age )
|
174
|
+
assert_equal( nil, record.address )
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
=end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# = Preinitialize
|
2
|
+
#
|
3
|
+
# This is an object preinitialize system, which provides
|
4
|
+
# an elegant way to initialize an object allowing the
|
5
|
+
# class to provide additional default structure to an
|
6
|
+
# object prior to calling initialize.
|
7
|
+
#
|
8
|
+
# In effect it does two things after allocating the object
|
9
|
+
# but prior to initializing it.
|
10
|
+
#
|
11
|
+
# First, it calls the class method #default_instance_variables,
|
12
|
+
# which returns a hash and by default returns the hash
|
13
|
+
# stored in @default_instance_variables. It uses this to
|
14
|
+
# pre-define instance variables.
|
15
|
+
#
|
16
|
+
# Then it goes to the top of the class hierarchy and works
|
17
|
+
# it's way down calling #preinitialize if defined.
|
18
|
+
# WARNING! It is rather useless to use <tt>super</tt>
|
19
|
+
# inside the any preinitialize hook.
|
20
|
+
#
|
21
|
+
# module M
|
22
|
+
# def preinitialize
|
23
|
+
# @a = 23
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# class X
|
28
|
+
# include M
|
29
|
+
# def a ; @a ; end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# x = X.new
|
33
|
+
# x.a #=> 23
|
34
|
+
#
|
35
|
+
# If neded the original new method has been aliased, albeit
|
36
|
+
# <tt>postinitialize_new</tt> is probably a bit of a misnomer.
|
37
|
+
|
38
|
+
#--
|
39
|
+
# class Module
|
40
|
+
#
|
41
|
+
# def default_instance_variables(complete=false)
|
42
|
+
# @default_instance_variables ||= {}
|
43
|
+
# unless complete
|
44
|
+
# return @default_instance_variables
|
45
|
+
# else
|
46
|
+
# parent = ancestors[1]
|
47
|
+
# if parent
|
48
|
+
# return @default_instance_variables.merge(parent.default_instance_variables)
|
49
|
+
# else
|
50
|
+
# return @default_instance_variables
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# end
|
56
|
+
#++
|
57
|
+
|
58
|
+
module Preinitializable
|
59
|
+
|
60
|
+
def self.included(base)
|
61
|
+
if Class===base
|
62
|
+
(class << base; self; end).__send__(:alias_method, :post_new, :new)
|
63
|
+
base.extend Meta
|
64
|
+
else
|
65
|
+
(class << base; self; end).__send__(:define_method, :included, &method(:included))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module Meta
|
70
|
+
|
71
|
+
def new(*args, &blk)
|
72
|
+
o = allocate
|
73
|
+
#if respond_to?(:default_instance_variables)
|
74
|
+
# default_instance_variables.each{|k,v| o.instance_variable_set( "@#{k.to_s.gsub(/\W$/,'')}",v )}
|
75
|
+
#end
|
76
|
+
a = ancestors
|
77
|
+
until a.empty?
|
78
|
+
m = a.pop
|
79
|
+
if m.private_instance_methods(false).include?('preinitialize') or
|
80
|
+
m.protected_instance_methods(false).include?('preinitialize') or
|
81
|
+
m.public_instance_methods(false).include?('preinitialize')
|
82
|
+
im = instance_method('preinitialize')
|
83
|
+
im.arity == 0 ? im.bind(o).call : im.bind(o).call(*args, &blk)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
o.__send__(:initialize, *args, &blk) if o.class.private_method_defined?(:initialize)
|
87
|
+
o
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# = Registerable
|
2
|
+
#
|
3
|
+
module Registerable
|
4
|
+
|
5
|
+
# Register format names.
|
6
|
+
|
7
|
+
def register(*names)
|
8
|
+
names.each do |name|
|
9
|
+
registry[name.to_s] = self
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Access registry.
|
14
|
+
|
15
|
+
def registry
|
16
|
+
@@registry ||= {}
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
|
21
|
+
def registry_invalid?(*types)
|
22
|
+
bad = []
|
23
|
+
types.each do |type|
|
24
|
+
bad << type unless @@registry[type]
|
25
|
+
end
|
26
|
+
return bad.empty? ? false : bad
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/meta/contact
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rubyworks-mailinglist@googlegroups.com
|
data/meta/description
ADDED
data/meta/homepage
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://rubyworks.github.com/mixers
|
data/meta/name
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mixers
|
@@ -0,0 +1 @@
|
|
1
|
+
http://github.com/rubyworks/mixers
|
@@ -0,0 +1 @@
|
|
1
|
+
http://rubyworks.github.com/mixers
|
data/meta/suite
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rubyworks
|
data/meta/summary
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Collection of helpful mixin modules
|
data/meta/version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'mixers/advisable'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestAdvice < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class X
|
7
|
+
include Advisable
|
8
|
+
|
9
|
+
attr_reader :out
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@out = []
|
13
|
+
end
|
14
|
+
|
15
|
+
before :x do
|
16
|
+
@out << "BEFORE X#x"
|
17
|
+
end
|
18
|
+
|
19
|
+
after :x do
|
20
|
+
@out << "AFTER X#x"
|
21
|
+
end
|
22
|
+
|
23
|
+
def x
|
24
|
+
@out << "X#x"
|
25
|
+
"x"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Y < X
|
30
|
+
before :x do
|
31
|
+
@out << "BEFORE Y#x"
|
32
|
+
end
|
33
|
+
|
34
|
+
after :x do
|
35
|
+
@out << "AFTER Y#x"
|
36
|
+
end
|
37
|
+
|
38
|
+
around :x do |target|
|
39
|
+
"{" + target.call + "}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def x
|
43
|
+
@out << "Y#x"
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# tests
|
49
|
+
|
50
|
+
def setup
|
51
|
+
@x = X.new
|
52
|
+
@y = Y.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_x
|
56
|
+
r = @x.x
|
57
|
+
o = @x.out
|
58
|
+
assert_equal("x", r)
|
59
|
+
assert_equal(["BEFORE X#x", "X#x", "AFTER X#x"], o)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_y
|
63
|
+
r = @y.x
|
64
|
+
o = @y.out
|
65
|
+
assert_equal("{x}", r)
|
66
|
+
assert_equal(["BEFORE Y#x", "BEFORE X#x", "Y#x", "X#x", "AFTER X#x", "AFTER Y#x"], o)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'mixers/cloneable'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class Foo
|
5
|
+
include Cloneable
|
6
|
+
def initialize
|
7
|
+
@bar=[]
|
8
|
+
end
|
9
|
+
def bar_id
|
10
|
+
@bar.object_id
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestCloneable < Test::Unit::TestCase
|
15
|
+
def test_dup
|
16
|
+
a=Foo.new
|
17
|
+
b=a.dup
|
18
|
+
assert_not_equal a.bar_id,b.bar_id
|
19
|
+
|
20
|
+
a.taint
|
21
|
+
b=a.dup
|
22
|
+
assert b.tainted?, "b should be tainted"
|
23
|
+
|
24
|
+
a.freeze
|
25
|
+
b=a.dup
|
26
|
+
assert !b.frozen?, "b should not be frozen"
|
27
|
+
end
|
28
|
+
def test_clone
|
29
|
+
a=Foo.new
|
30
|
+
b=a.clone
|
31
|
+
assert_not_equal a.bar_id,b.bar_id
|
32
|
+
|
33
|
+
a.taint
|
34
|
+
b=a.dup
|
35
|
+
assert b.tainted?, "b should be tainted"
|
36
|
+
|
37
|
+
a.freeze
|
38
|
+
b=a.clone
|
39
|
+
assert b.frozen?, "b should be frozen"
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'mixers/enumargs'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# fixture
|
5
|
+
|
6
|
+
class PlusArray
|
7
|
+
include Enumerable::Arguments
|
8
|
+
def initialize(arr)
|
9
|
+
@arr = arr
|
10
|
+
end
|
11
|
+
def each(n=0)
|
12
|
+
@arr.each{ |e| yield(e+n) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TC_Enumerable < Test::Unit::TestCase
|
17
|
+
|
18
|
+
def test_collect
|
19
|
+
t = PlusArray.new([1,2,3])
|
20
|
+
assert_equal( [5,6,7], t.collect(4){ |e| e } )
|
21
|
+
end
|
22
|
+
|
23
|
+
#def test_each_slice
|
24
|
+
# t = PlusArray.new([1,2,3,4])
|
25
|
+
# a = []
|
26
|
+
# t.each_slice(2,4){ |e,f| a << [e,f] }
|
27
|
+
# assert_equal( [[5,6],[7,8]], a )
|
28
|
+
#end
|
29
|
+
|
30
|
+
#def test_find
|
31
|
+
# t = PlusArray.new([1,2,3,4])
|
32
|
+
# f = t.find(2, :ifnone=>lambda{:NOPE}) { |a| a == 10 }
|
33
|
+
# assert_equal(:NOPE, f)
|
34
|
+
#end
|
35
|
+
|
36
|
+
def test_grep
|
37
|
+
# TODO
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_to_a
|
41
|
+
t = PlusArray.new([1,2,3])
|
42
|
+
assert_equal( [5,6,7], t.to_a(4) )
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_min
|
46
|
+
t = PlusArray.new([1,2,3])
|
47
|
+
assert_equal( 5, t.min(4) )
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_max
|
51
|
+
t = PlusArray.new([1,2,3])
|
52
|
+
assert_equal( 7, t.max(4) )
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_include?
|
56
|
+
t = PlusArray.new([1,2,3])
|
57
|
+
assert( t.include?(7,4) )
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_select
|
61
|
+
t = PlusArray.new([1,2,3])
|
62
|
+
assert_equal( [6], t.select(4){ |x| x == 6 } )
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_reject
|
66
|
+
t = PlusArray.new([1,2,3])
|
67
|
+
assert_equal( [5,7], t.reject(4){ |x| x == 6 } )
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'mixers/equitable'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestModuleEquatable < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_equatable_with_arguments
|
7
|
+
c = Class.new
|
8
|
+
c.class_eval {
|
9
|
+
include Equitable(:a,:b)
|
10
|
+
attr_accessor :a, :b
|
11
|
+
}
|
12
|
+
c1,c2 = c.new,c.new
|
13
|
+
c1.a = 10; c1.b = 20
|
14
|
+
c2.a = 10; c2.b = 20
|
15
|
+
assert_equal( c1, c2 )
|
16
|
+
c1.a = 10; c1.b = 10
|
17
|
+
c2.a = 10; c2.b = 20
|
18
|
+
assert_not_equal( c1, c2 )
|
19
|
+
c1.a = 10; c1.b = 20
|
20
|
+
c2.a = 20; c2.b = 20
|
21
|
+
assert_not_equal( c1, c2 )
|
22
|
+
end
|
23
|
+
|
24
|
+
=begin
|
25
|
+
def test_equate_on_old
|
26
|
+
c = Class.new
|
27
|
+
c.class_eval { attr_accessor :a, :b ; equate_on :a,:b }
|
28
|
+
c1,c2 = c.new,c.new
|
29
|
+
c1.a = 10; c1.b = 20
|
30
|
+
c2.a = 10; c2.b = 20
|
31
|
+
assert_equal( c1, c2 )
|
32
|
+
c1.a = 10; c1.b = 10
|
33
|
+
c2.a = 10; c2.b = 20
|
34
|
+
assert_not_equal( c1, c2 )
|
35
|
+
c1.a = 10; c1.b = 20
|
36
|
+
c2.a = 20; c2.b = 20
|
37
|
+
assert_not_equal( c1, c2 )
|
38
|
+
end
|
39
|
+
=end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'mixers/instantiable'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestInstantiable < Test::Unit::TestCase
|
5
|
+
|
6
|
+
module M
|
7
|
+
extend Instantiable
|
8
|
+
|
9
|
+
attr :a
|
10
|
+
|
11
|
+
def initialize( a )
|
12
|
+
@a = a
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module N
|
17
|
+
include Instantiable
|
18
|
+
|
19
|
+
attr :a
|
20
|
+
|
21
|
+
def initialize( a )
|
22
|
+
@a = a
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_m_new
|
27
|
+
m = M.new( 1 )
|
28
|
+
assert_equal( 1, m.a )
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_n_new
|
32
|
+
m = N.new( 1 )
|
33
|
+
assert_equal( 1, m.a )
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'mixers/preinitilizable'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TC_Preinitalizable < Test::Unit::TestCase
|
5
|
+
|
6
|
+
module M
|
7
|
+
include Preinitializable
|
8
|
+
def preinitialize
|
9
|
+
@a = 10
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class X
|
14
|
+
include M
|
15
|
+
def a; @a ; end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Y < X
|
19
|
+
def initialize
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_x
|
25
|
+
x = X.new
|
26
|
+
assert_equal(10, x.a)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_y
|
30
|
+
y = Y.new
|
31
|
+
assert_equal(10, y.a)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mixers
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors: []
|
12
|
+
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-27 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: |-
|
22
|
+
Ruby Mixers is collection mixin modules for the Ruby
|
23
|
+
programming language. Mixers is a spin-off of Ruby
|
24
|
+
Facets. When Ruby Facets scaled back to extensions
|
25
|
+
only project, it's mixin modules were gathered to
|
26
|
+
create this new project.
|
27
|
+
email:
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- README
|
34
|
+
files:
|
35
|
+
- lib/mixers/advisable.rb
|
36
|
+
- lib/mixers/cloneable.rb
|
37
|
+
- lib/mixers/enumargs.rb
|
38
|
+
- lib/mixers/equitable.rb
|
39
|
+
- lib/mixers/expirable.rb
|
40
|
+
- lib/mixers/hook.rb
|
41
|
+
- lib/mixers/instantiable.rb
|
42
|
+
- lib/mixers/ostructable.rb
|
43
|
+
- lib/mixers/preinitilizable.rb
|
44
|
+
- lib/mixers/registerable.rb
|
45
|
+
- meta/contact
|
46
|
+
- meta/description
|
47
|
+
- meta/homepage
|
48
|
+
- meta/name
|
49
|
+
- meta/resource/development
|
50
|
+
- meta/resource/homepage
|
51
|
+
- meta/suite
|
52
|
+
- meta/summary
|
53
|
+
- meta/version
|
54
|
+
- test/test_advisable.rb
|
55
|
+
- test/test_cloneable.rb
|
56
|
+
- test/test_enumargs.rb
|
57
|
+
- test/test_equitable.rb
|
58
|
+
- test/test_instantiable.rb
|
59
|
+
- test/test_preinitilizable.rb
|
60
|
+
- LICENSE
|
61
|
+
- README
|
62
|
+
- HISTORY
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://rubyworks.github.com/mixers
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options:
|
69
|
+
- --title
|
70
|
+
- Mixers API
|
71
|
+
- --main
|
72
|
+
- README
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
version: "0"
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
requirements: []
|
90
|
+
|
91
|
+
rubyforge_project: mixers
|
92
|
+
rubygems_version: 1.3.6
|
93
|
+
signing_key:
|
94
|
+
specification_version: 3
|
95
|
+
summary: Collection of helpful mixin modules
|
96
|
+
test_files:
|
97
|
+
- test/test_advisable.rb
|
98
|
+
- test/test_cloneable.rb
|
99
|
+
- test/test_enumargs.rb
|
100
|
+
- test/test_equitable.rb
|
101
|
+
- test/test_instantiable.rb
|
102
|
+
- test/test_preinitilizable.rb
|