Class Module
In: lib/core/facets/module/basename.rb
lib/core/facets/module/attr_setter.rb
lib/core/facets/module/wrap_method.rb
lib/core/facets/module/spacename.rb
lib/core/facets/module/instance_method.rb
lib/core/facets/module/extend.rb
lib/core/facets/module/revise.rb
lib/core/facets/module/alias_method_chain.rb
lib/core/facets/module/rename_method.rb
lib/core/facets/module/abstract.rb
lib/core/facets/module/modspace.rb
lib/core/facets/module/class.rb
lib/core/facets/module/nesting.rb
lib/core/facets/module/is.rb
lib/core/facets/module/module_load.rb
lib/core/facets/module/instance_methods.rb
lib/core/facets/module/alias_module_function.rb
lib/core/facets/module/pathize.rb
lib/core/facets/module/op.rb
lib/core/facets/module/redefine_method.rb
lib/core/facets/module/include_function_module.rb
lib/core/facets/module/can.rb
lib/core/facets/module/conflict.rb
lib/core/facets/module/methodize.rb
lib/core/facets/module/redirect_method.rb
lib/core/facets/module/ancestor.rb
lib/core/facets/module/prepend.rb
lib/core/facets/module/alias_accessor.rb
lib/core/facets/comparable/comparable.rb
lib/core/facets/metaid.rb
Parent: Object

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

External Aliases

extend -> _extend
remove_method -> remove
undef_method -> nodef
=== -> class?
  Alias for #===. This provides a verbal method for inquery.
  s = "HELLO"
  String.class?(s)  #=> true

Public Instance methods

Rename methods.

  module A
    def a; "a"; end
  end

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

  class X; include B; end

  X.new.b    #=> "a"

Thomas Sawyer, Robert Dober

[Source]

    # File lib/core/facets/module/op.rb, line 80
80:   def *(rename_map)
81:     base = self
82:     Module.new do
83:       include base
84:       rename_map.each do |from, to|
85:         alias_method to, from
86:         undef_method from
87:       end
88:     end
89:   end

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, Robert Dober

[Source]

    # File lib/core/facets/module/op.rb, line 35
35:   def +(other)
36:     base = self
37:     Module.new do
38:       include base
39:       include other
40:     end
41:   end

Subtract modules.

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

CREDIT: Thomas Sawyer, Robert Dober

[Source]

    # File lib/core/facets/module/op.rb, line 49
49:   def -(other)
50:     case other
51:     when Array
52:       subtract = instance_methods(true) & other.collect{|m| m.to_s}
53:     when Module
54:       subtract = instance_methods(true) & other.instance_methods(true)  # false?
55:     when String, Symbol
56:       subtract = instance_methods(true) & [other.to_s]
57:     end
58:     base = self
59:     Module.new do
60:       include base
61:       subtract.each{ |x| undef_method x }
62:     end
63:   end

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

[Source]

    # File lib/core/facets/comparable/comparable.rb, line 28
28:   def Comparable(*accessors)
29:     define_method(:comparability){ accessors }
30:     code = %{
31:       def <=>(other)
32:         comparability.each do |a|
33:           cmp = (send(a) <=> other.send(a)); return cmp unless cmp == 0
34:         end
35:       end
36:     }
37:     module_eval code
38:     return Comparable
39:   end

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

[Source]

    # File lib/core/facets/module/abstract.rb, line 15
15:   def abstract( *sym )
16:     sym.each { |s|
17:       define_method( s ) { raise TypeError, "undefined abstraction ##{s}" }
18:     }
19:   end

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, Rails Team

[Source]

    # File lib/core/facets/module/alias_method_chain.rb, line 27
27:   def alias_method_chain(target, feature)
28:     # Strip out punctuation on predicates or bang methods since
29:     # e.g. target?_without_feature is not a valid method name.
30:     aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
31:     yield(aliased_target, punctuation) if block_given?
32: 
33:     with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
34: 
35:     alias_method without_method, target
36:     alias_method target, with_method
37: 
38:     case
39:       when public_method_defined?(without_method)
40:         public target
41:       when protected_method_defined?(without_method)
42:         protected target
43:       when private_method_defined?(without_method)
44:         private target
45:     end
46:   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

[Source]

    # File lib/core/facets/module/attr_setter.rb, line 49
