[ + ]
# File lib/more/facets/class_extension.rb, line 85 def self.append_features(mod) append_features_without_class_extension(mod) end
This function provided a "shortcut" for creating the identity method based on given accessors and returns the Equatable module for inclusion.
include Equatable(:a, :b)
is equivalent to including a module containing:
def ==(other) self.a == other.a && self.b == other.b end def eql?(other) self.a.eql?(other.a) && self.b.eql?(other.b) end def hash() self.a.hash ^ self.b.hash end
[ + ]
# File lib/more/facets/equatable.rb, line 115 def Equatable(*accessors) Equatable.identify(self, *accessors) end
Create aliases for flag accessors.
CREDIT: Trans
[ + ]
# File lib/more/facets/attr.rb, line 117 def alias_accessor!(*args) orig = args.last args = args - [orig] args.each do |name| alias_method("#{name}?", "#{orig}?") alias_method("#{name}!", "#{orig}!") end end
Create aliases for flag reader.
CREDIT: Trans
[ + ]
# File lib/more/facets/attr.rb, line 159 def alias_reader!(*args) orig = args.last args = args - [orig] args.each do |name| alias_method("#{name}?", "#{orig}?") end end
Alias an accessor. This create an alias for both a reader and a writer.
class X attr_accessor :a alias_accessor :b, :a end x = X.new x.b = 1 x.a #=> 1 CREDIT: Trans
[ + ]
# File lib/more/facets/attr.rb, line 81 def alias_setter(*args) args = args - [orig] args.each do |name| alias_method(name, orig) end end
Create aliases for validators.
[ + ]
# File lib/more/facets/attr.rb, line 24 def alias_validator(*args) orig = args.last args = args - [orig] args.each do |name| #alias_method(name, orig) alias_method("#{name}=", "#{orig}=") end end
Create aliases for flag writer.
CREDIT: Trans
[ + ]
# File lib/more/facets/attr.rb, line 200 def alias_writer!(*args) orig = args.last args = args - [orig] args.each do |name| alias_method("#{name}!", "#{orig}!") end end
Set or read annotations.
[ + ]
# File lib/more/facets/annotations.rb, line 123 def ann( ref, keys_or_class=nil, keys=nil ) return heritage(ref) unless keys_or_class or keys if Class === keys_or_class keys ||= {} keys[:class] = keys_or_class else keys = keys_or_class end if Hash === keys ref = ref.to_sym annotations[ref] ||= {} annotations[ref].update(keys.rekey) else key = keys.to_sym heritage(ref)[key] end end
To change an annotation‘s value in place for a given class or module it first must be duplicated, otherwise the change may effect annotations in the class or module‘s ancestors.
[ + ]
# File lib/more/facets/annotations.rb, line 147 def ann!( ref, keys_or_class=nil, keys=nil ) #return heritage(ref) unless keys_or_class or keys return annotations[ref] unless keys_or_class or keys if Class === keys_or_class keys ||= {} keys[:class] = keys_or_class else keys = keys_or_class end if Hash === keys ref = ref.to_sym annotations[ref] ||= {} annotations[ref].update(keys.rekey) else key = keys.to_sym annotations[ref][key] = heritage(ref)[key].dup end end
[ + ]
# File lib/more/facets/annotations.rb, line 108 def annotations #$annotations[self] @annotations ||= {} end
[ + ]
# File lib/more/facets/class_extension.rb, line 95 def append_features(mod) append_features_without_class_extension(mod) mod.extend(class_extension) if mod.instance_of? Module mod.__send__(:class_extension).__send__(:include, class_extension) end end
[ + ]
# File lib/more/facets/classmethods.rb, line 163 def append_features( base ) result = append_features_without_classmethods( base ) if const_defined?( :ClassMethods ) base.extend( self::ClassMethods ) unless base.is_a?( Class ) unless base.const_defined?( :ClassMethods ) base.const_set( :ClassMethods, Module.new ) end my = self base::ClassMethods.class_eval do include my::ClassMethods end end end result end
Alias for append_features
[ + ]
# File lib/more/facets/annotations.rb, line 222 def attr( *args ) args.flatten! case args.last when TrueClass args.pop attr_accessor( *args ) when FalseClass args.pop attr_reader( *args ) else attr_reader( *args ) end end
Create a toggle attribute. This creates two methods for each given name. One is a form of tester and the other is used to toggle the value.
attr_accessor! :a
is equivalent to
def a? @a end def a!(value=true) @a = value self end CREDIT: Trans
[ + ]
# File lib/more/facets/attr.rb, line 107 def attr_accessor!(*args) attr_reader!(*args) + attr_writer!(*args) end
Create an tester attribute. This creates a single method used to test the attribute for truth.
attr_reader! :a
is equivalent to
def a? @a ? true : @a end
[ + ]
# File lib/more/facets/attr.rb, line 139 def attr_reader!(*args) code, made = '', [] args.each do |a| code << %{ def #{a}?(truth=nil) @#{a} ? truth || @#{a} : @#{a} end } made << "#{a}?".to_sym end module_eval code made end
Create an attribute method for both getting and setting an instance variable.
attr_setter :a
_is equivalent to_
def a(*args) if args.size > 0 @a = args[0] self else @a end end CREDIT: Trans
[ + ]
# File lib/more/facets/attr.rb, line 53 def attr_setter(*args) code, made = '', [] args.each do |a| code << %{ def #{a}(*args) args.size > 0 ? ( @#{a}=args[0] ; self ) : @#{a} end } made << "#{a}".to_sym end module_eval code made end
Like attr_writer, but the writer method validates the setting against the given block.
CREDIT: ?
[ + ]
# File lib/more/facets/attr.rb, line 8 def attr_validator(*symbols, &validator) made = [] symbols.each do |symbol| define_method "#{symbol}=" do |val| unless validator.call(val) raise ArgumentError, "Invalid value provided for #{symbol}" end instance_variable_set("@#{symbol}", val) end made << "#{symbol}=".to_sym end made end
Create a flaggable attribute. This creates a single methods used to set an attribute to "true".
attr_writer! :a
is equivalent to
def a!(value=true) @a = value self end
[ + ]
# File lib/more/facets/attr.rb, line 181 def attr_writer!(*args) code, made = '', [] args.each do |a| code << %{ def #{a}!(value=true) @#{a} = value self end } made << "#{a}!".to_sym end module_eval code made end
Alias for class_methods
[ + ]
# File lib/more/facets/classmethods.rb, line 180 def class_methods( &yld ) if const_defined?( :ClassMethods ) self::ClassMethods.class_eval( &yld ) else self.const_set( :ClassMethods, Module.new( &yld ) ) end extend( self::ClassMethods ) self::ClassMethods end
Return list of attributes that have a :class annotation.
class MyClass attr_accessor :test attr_accessor :name, String, :doc => 'Hello' attr_accessor :age, Fixnum end MyClass.instance_attributes # => [:test, :name, :age, :body] MyClass.classified_attributes # => [:name, :age]
[ + ]
# File lib/more/facets/annotations.rb, line 295 def classified_attributes instance_attributes.find_all do |a| self.ann(a, :class) end end
[ + ]
# File lib/more/facets/dependency.rb, line 120 def define_dependency( name, *deps ) @dependency ||= {} if @dependency[name.to_sym] @dependency[name.to_sym] = deps else @dependency[name.to_sym] = deps deplist = lambda{ dependencies(name) } alias_method("#{name}:execute",name) define_method(name) do |*a| # run dependencies deplist.call.each do |d| if respond_to?("#{d}:execute") send("#{d}:execute",*a) #,&b) else send(d,*a) #,&b) end end # run core method send("#{name}:execute",*a) #,&b) end end end
[ + ]
# File lib/more/facets/dependency.rb, line 90 def depend( name_and_deps=nil ) if Hash === name_and_deps name_and_deps.to_h.each do |name, deps| deps = [deps].flatten define_dependency(name, *deps) end elsif name_and_deps @dependency ||= {} @dependency[name_and_deps.to_sym] else @dependency ||= {} end end
Compile list of all unique prerequisite calls.
[ + ]
# File lib/more/facets/dependency.rb, line 106 def dependencies(name, build=[]) @dependency ||= {} deps = @dependency[name.to_sym] return build unless deps deps.each do |dep| build.unshift(dep) dependencies(dep,build) end build.uniq! build end
[ + ]
# File lib/more/facets/annotations.rb, line 113 def heritage(ref) ref = ref.to_sym ancestors.inject({}) { |memo, ancestor| ancestor.annotations[ref] ||= {} ancestor.annotations[ref] + memo } end
Include a module via a specified space.
module T def t ; "HERE" ; end end class X include_as :test => T def t ; test.t ; end end X.new.t #=> "HERE"
[ + ]
# File lib/more/facets/methodspace.rb, line 103 def include_as(h) h.each{ |name, mod| method_space(name, mod) } end
Easy access to method as objects, and they retain state!
module K def hello puts "Hello World!" end end p K.instance_method!(:hello) #=> <UnboundMethod: #hello>
NOTE: This is limited to the scope of the current module/class.
[ + ]
# File lib/more/facets/1stclassmethod.rb, line 134 def instance_method!(s) #( @@__instance_methods__ ||= {} )[s] ||= instance_method(s) # TODO when fixed ( @__instance_methods__ ||= {} )[s] ||= instance_method(s) end
Directive for making your functions faster by trading space for time. When you "memoize" a method/function its results are cached so that later calls with the same arguments returns results in the cache instead of recalculating them.
class T def initialize(a) @a = a end def a "#{@a ^ 3 + 4}" end memoize :a end t = T.new t.a.__id__ == t.a.__id__ #=> true
[ + ]
# File lib/more/facets/memoize.rb, line 61 def memoize(*meths) @_MEMOIZE_CACHE ||= Hash.new meths.each do |meth| mc = @_MEMOIZE_CACHE[meth] = Hash.new old = instance_method(meth) new = proc do |*args| if mc.has_key? args mc[args] else mc[args] = old.bind(self).call(*args) end end send(:define_method, meth, &new) end end
[ + ]
# File lib/more/facets/overload.rb, line 25 def method_overloads @method_overloads ||= {} end
Define a simple method namespace.
class A attr_writer :x method_space :inside do def x; @x; end end end a = A.new a.x = 10 a.inside.x #=> 10 a.x # no method error
[ + ]
# File lib/more/facets/methodspace.rb, line 48 def method_space(name, mod=nil, &blk) # If block is given then create a module, otherwise # get the name of the module. if block_given? name = name.to_s raise ArgumentError if mod mod = Module.new(&blk) else if Module === name mod = name name = mod.basename.downcase end mod = mod.dup end # Include the module. This is neccessary, otherwise # Ruby won't let us bind the instance methods. include mod # Save the instance methods of the module and # replace them with a "transparent" version. methods = {} mod.instance_methods(false).each do |m| methods[m.to_sym] = mod.instance_method(m) mod.instance_eval do define_method(m) do super end end end # Add a method for the namespace that delegates # via the Functor to the saved instance methods. define_method(name) do mtab = methods Functor.new do |op, *args| mtab[op].bind(self).call(*args) end end end
Store for parametric mixin parameters.
Returns a hash, the keys of which are the parametric mixin module and the values are the parameters associacted with this module/class.
class C include P(:x=>1) end C.mixin_parameters[P] #=> {:x=>1}
[ + ]
# File lib/more/facets/paramix.rb, line 196 def mixin_parameters @mixin_parameters ||= {} end
Alias for mixin_parameters
Overload methods.
class X def x "hello" end overload :x, Integer do |i| i end overload :x, String, String do |s1, s2| [s1, s2] end end
[ + ]
# File lib/more/facets/overload.rb, line 45 def overload( name, *signiture, &block ) raise ArgumentError unless signiture.all?{|s| s.instance_of?(Class)} name = name.to_sym if method_overloads.key?( name ) method_overloads[name][signiture] = block else method_overloads[name] = {} method_overloads[name][signiture] = block if method_defined?( name ) #method_overloads[name][nil] = instance_method( name ) #true alias_method( "#{name}Generic", name ) has_generic = true else has_generic = false end define_method( name ) do |*args| ovr = self.class.method_overloads["#{name}".to_sym] sig = args.collect{ |a| a.class } hit = nil faces = ovr.keys #.sort { |a,b| b.size <=> a.size } faces.each do |cmp| next unless cmp.size == sig.size if (0...cmp.size).all?{ |i| cmp[i] >= sig[i] } break hit = cmp end end if hit ovr[hit].call(*args) else if has_generic #ovr[nil] send( "#{name}Generic", *args ) #ovr[nil].bind(self).call(*args) else raise NoMethodError end end end end end
Defines a configuration setting for the enclosing class.
Example
class Compiler
setting :template_root, :default => 'src/template', :doc => 'The template root dir'
end
[ + ]
# File lib/more/facets/settings.rb, line 233 def setting(sym, options = {}) Settings.add_setting(self, sym, options) module_eval %{ def self.#{sym} Settings[#{self}][:#{sym}].value end def self.#{sym}=(obj) Settings.setting #{self}, :#{sym}, :value => obj end } end