Class: Module
- Defined in:
- lib/nano/module/sort_on.rb,
lib/nano/module/wrap.rb,
lib/nano/module/redef.rb,
lib/nano/module/sattr.rb,
lib/nano/module/undef.rb,
lib/nano/module/remove.rb,
lib/nano/module/rename.rb,
lib/nano/module/by_name.rb,
lib/nano/module/dirname.rb,
lib/nano/module/memoize.rb,
lib/nano/module/abstract.rb,
lib/nano/module/basename.rb,
lib/nano/module/modspace.rb,
lib/nano/module/redirect.rb,
lib/nano/module/equate_on.rb,
lib/nano/module/integrate.rb,
lib/nano/module/namespace.rb,
lib/nano/module/include_as.rb,
lib/nano/module/attr_setter.rb,
lib/nano/module/attr_tester.rb,
lib/nano/module/clone_using.rb,
lib/nano/module/initializer.rb,
lib/nano/module/wrap_method.rb,
lib/nano/module/cattr_reader.rb,
lib/nano/module/cattr_writer.rb,
lib/nano/module/rename_method.rb,
lib/nano/module/cattr_accessor.rb,
lib/nano/module/clone_removing.rb,
lib/nano/module/clone_renaming.rb,
lib/nano/module/redefine_method.rb,
lib/nano/module/redirect_method.rb,
lib/nano/module/instance_methods.rb,
lib/nano/module/alias_module_function.rb,
lib/nano/module/generate_instance_method_name.rb,
lib/nanosys.rb
Overview
– :TODO: Perhaps need to make a check against overriding Megas annotated version. ++
Constant Summary collapse
- METHOD_TYPES =
[ :inherited, :ancestors, :local, :public, :private, :protected, :all ]
Instance Method Summary collapse
- #abstract(*sym) ⇒ Object
-
#attr_setter(*args) ⇒ Object
Create an attribute method for both getting and setting an instance variable.
-
#attr_tester(*args) ⇒ Object
Create an tester attribute.
-
#basename ⇒ Object
Returns the root name of the module/class.
-
#by_name(name) ⇒ Object
Note: the following documentation uses “class” because it’s more common, but it applies to modules as well..
-
#cattr_accessor(*syms) ⇒ Object
Creates a class-variable attr_accessor that can be accessed both on an instance and class level.
-
#cattr_reader(*syms) ⇒ Object
Creates a class-variable attr_reader that can be accessed both on an instance and class level.
-
#cattr_writer(*syms) ⇒ Object
Creates a class-variable attr_writer that can be accessed both on an instance and class level.
-
#clone_removing(*meths) ⇒ Object
Returns an anonymous module with the specified methods of the receiving module removed.
-
#clone_renaming(pairs) ⇒ Object
Returns an anonymous module with the specified methods of the receiving module renamed.
-
#clone_using(*meths) ⇒ Object
Returns an anonymous module with only the specified methods of the receiving module intact.
-
#dirname ⇒ Object
Returns the name of module’s container module.
-
#equate_on(*fields) ⇒ Object
(also: #key_attributes)
Generates identity/key methods based on specified attributes.
-
#generate_instance_method_name(name = 'a') ⇒ Object
Generates a new symbol that is unique among the inctance methods of the class/module.
-
#include_as(h) ⇒ Object
Include a module via a specified namespace.
-
#initializer(*attributes, &block) ⇒ Object
Automatically create an initializer assigning the given arguments.
-
#instance_methods(*args) ⇒ Object
Provides an improved method lookup routnine.
- #integrate(mod, &blk) ⇒ Object
-
#memoize(*meths) ⇒ Object
Directive for making your functions faster by trading space for time.
-
#modspace ⇒ Object
Returns the module’s container module.
-
#namespace(name, &blk) ⇒ Object
Create a seperated method namespace.
-
#redirect_method(method_hash) ⇒ Object
Redirect methods to other methods.
-
#sattr(*args) ⇒ Object
Shortcuts for creating class instance attributes.
- #sattr_accessor(*args) ⇒ Object
- #sattr_reader(*args) ⇒ Object
- #sattr_setter(*args) ⇒ Object
- #sattr_tester(*args) ⇒ Object
- #sattr_writer(*args) ⇒ Object
-
#sort_on(*fields) ⇒ Object
(also: #compare_on, #sort_attributes)
Automatically generate sorting defintions base on attribute fields.
-
#use(*meths) ⇒ Object
Require method nano(s) for the class/module.
Instance Method Details
#abstract(*sym) ⇒ Object
13 14 15 16 17 |
# File 'lib/nano/module/abstract.rb', line 13 def abstract( *sym ) sym.each { |s| define_method( s ) { raise TypeError, "undefined abstraction ##{s}" } } end |
#attr_setter(*args) ⇒ Object
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
23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/nano/module/attr_setter.rb', line 23 def attr_setter(*args) make = {} args.each { |a| make[:"#{a}"] = %{ def #{a}(*args) args.size > 0 ? ( @#{a}=args[0] ; self ) : @#{a} end } } module_eval( make.values.join("\n") ) return make.keys end |
#attr_tester(*args) ⇒ Object
Create an tester attribute. This creates two methods for each given variable name. One is used to test the attribute and the other is used to set or toggle it.
attr_switch :a
is equivalent to
def a?
@a ? true : @a
end
def a!(switch=nack)
if switch == nack
@a = ! @a
else
@a = @a ? switch : @a
self
end
end
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/nano/module/attr_tester.rb', line 26 def attr_tester(*args) make = {} args.each { |a| make[:"#{a}?"] = %{ def #{a}?; @#{a} ? true : @#{a}; end } make[:"#{a}!"] = %{ def #{a}!(switch=nack) if switch==nack @#{a} = !@#{a} else @#{a} = @#{a} ? switch : @#{a} self end end } } module_eval make.values.join("\n") return make.keys end |
#basename ⇒ Object
Returns the root name of the module/class.
module Example
class Demo
end
end
Demo.name #=> Example::Demo
Demo.basename #=> Demo
13 14 15 |
# File 'lib/nano/module/basename.rb', line 13 def basename self.name.gsub(/^.*::/, '') end |
#by_name(name) ⇒ Object
Note: the following documentation uses “class” because it’s more common, but it applies to modules as well.
Given the name of a class, returns the class itself (i.e. instance of Class). The dereferencing starts at Object. That is,
Class.by_name("String")
is equivalent to
Object.const_get("String")
The parameter name is expected to be a Symbol or String, or at least to respond to to_str.
An ArgumentError is raised if name does not correspond to an existing class. If name is not even a valid class name, the error you’ll get is not defined.
Examples:
Class.by_name("String") # -> String
Class.by_name("::String") # -> String
Class.by_name("Process::Sys") # -> Process::Sys
Class.by_name("GorillaZ") # -> (ArgumentError)
Class.by_name("Enumerable") # -> Enumerable
Module.by_name("Enumerable") # -> Enumerable
– Credit for this goes to Gavin Sinclair ++
37 38 39 40 41 |
# File 'lib/nano/module/by_name.rb', line 37 def by_name(name) result = Object.constant(name) return result if result.kind_of?( Module ) raise ArgumentError, "#{name} is not a module or class" end |
#cattr_accessor(*syms) ⇒ Object
Creates a class-variable attr_accessor that can be accessed both on an instance and class level.
class MyClass
cattr_accessor :a
end
MyClass.a = 10
MyClass.a #=> 10
mc = MyClass.new
mc.a #=> 10
18 19 20 21 22 23 |
# File 'lib/nano/module/cattr_accessor.rb', line 18 def cattr_accessor(*syms) m = [] m.concat( cattr_reader(*syms) ) m.concat( cattr_writer(*syms) ) m end |
#cattr_reader(*syms) ⇒ Object
Creates a class-variable attr_reader that can be accessed both on an instance and class level.
class MyClass
@@a = 10
cattr_reader :a
end
MyClass.a #=> 10
MyClass.new.a #=> 10
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/nano/module/cattr_reader.rb', line 21 def cattr_reader(*syms) hsyms = ( syms.last.is_a?(Hash) ? syms.pop : {} ) hsyms.update( Hash[*(syms.zip([nil]*syms.size).flatten)] ) hsyms.each_pair do |sym, val| class_eval " if ! defined? @@\#{sym}\n @@\#{sym} = val\n end\n def self.\#{sym}\n @@\#{sym}\n end\n def \#{sym}\n self.class.\#{sym}\n end\n EOS\n end\n return hsyms.keys\nend\n" |
#cattr_writer(*syms) ⇒ Object
Creates a class-variable attr_writer that can be accessed both on an instance and class level.
class MyClass
cattr_writer :a
def a
@@a
end
end
MyClass.a = 10
MyClass.a #=> 10
MyClass.new.a = 29
MyClass.a #=> 29
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/nano/module/cattr_writer.rb', line 25 def cattr_writer(*syms) hsyms = ( syms.last.is_a?(Hash) ? syms.pop : {} ) hsyms.update( Hash[*(syms.zip([nil]*syms.size).flatten)] ) hsyms.each_pair do |sym, val| class_eval " if ! defined? @@\#{sym}\n @@\#{sym} = val\n end\n def self.\#{sym}=(obj)\n @@\#{sym} = obj\n end\n def \#{sym}=(obj)\n self.class.\#{sym}=(obj)\n end\n EOS\n end\n return hsyms.keys\nend\n" |
#clone_removing(*meths) ⇒ Object
Returns an anonymous module with the specified methods of the receiving module removed.
4 5 6 7 8 9 |
# File 'lib/nano/module/clone_removing.rb', line 4 def clone_removing( *meths ) mod = self.dup methods_to_remove = meths methods_to_remove.each { |m| mod.class_eval { remove_method m } } return mod end |
#clone_renaming(pairs) ⇒ Object
Returns an anonymous module with the specified methods of the receiving module renamed.
4 5 6 7 8 9 10 11 12 13 |
# File 'lib/nano/module/clone_renaming.rb', line 4 def clone_renaming( pairs ) mod = self.dup pairs.each_pair { |to_sym, from_sym| mod.class_eval { alias_method( to_sym, from_sym ) undef_method( from_sym ) } } return mod end |
#clone_using(*meths) ⇒ Object
Returns an anonymous module with only the specified methods of the receiving module intact.
6 7 8 9 10 11 12 |
# File 'lib/nano/module/clone_using.rb', line 6 def clone_using( *meths ) meths = meths.collect { |m| m.to_s } methods_to_remove = (self.instance_methods - meths) mod = self.dup mod.class_eval { methods_to_remove.each { |m| undef_method m } } return mod end |
#dirname ⇒ Object
Returns the name of module’s container module.
module Example
class Demo
end
end
Demo.name #=> "Example::Demo"
Demo.dirname #=> "Example"
See also Module#basename.
15 16 17 |
# File 'lib/nano/module/dirname.rb', line 15 def dirname name.gsub(/::[^:]*$/, '') end |
#equate_on(*fields) ⇒ Object Also known as: key_attributes
Generates identity/key methods based on specified attributes.
equate_on :a, :b
_is equivalent to_
def ==(o)
self.a == o.a && self.b == o.b
end
def eql?(o)
self.a.eql?(o.a) && self.b.eql?(o.b)
end
def hash()
self.a.hash ^ self.b.hash
end
25 26 27 28 29 30 31 32 |
# File 'lib/nano/module/equate_on.rb', line 25 def equate_on(*fields) code = "" code << "def ==(o) " << fields.map {|f| "self.#{f} == o.#{f}" }.join(" && ") << " end\n" code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?(o.#{f})" }.join(" && ") << " end\n" code << "def hash() " << fields.map {|f| "self.#{f}.hash" }.join(" ^ ") << " end\n" class_eval( code ) fields end |
#generate_instance_method_name(name = 'a') ⇒ Object
Generates a new symbol that is unique among the inctance methods of the class/module. If a name argument is given, it will generate a similar name.
Class.generate_instance_method_name( :class ) => :_clast_
10 11 12 13 14 15 16 |
# File 'lib/nano/module/generate_instance_method_name.rb', line 10 def generate_instance_method_name( name='a' ) s = name.to_s while self.method_defined?( "_#{s}_" ) s = s.succ end return :"_#{s}_" end |
#include_as(h) ⇒ Object
Include a module via a specified namespace.
module T
def t ; "HERE" ; end
end
class X
include_as :test => T
def t ; test.t ; end
end
X.new.t #=> "HERE"
19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/nano/module/include_as.rb', line 19 def include_as( h ) h.each{ |name, mod| s = self c = Class.new(SimpleDelegator) { include mod define_method(:initialize) { |s| super(s) } } class_eval { define_method( name ) { instance_variable_set( "@#{name}", instance_variable_get( "@#{name}" ) || c.new(s) ) } } } end |
#initializer(*attributes, &block) ⇒ Object
Automatically create an initializer assigning the given arguments.
class MyClass
initializer(:a, "b", :c)
end
_is equivalent to_
class MyClass
def initialize(a, b, c)
@a,@b,@c = a,b,c
end
end
Downside: Initializers defined like this can’t take blocks. This can be fixed when Ruby 1.9 is out.
The initializer will not raise an Exception when the user does not supply a value for each instance variable. In that case it will just set the instance variable to nil. You can assign default values or raise an Exception in the block.
25 26 27 28 29 30 31 32 33 |
# File 'lib/nano/module/initializer.rb', line 25 def initializer(*attributes, &block) define_method(:initialize) do |*args| attributes.zip(args) do |sym, value| instance_variable_set(:"@#{sym}", value) end instance_eval(&block) if block end end |
#instance_methods(*args) ⇒ Object
Provides an improved method lookup routnine. It returns a list of methods according to symbol(s) given.
Recognized symbols are:
-
:publicinclude public methods -
:privateinclude private methods -
:protectedinclude protected methods -
:ancestorsinclude all ancestor’s methods -
:inherited(same as above) -
<tt>:local</tti> include non-ancestor methods
-
:allinclude all of the above
This method also uses the symbol-not system. So you can specify the inverse of all of the above. For instance ~:public would mean :private, :protected (see nano/symbol/not).
If no symbol is given then :public, :local is assumed. Unrecognized symbols raise an error.
module Demo
def test
puts("Hello World!")
end
end
Demo.instance_methods(:local) #=> ['test']
To maintain backward compatibility true as an intitial argument is converted to :local, :ancestors (i.e. it includes both).
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/nano/module/instance_methods.rb', line 40 def instance_methods(*args) # for backward compatibility args << true if args.empty? case args[0] when TrueClass args.shift args << :ancestors args << :local when FalseClass args.shift args << :local end # default public, local args |= [:public] unless [:publix,:private,:protected,:all].any?{ |a| args.include?(a) } args |= [:ancestors,:local] unless [:ancestors,:inherited,:local,:all].any?{ |a| args.include?(a) } raise ArgumentError if args.any?{ |a| ! METHOD_TYPES.include?(a) } pos, neg = args.partition { |s| ! s.not? } m = [] pos.each do |n| case n when :inherited, :ancestors m |= ( public_instance_methods( true ) - public_instance_methods( false ) ) if pos.include?(:public) m |= ( private_instance_methods( true ) - private_instance_methods( false ) ) if pos.include?(:private) m |= ( protected_instance_methods( true ) - protected_instance_methods( false ) ) if pos.include?(:protected) when :local m |= public_instance_methods( false ) if pos.include?(:public) m |= private_instance_methods( false ) if pos.include?(:private) m |= protected_instance_methods( false ) if pos.include?(:protected) when :all m |= public_instance_methods( true ) m |= private_instance_methods( true ) m |= protected_instance_methods( true ) end end neg.each do |n| case n when :public m -= public_instance_methods( true ) when :private m -= private_instance_methods( true ) when :protected m -= protected_instance_methods( true ) when :inherited, :ancestors m -= ( public_instance_methods( true ) - public_instance_methods( false ) ) m -= ( private_instance_methods( true ) - private_instance_methods( false ) ) m -= ( protected_instance_methods( true ) - protected_instance_methods( false ) ) when :local m -= public_instance_methods( false ) m -= private_instance_methods( false ) m -= protected_instance_methods( false ) end end m.sort end |
#integrate(mod, &blk) ⇒ Object
10 11 12 13 14 15 |
# File 'lib/nano/module/integrate.rb', line 10 def integrate mod, &blk newmod = mod.dup newmod.class_eval &blk class_eval { include newmod } newmod end |
#memoize(*meths) ⇒ Object
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
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/nano/module/memoize.rb', line 27 def memoize(*meths) 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 |
#modspace ⇒ Object
Returns the module’s container module.
module Example
class Demo
end
end
Demo.modspace #=> Example
See also Module#basename.
17 18 19 |
# File 'lib/nano/module/modspace.rb', line 17 def modspace eval self.name[ 0...self.name.rindex( '::' ) ] end |
#namespace(name, &blk) ⇒ Object
Create a seperated method namespace.
module T
def t ; "HERE" ; end
end
class X
namespace :test { include T }
def t ; test.t ; end
end
X.new.t #=> "HERE"
NOTE: This is not as functional as it ought be in that the instance variables of the object are not accessible within the namespace.
22 23 24 25 26 27 28 29 30 31 |
# File 'lib/nano/module/namespace.rb', line 22 def namespace( name, &blk ) s = self c = Class.new(SimpleDelegator, &blk) c.class_eval { define_method(:initialize) { |s| super(s) } } self.class_eval { define_method( name ) { instance_variable_set( "@#{name}", instance_variable_get( "@#{name}" ) || c.new(s) ) } } end |
#redirect_method(method_hash) ⇒ Object
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
33 34 35 36 37 |
# File 'lib/nano/module/redirect_method.rb', line 33 def redirect_method( method_hash ) method_hash.each do |targ,adv| define_method(targ) { |*args| send(adv,*args) } end end |
#sattr(*args) ⇒ Object
Shortcuts for creating class instance attributes.
Concerning the naming of these emthods, since the letter ‘c’ has become the convention for class variable attributes (ie. @@v), the letter ‘s’ was chosen and stands for ‘self’ or ‘singleton’.
20 21 22 23 24 |
# File 'lib/nano/module/sattr.rb', line 20 def sattr(*args) class << self attr(*args) end end |
#sattr_accessor(*args) ⇒ Object
38 39 40 41 42 |
# File 'lib/nano/module/sattr.rb', line 38 def sattr_accessor(*args) class << self attr_accessor(*args) end end |
#sattr_reader(*args) ⇒ Object
26 27 28 29 30 |
# File 'lib/nano/module/sattr.rb', line 26 def sattr_reader(*args) class << self attr_reader(*args) end end |
#sattr_setter(*args) ⇒ Object
44 45 46 47 48 |
# File 'lib/nano/module/sattr.rb', line 44 def sattr_setter(*args) class << self attr_setter(*args) end end |
#sattr_tester(*args) ⇒ Object
50 51 52 53 54 |
# File 'lib/nano/module/sattr.rb', line 50 def sattr_tester(*args) class << self attr_tester(*args) end end |
#sattr_writer(*args) ⇒ Object
32 33 34 35 36 |
# File 'lib/nano/module/sattr.rb', line 32 def sattr_writer(*args) class << self attr_writer(*args) end end |
#sort_on(*fields) ⇒ Object Also known as: compare_on, sort_attributes
Automatically generate sorting defintions base on attribute fields.
sort_on :a, :b
_is equivalent to_
def <=>(o)
cmp = self.a <=> o.a; return cmp unless cmp == 0
cmp = self.b <=> o.b; return cmp unless cmp == 0
0
end
19 20 21 22 23 24 25 26 27 |
# File 'lib/nano/module/sort_on.rb', line 19 def sort_on(*fields) code = %{def <=>(o)\n} fields.each { |f| code << %{cmp = ( @#{f} <=> o.instance_variable_get('@#{f}') ); return cmp unless cmp == 0\n} } code << %{0\nend; alias_method :cmp, :<=>;} class_eval( code ) fields end |
#use(*meths) ⇒ Object
Require method nano(s) for the class/module.
String.use :humanize, last=
199 200 201 |
# File 'lib/nanosys.rb', line 199 def use( *meths ) NanoSystem.require( self, *meths ) end |