49:   def alias_setter(*args)
50:     args = args - [orig]
51:     args.each do |name|
52:       alias_method(name, orig)
53:     end
54:   end

List all instance methods, equivalent to

  public_instance_methods +
  protected_instance_methods +
  private_instance_methods

TODO: Better name for all_instance_methods?

CREDIT: Trans

[Source]

    # File lib/core/facets/module/instance_methods.rb, line 13
13:   def all_instance_methods(include_super=true)
14:     public_instance_methods(include_super) +
15:     protected_instance_methods(include_super) +
16:     private_instance_methods(include_super)
17:   end

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

 class X ; end
 class Y < X ; end

  X.ancestor?(Y)

[Source]

    # File lib/core/facets/module/ancestor.rb, line 11
11:   def ancestor?( mod )
12:     ancestors.include? mod
13:   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

[Source]

    # File lib/core/facets/module/attr_setter.rb, line 21
21:   def attr_setter(*args)
22:     code, made = '', []
23:     args.each do |a|
24:       code << %{
25:         def #{a}(*args)
26:           args.size > 0 ? ( @#{a}=args[0] ; self ) : @#{a}
27:         end
28:       }
29:       made << "#{a}".to_sym
30:     end
31:     module_eval code
32:     made
33:   end

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

[Source]

    # File lib/core/facets/module/basename.rb, line 22
22:   def basename
23:     if name and not name.empty?
24:       name.gsub(/^.*::/, '')
25:     else
26:       nil #inspect.gsub('#<','').gsub('>','').sub(':', '_')
27:     end
28:   end
can(*mod, &blk)

Alias for extend

Defines an instance method within a class.

CREDIT: WhyTheLuckyStiff

[Source]

    # File lib/core/facets/metaid.rb, line 82
82:   def class_def name, &blk
83:     class_eval { define_method name, &blk }
84:   end
class_load( path )

Alias for module_load

class_require( path )

Alias for module_require

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, Robert Dober

[Source]

    # File lib/core/facets/module/conflict.rb, line 20
20:   def conflict?(other)
21:     common_ancestor = (ancestors & other.ancestors).first
22:     c = []
23:     c += (public_instance_methods(true) & other.public_instance_methods(true))
24:     c += (private_instance_methods(true) & other.private_instance_methods(true))
25:     c += (protected_instance_methods(true) & other.protected_instance_methods(true))
26:     c -= common_ancestor.public_instance_methods(true)
27:     c -= common_ancestor.private_instance_methods(true)
28:     c -= common_ancestor.protected_instance_methods(true)
29:     c.empty? ? false : c
30:   end

[Source]

   # File lib/core/facets/module/extend.rb, line 5
5:   def extend(*mod, &blk)
6:     _extend *mod unless mod.empty?
7:     _extend Module.new(&blk) if blk
8:   end

Access method as a singleton object and 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.

[Source]

    # File lib/core/facets/module/instance_method.rb, line 17
17:   def instance_method!(s)
18:     #( @@__instance_methods__ ||= {} )[s] ||= instance_method(s)  # TODO: use class vars for 1.9+ ?
19:     #( @__instance_methods__ ||= {} )[s.to_sym] ||= instance_method(s.to_sym)
20:     $FIRST_CLASS_INSTANCE_METHODS[self][s.to_sym] ||= instance_method(s.to_sym)
21:   end

Query whether a public instance method is defined for the module.

CREDIT: Gavin Sinclair, Noah Gibbs

[Source]

    # File lib/core/facets/module/instance_methods.rb, line 23
23:   def instance_method_defined?(meth)
24:     instance_methods(true).find{ |m| m == meth.to_s }
25:   end

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

[Source]

    # File lib/core/facets/module/revise.rb, line 51
51:   def integrate(mod, &block)
52:     #include mod.revisal( &blk )
53:     m = Module.new{ include mod }
54:     m.class_eval(&block)
55:     include m
56:   end

alias_method :is, :include

[Source]

    # File lib/core/facets/module/is.rb, line 27
27:   def is(*mods)
28:     mods.each do |mod|
29:       if mod.const_defined?(:Self)
30:         extend mod::Self
31:         # pass it along if module
32:         if instance_of?(Module)
33:           const_set(:Self, Module.new) unless const_defined?(:Self)
34:           const_get(:Self).send(:include, mod::Self)
35:         end
36:       end
37:     end
38:     include(*mods)
39:   end

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

[Source]

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

Translate a module name to a suitable method name.

  My::CoolClass.methodize => "my__cool_class"

[Source]

    # File lib/core/facets/module/methodize.rb, line 9
 9:   def methodize
10:     name.methodize
11:   end

Returns the module‘s container module.

  module Example
    class Demo
    end
  end

  Example::Demo.modspace   #=> Example

See also Module#basename.

CREDIT: Trans

[Source]

    # File lib/core/facets/module/modspace.rb, line 16
16:   def modspace
17:     space = name[ 0...(name.rindex( '::' ) || 0)]
18:     space.empty? ? Object : eval(space)
19:   end

Load file directly into module/class namespace.

Please use this with careful consideration. It is best suited to loading plugin-type scripts, and should generally not be used as a substitue for Ruby‘s standard load system.

CREDIT: Trans

[Source]

    # File lib/core/facets/module/module_load.rb, line 12
12:   def module_load( path )
13:     if path =~ /^[\/~.]/
14:       file = File.expand_path(path)
15:     else
16:       $LOAD_PATH.each do |lp|
17:         file = File.join(lp,path)
18:         break if File.exist?(file)
19:         file = nil
20:       end
21:     end
22:     raise LoadError, "no such file to load -- #{path}" unless file
23:     module_eval(File.read(file))
24:   end
module_method_defined?(meth)

Alias for singleton_method_defined?

Require file into module/class namespace.

Unlike load this keeps a per-module cache and will not load the same file into the same module more than once despite repeated attempts.

The cache is kept in a global var called +$module_require+.

Please use this with careful consideration. It is best suited to loading plugin-type scripts, and should generally not be used as a substitue for Ruby‘s standard load system.

CREDIT: Trans

[Source]

    # File lib/core/facets/module/module_load.rb, line 41
41:   def module_require( path )
42:     if path =~ /^[\/~.]/
43:       file = File.expand_path(path)
44:     else
45:       $LOAD_PATH.each do |lp|
46:         file = File.join(lp,path)
47:         break if File.exist?(file)
48:         file += '.rb'
49:         break if File.exist?(file)
50:         file = nil
51:       end
52:     end
53:     raise LoadError, "no such file to load -- #{path}" unless file
54:     # per-module load cache
55:     $module_require ||= {}
56:     $module_require[self] ||= {}
57:     loaded = $module_require[self]
58:     if loaded.key?(file)
59:       false
60:     else
61:       loaded[file] = true
62:       script = File.read(file)
63:       module_eval(script)
64:       true
65:     end
66:   end

Show a modules nesting in module namespaces.

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

CREDIT: Trans

[Source]

    # File lib/core/facets/module/nesting.rb, line 9
 9:   def nesting
10:     n = []
11:     name.split(/::/).inject(self) do |mod, name|
12:       c = mod.const_get(name) ; n << c ; c
13:     end
14:     return n
15:   end

Converts a class name to a unix path

Examples

  CoolClass.pathize       #=> "cool_class"
  My::CoolClass.pathize   #=> "my/cool_class"

[Source]

    # File lib/core/facets/module/pathize.rb, line 11
11:   def pathize
12:     name.pathize
13:     #to_s.
14:     #  gsub(/::/, '/').
15:     #  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
16:     #  gsub(/([a-z\d])([A-Z])/,'\1_\2').
17:     #  tr("-", "_").
18:     #  downcase
19:   end

Prepend an aspect module to a module. This only works at the module level.

  module X
    def x; "x"; end
  end

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

  X.prepend U

  X.x  # => "{x}"

CREDIT Trans

[Source]

    # File lib/core/facets/module/prepend.rb, line 20
20:   def prepend(aspect)
21:     aspect.__send__(:include, self)
22:     extend aspect
23:   end

Like conflict?, but checks only private methods.

[Source]

    # File lib/core/facets/module/conflict.rb, line 46
46:   def private_conflict?(other)
47:     common_ancestor = (ancestors & other.ancestors).first
48:     c = private_instance_methods(true) & other.private_instance_methods(true)
49:     c -= common_ancestor.private_instance_methods(true)
50:     c.empty? ? false : c
51:   end

Like conflict?, but checks only protected methods.

[Source]

    # File lib/core/facets/module/conflict.rb, line 54
54:   def protected_conflict?(other)
55:     common_ancestor = (ancestors & other.ancestors).first
56:     c = protected_instance_methods(true) & other.protected_instance_methods(true)
57:     c -= common_ancestor.protected_instance_methods(true)
58:     c.empty? ? false : c
59:   end

Like conflict?, but checks only public methods.

[Source]

    # File lib/core/facets/module/conflict.rb, line 38
38:   def public_conflict?(other)
39:     common_ancestor = (ancestors & other.ancestors).first
40:     c = public_instance_methods(true) & other.public_instance_methods(true)
41:     c -= common_ancestor.public_instance_methods(true)
42:     c.empty? ? false : c
43:   end
revisal(&blk)

Alias for revise

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

CREDIT: Trans

[Source]

    # File lib/core/facets/module/revise.rb, line 13
13:   def revise(&blk)
14:     base = self
15:     nm = Module.new{ include base }
16:     nm.class_eval(&blk)
17:     nm
18:   end

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

CREDIT: Gavin Sinclair, Noah Gibbs

[Source]

    # File lib/core/facets/module/instance_methods.rb, line 31
31:   def singleton_method_defined?(meth)
32:     singleton_methods(true).find{ |m| m == meth.to_s }
33:   end

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

[Source]

    # File lib/core/facets/module/spacename.rb, line 19
19:   def spacename
20:     name[0...(name.rindex('::') || 0)]
21:     #name.gsub(/::[^:]*$/, '')
22:   end
wrap( sym, &blk )

Alias for wrap_method

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

[Source]

    # File lib/core/facets/module/wrap_method.rb, line 20
20:   def wrap_method( sym, &blk )
21:     old = instance_method(sym)
22:     define_method(sym) { |*args| blk.call(old.bind(self), *args) }
23:   end

Private Instance methods

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

[Source]

    # File lib/core/facets/module/alias_accessor.rb, line 14
14:   def alias_accessor(*args)
15:     orig = args.last
16:     args = args - [orig]
17:     args.each do |name|
18:       alias_method(name, orig)
19:       alias_method("#{name}=", "#{orig}=")
20:     end
21:   end

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

[Source]

    # File lib/core/facets/module/alias_module_function.rb, line 24
24:   def alias_module_function(new, old)
25:     alias_method(new, old)
26:     module_function(new)
27:   end

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

[Source]

    # File lib/core/facets/module/alias_accessor.rb, line 26
26:   def alias_reader(*args)
27:     orig = args.last
28:     args = args - [orig]
29:     args.each do |name|
30:       alias_method(name, orig)
31:     end
32:   end

As with alias_method but does the writer instead.

[Source]

    # File lib/core/facets/module/alias_accessor.rb, line 36
36:   def alias_writer(*args)
37:     orig = args.last
38:     args = args - [orig]
39:     args.each do |name|
40:       alias_method("#{name}=", "#{orig}=")
41:     end
42:   end

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

[Source]

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

Alias for redefine_method

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

[Source]

    # File lib/core/facets/module/redefine_method.rb, line 26
26:   def redefine_method(sym, aka=nil, &blk)
27:     raise ArgumentError, "method does not exist" unless method_defined?( sym )
28:     alias_method( aka, sym ) if aka
29:     undef_method( sym )
30:     define_method( sym, &blk )
31:   end
redirect( method_hash )

Alias for redirect_method

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

[Source]

    # File lib/core/facets/module/redirect_method.rb, line 37
37:   def redirect_method( method_hash )
38:     method_hash.each do |targ,adv|
39:       define_method(targ) { |*args| send(adv,*args) }
40:     end
41:   end
rename( to_sym, from_sym )

Alias for rename_method

Aliases a method and undefines the original.

  rename_method( :to_method, :from_method  )

CREDIT: Trans

[Source]

    # File lib/core/facets/module/rename_method.rb, line 11
11:   def rename_method( to_sym, from_sym )
12:     raise ArgumentError, "method #{from_sym} does not exist" unless method_defined?( from_sym )
13:     alias_method( to_sym, from_sym )
14:     undef_method( from_sym )
15:   end

[Validate]