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
extend | -> | _extend |
remove_method | -> | remove |
undef_method | -> | nodef |
=== | -> | class? |
Alias for #===. This provides a verbal method for inquery.
s = "HELLO" String.class?(s) #=> true |
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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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)
# 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
# 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
# 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
Defines an instance method within a class.
CREDIT: WhyTheLuckyStiff
# File lib/core/facets/metaid.rb, line 82 82: def class_def name, &blk 83: class_eval { define_method name, &blk } 84: end
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
# 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
# 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.
# 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
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/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
# 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
# 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"
# 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
# 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
# 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
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
# 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
Converts a class name to a unix path
Examples
CoolClass.pathize #=> "cool_class" My::CoolClass.pathize #=> "my/cool_class"
# 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
# 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.
# 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.
# 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.
# 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
Return a new module based on another. This includes the original module into the new one.
CREDIT: Trans
# 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
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/core/facets/module/spacename.rb, line 19 19: def spacename 20: name[0...(name.rindex('::') || 0)] 21: #name.gsub(/::[^:]*$/, '') 22: end
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
# 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
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/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
# 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.
# 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.
# 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
# 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
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
# 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 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
# 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
Aliases a method and undefines the original.
rename_method( :to_method, :from_method )
CREDIT: Trans
# 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