This is a module prepend system, which provides an elegant way to prepend code to the class hierarchy rather then append it (a la #).
class C
def f
"f"
end
end
module M
def f
'{' + super + '}'
end
end
class C
prepend M
end
c = C.new
c.f #=> "{f}"
This works by overriding Class#new so that all prepended modules extend new instances of the class upon instantiation.
Creates a class-variable attribute that can be accessed both on an instance and class level.
NOTE This used to be a Module method. But turns out it does not work as expected when included. The class-level method is not carried along. So it is now just a Class method. Accordingly, # has been deprecated.
CREDIT: David Heinemeier Hansson
# File lib/core/facets/class/cattr.rb, line 12
12: def cattr( *syms )
13: writers, readers = syms.flatten.partition{ |a| a.to_s =~ /=$/ }
14: writers = writers.collect{ |e| e.to_s.chomp('=').to_sym }
15: readers.concat( writers ) # writers also get readers
16: cattr_writer( *writers )
17: cattr_reader( *readers )
18: return readers + writers
19: end
Creates a class-variable attr_accessor that can be accessed both on an instance and class level.
class MyClass
cattr_accessor :a
end
MyClass.a = 10
MyClass.a #=> 10
mc = MyClass.new
mc.a #=> 10
CREDIT: David Heinemeier Hansson
# File lib/core/facets/class/cattr.rb, line 100
100: def cattr_accessor(*syms)
101: cattr_reader(*syms) + cattr_writer(*syms)
102: end
Creates a class-variable attr_reader that can be accessed both on an instance and class level.
class MyClass
@@a = 10
cattr_reader :a
end
MyClass.a #=> 10
MyClass.new.a #=> 10
CREDIT: David Heinemeier Hansson
# File lib/core/facets/class/cattr.rb, line 33
33: def cattr_reader( *syms )
34: syms.flatten.each do |sym|
35: class_eval( unless defined? @@#{sym} @@#{sym} = nil end def self.#{sym} @@#{sym} end def #{sym} @@#{sym} end, __FILE__, __LINE__)
36: end
37: return syms
38: end
Creates a class-variable attr_writer that can be accessed both on an instance and class level.
class MyClass
cattr_writer :a
def a
@@a
end
end
MyClass.a = 10
MyClass.a #=> 10
MyClass.new.a = 29
MyClass.a #=> 29
CREDIT: David Heinemeier Hansson
# File lib/core/facets/class/cattr.rb, line 68
68: def cattr_writer(*syms)
69: syms.flatten.each do |sym|
70: class_eval( unless defined? @@#{sym} @@#{sym} = nil end def self.#{sym}=(obj) @@#{sym} = obj end def #{sym}=(obj) @@#{sym}=(obj) end, __FILE__, __LINE__)
71: end
72: return syms
73: end
For Class, # is the same as class_eval. The alternative is to “undef_method :class_extend“, but this seems uneccessarily limited.
# File lib/more/facets/class_extend.rb, line 118
118: def class_extend(*mods, &block)
119: m = Module.new
120: m.__send__(:include, *mods)
121: m.module_eval(&block)
122: extend(m)
123: m
124: end
List all descedents of this class.
class X ; end class A < X; end class B < X; end X.descendents #=> [A,B]
You may also limit the generational distance the subclass may be from the parent class.
class X ; end class A < X; end class B < A; end X.descendents #=> [A, B] X.descendents(1) #=> [A]
NOTE: This is a intensive operation. Do not expect it to be super fast.
# File lib/core/facets/class/descendants.rb, line 22
22: def descendants(generations=nil)
23: subclass = []
24: ObjectSpace.each_object(Class) do |c|
25: ancestors = c.ancestors[0..(generations || 1)]
26: if ancestors.include?(self) and self != c
27: subclass << c
28: end
29: end
30: return subclass
31: end
Translate a class name to a suitable method name.
My::CoolClass.methodize => "my__cool_class"
# File lib/core/facets/class/methodize.rb, line 9
9: def methodize
10: name.methodize
11: end
# File lib/more/facets/preinitialize.rb, line 90
90: def new(*args, &blk)
91: o = allocate
92:
93: #if respond_to?(:default_instance_variables)
94: # default_instance_variables.each{|k,v| o.instance_variable_set( "@#{k.to_s.gsub(/\W$/,'')}",v )}
95: #end
96:
97: a = ancestors
98: until a.empty?
99: m = a.pop
100: #if m.private_instance_methods.include?('preinitialize') or m.public_instance_methods.include?('preinitialize')
101: if m.method_defined?('preinitialize') or m.private_method_defined?('preinitialize')
102: im = instance_method('preinitialize')
103: im.arity == 0 ? im.bind(o).call : im.bind(o).call(*args, &blk)
104: end
105: end
106:
107: o.__send__(:initialize, *args, &blk) if o.object_class.private_method_defined?(:initialize)
108:
109: o
110: end
# File lib/more/facets/prepend.rb, line 47
47: def new(*args, &blk)
48: o = allocate
49: prepend.each do |mod|
50: o.extend(mod)
51: end
52: o.__send__(:initialize, *args, &blk) #if private_method_defined?(:initialize)
53: o
54: end
Converts a class name to a unix path.
My::CoolClass.pathize #=> "my/cool_class"
# File lib/core/facets/class/pathize.rb, line 9
9: def pathize
10: name.pathize
11: end
# File lib/more/facets/prepend.rb, line 39
39: def prepend(*mods)
40: @prepend ||= []
41: @prepend.concat(mods)
42: @prepend
43: end
Prepend an “aspect module” to a class.
class Firetruck
def put_out_fire(option)
"Put out #{option}"
end
end
module FastFiretruck
def put_out_fire(option)
super("very #{option}!")
end
end
Firetruck.prepend(FastFiretruck)
ft = Firetruck.new
ft.put_out_fire('fast') #=> "Put out very fast!"
Implementation of this method has some limitations, in that it works by overriding # and #.
CREDIT: Trans
TODO: Perhaps rename this to preallocate, b/c of the way it works. It is not really a clean prepend, like that of Module#prepend.
# File lib/core/facets/class/prepend.rb, line 30
30: def prepend( aspect )
31: _new = method(:new)
32: _allocate = method(:allocate)
33: (class << self; self; end).class_eval do
34: define_method(:new) do |*args|
35: o = _new.call(*args)
36: o.extend aspect
37: o
38: end
39: define_method(:allocate) do |*args|
40: o = _allocate.call(*args)
41: o.extend aspect
42: o
43: end
44: end
45: end
Convert instatiation of a class into a Proc.
class Person
def initialize(name)
@name = name
end
def inspect
@name.to_str
end
end
%w(john bob jane hans).map(&Person) => [john, bob, jane, hans]
CREDIT: Daniel Schierbeck
# File lib/core/facets/class/to_proc.rb, line 18
18: def to_proc
19: proc{|*args| new(*args)}
20: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.