It would nice if we could the following. Then the middle portion of the Comparable method would not be needed. But I fear it might break others code.

  module Comparable

   def <=>(other)
     comparability.each do |field|
       cmp = send(field) <=> other.send(field); return cmp unless cmp == 0
     end
   end

 end
Methods
Included Modules
Classes and Modules
Module Module::CloneExtensions
Public Instance methods
*(rename_map)

Rename methods.

  module A
    def a; "a"; end
  end

  B = A * { :a => :b }

  class X; include B; end

  X.new.b    #=> "a"

  CREDIT: Thomas Sawyer
  CREDIT: Robert Dober
# File lib/facets/module/op.rb, line 83
  def *(rename_map)
    base = self
    Module.new do
      include base
      rename_map.each do |from, to|
        alias_method to, from
        undef_method from
      end
    end
  end
+(other)

Combine modules.

  module A
    def a; "a"; end
  end

  module B
    def b; "b"; end
  end

  C = A + B

  class X; include C; end

  X.new.a    #=> "a"
  X.new.b    #=> "b"

Note that in the old version of traits.rb we cloned modules and altered their copies. Eg.

    def +(other)
      mod1 = other.clone
      mod2 = clone
      mod1.module_eval{ include mod2 }
    end

Later it was realized that this thwarted the main benefit that Ruby‘s concept of modules has over traditional traits, inheritance.

  CREDIT: Thomas Sawyer
  CREDIT: Robert Dober
# File lib/facets/module/op.rb, line 36
  def +(other)
    base = self
    Module.new do
      include base
      include other
    end
  end
-(other)

Subtract modules.

  TODO: Should this use all instance_methods, not just public?

  CREDIT: Thomas Sawyer
  CREDIT: Robert Dober
# File lib/facets/module/op.rb, line 51
  def -(other)
    case other
    when Array
      subtract = instance_methods(true) & other.collect{|m| m.to_s}
    when Module
      subtract = instance_methods(true) & other.instance_methods(true)  # false?
    when String, Symbol
      subtract = instance_methods(true) & [other.to_s]
    end
    base = self
    Module.new do
      include base
      subtract.each{ |x| undef_method x }
    end
  end
Comparable(*accessors)

Automatically generate sorting defintions base on attribute fields.

  include SortOn(:a, :b)

is equivalent to including a module containing:

  def <=>(other)
    cmp = self.a <=> other.a; return cmp unless cmp == 0
    cmp = self.b <=> other.b; return cmp unless cmp == 0
    0
  end
# File lib/facets/comparable/comparable.rb, line 28
  def Comparable(*accessors)
    define_method(:comparability){ accessors }
    code = %{
      def <=>(other)
        comparability.each do |a|
          cmp = (send(a) <=> other.send(a)); return cmp unless cmp == 0
        end
      end
    }
    module_eval code
    return Comparable
  end
abstract( *sym )

Create an abstract method. If it is not overridden, it will raise a TypeError when called.

  class C
    abstract :a
  end

  c = C.new
  c.a  #=> Error: undefined abstraction #a

 CREDIT: Trans
# File lib/facets/module/abstract.rb, line 15
  def abstract( *sym )
    sym.each { |s|
      define_method( s ) { raise TypeError, "undefined abstraction ##{s}" }
    }
  end
all_instance_methods(include_super=true)

List all instance methods, equivalent to

  public_instance_methods +
  protected_instance_methods +
  private_instance_methods

TODO: Better name for all_instance_methods?

 CREDIT: Trans
# File lib/facets/module/instance_methods.rb, line 13
  def all_instance_methods(include_super=true)
    public_instance_methods(include_super) +
    protected_instance_methods(include_super) +
    private_instance_methods(include_super)
  end
ancestor?( mod )

Is a given class or module an ancestor of this class or module?

 class X ; end
 class Y < X ; end

  X.ancestor?(Y)
# File lib/facets/module/ancestor.rb, line 11
  def ancestor?( mod )
    ancestors.include? mod
  end
basename()

Returns the root name of the module/class.

  module Example
    class Demo
    end
  end

  Demo.name       #=> "Example::Demo"
  Demo.basename   #=> "Demo"

For anonymous modules this will provide a basename based on Module#inspect.

  m = Module.new
  m.inspect       #=> "#<Module:0xb7bb0434>"
  m.basename      #=> "Module_0xb7bb0434"

  CREDIT: Trans
