Methods
Equatable alias_accessor! alias_reader! alias_reader? alias_setter alias_switcher alias_tester alias_toggler alias_validator alias_writer! ann ann! annotations append_features append_features append_features append_features_without_class_extension attr attr_accessor! attr_reader! attr_reader? attr_setter attr_switcher attr_tester attr_toggler attr_validator attr_writer! class_inherit class_methods classified_attributes define_dependency depend dependencies heritage include_as instance_method! memoize method_overloads method_space mixin_parameters mixin_params overload setting
Public Class methods
append_features(mod)
# File lib/more/facets/class_extension.rb, line 85
      def self.append_features(mod)
        append_features_without_class_extension(mod)
      end
Public Instance methods
Equatable(*accessors)

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
alias_accessor!(*args)

Create aliases for flag accessors.

 CREDIT: Trans
This method is also aliased as alias_switcher alias_toggler
# 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
alias_reader!(*args)

Create aliases for flag reader.

 CREDIT: Trans
This method is also aliased as alias_reader? alias_tester
# 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_reader?(*args)

Alias for alias_reader!

alias_setter(*args)

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
alias_switcher(*args)

Alias for alias_accessor!

alias_tester(*args)

Alias for alias_reader!

alias_toggler(*args)

Alias for alias_accessor!

alias_validator(*args)

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
alias_writer!(*args)

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
ann( ref, keys_or_class=nil, keys=nil )

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
ann!( ref, keys_or_class=nil, keys=nil )

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
annotations()
# File lib/more/facets/annotations.rb, line 108
  def annotations
    #$annotations[self]
    @annotations ||= {}
  end
append_features(mod)
# 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
append_features( base )
This method is also aliased as append_features_without_class_extension
# 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
append_features_without_class_extension( base )

Alias for append_features

attr( *args )
# 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
attr_accessor!(*args)

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
This method is also aliased as attr_switcher attr_toggler
# File lib/more/facets/attr.rb, line 107
  def attr_accessor!(*args)
    attr_reader!(*args) + attr_writer!(*args)
  end
attr_reader!(*args)

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
This method is also aliased as attr_reader? attr_tester
# 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
attr_reader?(*args)

Alias for attr_reader!

attr_setter(*args)

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
attr_switcher(*args)

Alias for attr_accessor!

attr_tester(*args)

Alias for attr_reader!

attr_toggler(*args)

Alias for attr_accessor!

attr_validator(*symbols, &validator)

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
attr_writer!(*args)

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
class_inherit( &yld )

Alias for class_methods

class_methods( &yld )
This method is also aliased as class_inherit
# 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
classified_attributes()

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
define_dependency( name, *deps )
# 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
depend( name_and_deps=nil )
# 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
dependencies(name, build=[])

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
heritage(ref)
# 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_as(h)

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
instance_method!(s)

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
memoize(*meths)

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
method_overloads()
# File lib/more/facets/overload.rb, line 25
  def method_overloads
    @method_overloads ||= {}
  end
method_space(name, mod=nil, &blk)

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
mixin_parameters()

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}
This method is also aliased as mixin_params
# File lib/more/facets/paramix.rb, line 196
  def mixin_parameters
    @mixin_parameters ||= {}
  end
mixin_params()

Alias for mixin_parameters

overload( name, *signiture, &block )

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
setting(sym, options = {})

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