TODO Is autoimport bets name for this?
append_features | -> | append_features_without_class_extension |
const_missing | -> | const_missing_before_autoimport |
$autoimport_activated = true |
# File lib/more/facets/module/class_extend.rb, line 87 87: def self.append_features(mod) 88: append_features_without_class_extension(mod) 89: end
This function provided a "shortcut" for creating the identity method based on given accessors and returns the Equitable module for inclusion.
include Equitable(: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/equitable.rb, line 115 115: def Equitable(*accessors) 116: Equitable.identify(self, *accessors) 117: end
Create aliases for flag accessors.
CREDIT: Trans
# File lib/more/facets/module/attr.rb, line 33 33: def alias_accessor!(*args) 34: orig = args.last 35: args = args - [orig] 36: args.each do |name| 37: alias_method("#{name}?", "#{orig}?") 38: alias_method("#{name}!", "#{orig}!") 39: end 40: end
Create aliases for flag reader.
CREDIT: Trans
# File lib/more/facets/module/attr_tester.rb, line 34 34: def alias_tester(*args) 35: orig = args.last 36: args = args - [orig] 37: args.each do |name| 38: alias_method("#{name}?", "#{orig}?") 39: end 40: end
Create aliases for attr_toggler.
CREDIT: Trans
# File lib/more/facets/module/attr_toggler.rb, line 49 49: def alias_toggler(*args) 50: orig = args.last 51: args = args - [orig] 52: args.each do |name| 53: alias_method("#{name}!", "#{orig}!") 54: alias_method("#{name}?", "#{orig}?") 55: end 56: end
Create aliases for validators.
# File lib/more/facets/module/attr_validator.rb, line 24 24: def alias_validator(*args) 25: orig = args.last 26: args = args - [orig] 27: args.each do |name| 28: #alias_method(name, orig) 29: alias_method("#{name}=", "#{orig}=") 30: end 31: end
Create aliases for flag writer.
CREDIT: Trans
# File lib/more/facets/module/attr.rb, line 75 75: def alias_writer!(*args) 76: orig = args.last 77: args = args - [orig] 78: args.each do |name| 79: alias_method("#{name}!", "#{orig}!") 80: end 81: end
Override append_features to handle class-inheritable extensions.
# File lib/more/facets/module/class_extend.rb, line 103 103: def append_features(mod) 104: append_features_without_class_extension(mod) 105: mod.extend(class_extend) 106: if mod.instance_of? Module 107: mod.__send__(:class_extend).__send__(:include, class_extend) 108: end 109: 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/module/attr.rb, line 22 22: def attr_switch_accessor(*args) 23: attr_reader!(*args) + attr_writer!(*args) 24: end
Create an tester attribute. This creates a single method used to test the attribute for truth.
attr_tester :a
is equivalent to
def a? @a ? true : @a end
# File lib/more/facets/module/attr_tester.rb, line 14 14: def attr_tester(*args) 15: code, made = '', [] 16: args.each do |a| 17: code << %{ 18: def #{a}?(truth=nil) 19: @#{a} ? truth || @#{a} : @#{a} 20: end 21: } 22: made << "#{a}?".to_sym 23: end 24: module_eval code 25: made 26: end
Create a flaggable attribute. This creates a single methods used to set an attribute to "true".
attr_toggler :a
is equivalent to
def a? @a ? true : @a end def a!(value=Exception) if Exception @a = @a ? false : true else @a = value end self end
# File lib/more/facets/module/attr_toggler.rb, line 25 25: def attr_toggler(*args) 26: code, made = '', [] 27: args.each do |a| 28: code << %{ 29: def #{a}!(value=Excception) 30: if Exception 31: @a = @a ? false : true 32: else 33: @a = value 34: end 35: self 36: end 37: } 38: made << "#{a}!".to_sym 39: end 40: module_eval code 41: made.concat(attr_tester(*args)) 42: made 43: end
Like attr_writer, but the writer method validates the setting against the given block.
CREDIT: ?
# File lib/more/facets/module/attr_validator.rb, line 8 8: def attr_validator(*symbols, &validator) 9: made = [] 10: symbols.each do |symbol| 11: define_method "#{symbol}=" do |val| 12: unless validator.call(val) 13: raise ArgumentError, "Invalid value provided for #{symbol}" 14: end 15: instance_variable_set("@#{symbol}", val) 16: end 17: made << "#{symbol}=".to_sym 18: end 19: made 20: 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/module/attr.rb, line 56 56: def attr_writer!(*args) 57: code, made = '', [] 58: args.each do |a| 59: code << %{ 60: def #{a}!(value=true) 61: @#{a} = value 62: self 63: end 64: } 65: made << "#{a}!".to_sym 66: end 67: module_eval code 68: made 69: end
Normally when including modules, class/module methods are not extended. To achieve this behavior requires some clever Ruby Karate. Instead class_extension provides an easy to use and clean solution. Simply place the extending class methods in a block of the special module method class_extension.
module Mix def inst_meth puts 'inst_meth' end class_extend do def class_meth "Class Method!" end end end class X include Mix end X.class_meth #=> "Class Method!"
NOTE: This old class_extension version of this method did not extend the containing class automatically —it had to be done by hand. With class_extend, that is no longer the case.
# File lib/more/facets/module/class_extend.rb, line 85 85: def class_extend(*mods, &block) 86: @class_extension ||= Module.new do 87: def self.append_features(mod) 88: append_features_without_class_extension(mod) 89: end 90: end 91: @class_extension.__send__(:include, *mods) 92: @class_extension.module_eval(&block) if block_given? 93: extend(@class_extension) # extend this module too 94: @class_extension 95: 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 103: def include_as(h) 104: h.each{ |name, mod| method_space(name, mod) } 105: end
Converts module methods into instance methods such that the first parameter is passed self. This promotes DRY programming when wishing to offer both inheritable and module callable procedures.
This method is modeled after module_function which essentially has the the opposite effect. Due to implementation limitations, this must use the callback singleton_method_added to emulate module_function when no method names are given.
module MyModule instance_function def self.jumble( obj, arg ) obj + arg end end class String include MyModule end MyModule.jumble( "Try", "Me" ) #=> "TryMe" "Try".jumble( "Me" ) #=> 'TryMe'
Note: This used to be a module called PromoteSelf and later Instantize, before becoming a method.
# File lib/more/facets/instance_function.rb, line 30 30: def instance_function(*meths) 31: if meths.empty? 32: extend InstanceFunction 33: else 34: meths.each do |meth| 35: class_eval %{ 36: def #{meth}(*args) 37: #{self.name}.#{meth}(self,*args) 38: end 39: } 40: end 41: end 42: 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 48: def method_space(name, mod=nil, &blk) 49: 50: # If block is given then create a module, otherwise 51: # get the name of the module. 52: if block_given? 53: name = name.to_s 54: raise ArgumentError if mod 55: mod = Module.new(&blk) 56: else 57: if Module === name 58: mod = name 59: name = mod.basename.downcase 60: end 61: mod = mod.dup 62: end 63: 64: # Include the module. This is neccessary, otherwise 65: # Ruby won't let us bind the instance methods. 66: include mod 67: 68: # Save the instance methods of the module and 69: # replace them with a "transparent" version. 70: methods = {} 71: mod.instance_methods(false).each do |m| 72: methods[m.to_sym] = mod.instance_method(m) 73: mod.instance_eval do 74: define_method(m) do 75: super 76: end 77: end 78: end 79: 80: # Add a method for the namespace that delegates 81: # via the Functor to the saved instance methods. 82: define_method(name) do 83: mtab = methods 84: Functor.new do |op, *args| 85: mtab[op].bind(self).call(*args) 86: end 87: end 88: end