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.