# File lib/facets/module/nesting.rb, line 54
  def basename
    if name and not name.empty?
      name.gsub(/^.*::/, '')
    else
      nil #inspect.gsub('#<','').gsub('>','').sub(':', '_')
    end
  end
class_def(name, &blk)

Defines an instance method within a class.

  CREDIT: WhyTheLuckyStiff
# File lib/facets/metaid.rb, line 109
  def class_def name, &blk
    class_eval { define_method name, &blk }
  end
class_load( path )

Alias for module_load

class_require( path )

Alias for module_require

conflict?(other)

Detect conflicts.

  module A
    def c; end
  end

  module B
    def c; end
  end

  A.conflict?(B)  #=> ["c"]

  TODO: All instance methods, or just public?

 CREDIT: Thomas Sawyer
 CREDIT: Robert Dober
# File lib/facets/module/conflict.rb, line 21
  def conflict?(other)
    c = []
    c += (public_instance_methods(true) & other.public_instance_methods(true))
    c += (private_instance_methods(true) & other.private_instance_methods(true))
    c += (protected_instance_methods(true) & other.protected_instance_methods(true))
    c.empty ? false : c
  end
instance_method_defined?(meth)

Query whether an instance method is defined for the module.

 CREDIT: Gavin Sinclair
 CREDIT: Noah Gibbs
# File lib/facets/module/instance_methods.rb, line 24
  def instance_method_defined?(meth)
    instance_methods_all(true).find{ |m| m == meth.to_s }
  end
integrate(mod, &block)

Using integrate is just like using include except the module included is a reconstruction of the one given altered by the commands given in the block.

Convenient commands available are: rename, redef, remove, nodef and wrap. But any module method can be used.

  module W
    def q ; "q" ; end
    def y ; "y" ; end
  end

  class X
    integrate W do
      nodef :y
    end
  end

  x = X.new
  x.q  #=> "q"
  x.y  #=> missing method error

This is like revisal, but revisal only returns the reconstructred module. It does not include it.

 CREDIT: Trans
# File lib/facets/module/revise.rb, line 46
  def integrate(mod, &block)
    #include mod.revisal( &blk )
    m = Module.new{ include mod }
    m.class_eval(&block)
    include m
  end
is(*mods)

alias_method :is, :include

# File lib/facets/module/is.rb, line 27
  def is(*mods)
    mods.each do |mod|
      if mod.const_defined?(:Self)
        extend mod::Self
        # pass it along if module
        if instance_of?(Module)
          const_set(:Self, Module.new) unless const_defined?(:Self)
          const_get(:Self).send(:include, mod::Self)
        end
      end
    end
    include(*mods)
  end
is?(base)

Is a given class or module an ancestor of this class or module?

 class X ; end
 class Y < X ; end

  Y.is?(X)  #=> true

  CREDIT: Trans
# File lib/facets/module/is.rb, line 13
  def is?(base)
    ancestors.slice(1..-1).include?(base)
  end
modspace()

Returns the module‘s container module.

  module Example
    class Demo
    end
  end

  Example::Demo.modspace   #=> Example

See also Module#basename.

  CREDIT: Trans
# File lib/facets/module/nesting.rb, line 30
  def modspace
    space = name[ 0...(name.rindex( '::' ) || 0)]
    space.empty? ? Object : eval(space)
  end
module_load( path )

Load file into module/class namespace.

  CREDIT: Trans
This method is also aliased as class_load
# File lib/facets/module/module_load.rb, line 9
    def module_load( path )
      if path =~ /^[\/~.]/
        file = File.expand_path(path)
      else
        $LOAD_PATH.each do |lp|
          file = File.join(lp,path)
          break if File.exist?(file)
          file = nil
        end
      end
      raise LoadError, "no such file to load -- #{path}" unless file
      module_eval(File.read(file))
    end
module_method_defined?(meth)

Alias for singleton_method_defined?

module_require( path )

Require file into module/class namespace.

  CREDIT: Trans
This method is also aliased as class_require
# File lib/facets/module/module_load.rb, line 27
    def module_require( path )
      if path =~ /^[\/~.]/
        file = File.expand_path(path)
      else
        $LOAD_PATH.each do |lp|
          file = File.join(lp,path)
          break if File.exist?(file)
          file += '.rb'
          break if File.exist?(file)
          file = nil
        end
      end
      raise LoadError, "no such file to load -- #{path}" unless file
      @loaded ||= {}
      if @loaded.key?(file)
        false
      else
        @loaded[file] = true
        script = File.read(file)
        module_eval(script)
        true
      end
    end
nesting()

Show a modules nesting in module namespaces.

  A::B::C.nesting  #=> [ A, A::B ]

 CREDIT: Trans
# File lib/facets/module/nesting.rb, line 9
  def nesting
    n = []
    name.split(/::/).inject(self) do |mod, name|
      c = mod.const_get(name) ; n << c ; c
    end
    return n
  end
pathize()

Converts a class name to a unix path

Examples

  CoolClass.pathize       #=> "cool_class"
  My::CoolClass.pathize   #=> "my/cool_class"
# File lib/facets/module/pathize.rb, line 9
  def pathize
    to_s.
      gsub(/::/, '/').
      gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
      gsub(/([a-z\d])([A-Z])/,'\1_\2').
      tr("-", "_").
      downcase
  end
prepend(aspect)

Prepend an aspect module to a module.

  module X
    def x; "x"; end
  end

  module U
    def x; '{' + super + '}'; end
  end

  X.prepend U

  X.x  # => "{x}"

 CREDIT Trans
# File lib/facets/module/prepend.rb, line 19
  def prepend(aspect)
    aspect.__send__(:include, self)
    extend aspect
  end
private_conflict?(other)

Like conflict?, but checks only private methods.

# File lib/facets/module/conflict.rb, line 43
  def private_conflict?(other)
    c = private_instance_methods(true) & other.private_instance_methods(true)
    c.empty ? false : c
  end
protected_conflict?(other)

Like conflict?, but checks only protected methods.

# File lib/facets/module/conflict.rb, line 50
  def protected_conflict?(other)
    c = protected_instance_methods(true) & other.protected_instance_methods(true)
    c.empty ? false : c
  end
public_conflict?(other)

Like conflict?, but checks only public methods.

# File lib/facets/module/conflict.rb, line 36
  def public_conflict?(other)
    c = public_instance_methods(true) & other.public_instance_methods(true)
    c.empty ? false : c
  end
revisal(&blk)

Alias for revise

revise(&blk)

Return a new module based on another. This includes the original module into the new one.

 CREDIT: Trans
This method is also aliased as revisal
# File lib/facets/module/revise.rb, line 8
  def revise(&blk)
    base = self
    nm = Module.new{ include base }
    nm.class_eval(&blk)
    nm
  end
singleton_method_defined?(meth)

Query whether a normal (singleton) method is defined for the module.

 CREDIT: Gavin Sinclair
 CREDIT: Noah Gibbs
This method is also aliased as module_method_defined?
# File lib/facets/module/instance_methods.rb, line 33
  def singleton_method_defined?(meth)
    singleton_methods(true).find{ |m| m == meth.to_s }
  end
spacename()

Returns the name of module‘s container module.

  module Example
    class Demo
    end
  end

  Demo.name         #=> "Example::Demo"
  Demo.spacename    #=> "Example"

This used to be called dirname.

See also Module#basename.

 CREDIT: Trans
# File lib/facets/module/nesting.rb, line 78
  def spacename
    name[0...(name.rindex('::') || 0)]
    #name.gsub(/::[^:]*$/, '')
  end
wrap( sym, &blk )

Alias for wrap_method

wrap_method( sym, &blk )

Creates a new method wrapping the previous of the same name. Reference to the old method is passed into the new definition block as the first parameter.

  wrap_method( sym ) { |old_meth, *args|
    old_meth.call
    ...
  }

Keep in mind that this can not be used to wrap methods that take a block.

  CREDIT: Trans
This method is also aliased as wrap
# File lib/facets/module/revise.rb, line 160
  def wrap_method( sym, &blk )
    old = instance_method(sym)
    define_method(sym) { |*args| blk.call(old.bind(self), *args) }
  end
Private Instance methods
alias_accessor(*args)

As with alias_method, but alias both reader and writer.

  attr_accessor :x
  self.x = 1
  alias_accessor :y, :x
  y #=> 1
  self.y = 2
  x #=> 2
# File lib/facets/module/alias.rb, line 14
  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_method_chain(target, feature) {|aliased_target, punctuation| ...}

Encapsulates the common pattern of:

  alias_method :foo_without_feature, :foo
  alias_method :foo, :foo_with_feature

With this, you simply do:

  alias_method_chain :foo, :feature

And both aliases are set up for you.

Query and bang methods (foo?, foo!) keep the same punctuation:

  alias_method_chain :foo?, :feature

is equivalent to

  alias_method :foo_without_feature?, :foo?
  alias_method :foo?, :foo_with_feature?

so you can safely chain foo, foo?, and foo! with the same feature.

 CREDIT: Bitsweat
 CREDIT: Rails Team
# File lib/facets/module/alias.rb, line 93
  def alias_method_chain(target, feature)
    # Strip out punctuation on predicates or bang methods since
    # e.g. target?_without_feature is not a valid method name.
    aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
    yield(aliased_target, punctuation) if block_given?

    with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"

    alias_method without_method, target
    alias_method target, with_method

    case
      when public_method_defined?(without_method)
        public target
      when protected_method_defined?(without_method)
        protected target
      when private_method_defined?(without_method)
        private target
    end
  end
alias_module_function(new, old)

Alias a module function so that the alias is also a module function. The typical alias_method does not do this.

  module Demo
    module_function
    def hello
      "Hello"
    end
  end

  Demo.hello    #=> Hello

  module Demo
    alias_module_function( :hi , :hello )
  end

  Demo.hi       #=> Hello
# File lib/facets/module/alias.rb, line 63
  def alias_module_function(new, old)
    alias_method(new, old)
    module_function(new)
  end
alias_reader(*args)

As with alias_accessor, but just for the reader. This is basically the same as alias_method.

# File lib/facets/module/alias.rb, line 26
  def alias_reader(*args)
    orig = args.last
    args = args - [orig]
    args.each do |name|
      alias_method(name, orig)
    end
  end
alias_writer(*args)

As with alias_method but does the writer instead.

# File lib/facets/module/alias.rb, line 36
  def alias_writer(*args)
    orig = args.last
    args = args - [orig]
    args.each do |name|
      alias_method("#{name}=", "#{orig}=")
    end
  end
include_function_module(*mod)

Include module and apply module_fuction to the included methods.

  module Utils
    module_function
    def foo; "foo"; end
  end

  module UtilsPlus
    include_function_module Utils
  end

 CREDIT: Trans
# File lib/facets/module/include_function_module.rb, line 19
  def include_function_module *mod
    include(*mod)
    module_function(*mod.collect{|m| m.private_instance_methods & m.methods(false)}.flatten)
  end
redef(sym, aka=nil, &blk)

Alias for redefine_method

redefine_method(sym, aka=nil, &blk)

Creates a new method for a pre-existing method.

If aka is given, then the method being redefined will first be aliased to this name.

  class Greeter
    def hello ; "Hello" ; end
  end

  Greeter.new.hello   #=> "Hello"

  class Greeter
    redefine_method( :hello, :hi ) do
      hi + ", friend!"
    end
  end

  Greeter.new.hello   #=> "Hello, friend!"

  CREDIT: Trans
This method is also aliased as redef
# File lib/facets/module/revise.rb, line 76
  def redefine_method(sym, aka=nil, &blk)
    raise ArgumentError, "method does not exist" unless method_defined?( sym )
    alias_method( aka, sym ) if aka
    undef_method( sym )
    define_method( sym, &blk )
  end
redirect( method_hash )

Alias for redirect_method

redirect_method( method_hash )

Redirect methods to other methods. This simply defines methods by the name of a hash key which calls the method with the name of the hash‘s value.

  class Example
    redirect_method :hi => :hello, :hey => :hello
    def hello(name)
      puts "Hello, #{name}."
    end
  end

  e = Example.new
  e.hello("Bob")    #=> "Hello, Bob."
  e.hi("Bob")       #=> "Hello, Bob."
  e.hey("Bob")      #=> "Hello, Bob."

The above class definition is equivalent to:

  class Example
    def hi(*args)
      hello(*args)
    end
    def hey(*args)
      hello(*args)
    end
    def hello
      puts "Hello"
    end
  end

  CREDIT: Trans
This method is also aliased as redirect
# File lib/facets/module/revise.rb, line 115
  def redirect_method( method_hash )
    method_hash.each do |targ,adv|
      define_method(targ) { |*args| send(adv,*args) }
    end
  end
rename( to_sym, from_sym )

Alias for rename_method

rename_method( to_sym, from_sym )

Aliases a method and undefines the original.

  rename_method( :to_method, :from_method  )

  CREDIT: Trans
This method is also aliased as rename
# File lib/facets/module/revise.rb, line 127
  def rename_method( to_sym, from_sym )
    raise ArgumentError, "method #{from_sym} does not exist" unless method_defined?( from_sym )
    alias_method( to_sym, from_sym )
    undef_method( from_sym )
  end