Module: NameMagic
- Defined in:
- lib/y_support/name_magic.rb,
lib/y_support/name_magic/namespace_methods.rb
Overview
This mixin imitates Ruby constant magic and automates the named argument :name (alias :ɴ). One can write:
require 'y_support/name_magic'
class Foo; include NameMagic end
Bar = Foo.new
and the resulting object will know its #name:
Bar.name #=> :Bar
Foo::Bar #=> <Foo:0x.....>
This is done by searching whole Ruby namespace for constants, triggered by the method #const_magic defined in the namespace mixin. (Once the object is named, subsequent constant assignments have no effects.) By default, the namespace is the class, in which NameMagic is included, but it is possible to prescribe another module as a namespace:
Quux = Module.new
class FooBar
include NameMagic
self.namespace = Quux
end
FooBar.new name: "Baz"
FooBar::Baz #=> NameError
Quux::Baz #=> <FooBar:0x.....>
When subclassing the classes with NameMagic included, namespace setting does not change:
class Animal; include NameMagic end
class Dog < Animal; end
class Cat < Animal; end
Dog.namespace #=> Animal
Cat.namespace #=> Animal
Livia = Cat.new
Cat.instance_names #=> []
Animal.instance_names #=> [:Livia]
To make the subclasses use each their own namespace, use #namespace!
method:
Dog.namespace!
NameMagic also provides an alternative way to create named objects by taking care of :name (alias :ɴ) named argument of the constructor:
Dog.new name: "Spot"
Dog.new ɴ: :Rover
Dog.instance_names #=> [:Spot, :Rover]
Animal.instance_names #=> []
Lastly, a name can be assigned by #name= accssor, as in
o = SomeClass.new
o.name = "SomeName"
Hook is provided for when the name magic is performed, as well as when the name is retrieved.
Defined Under Namespace
Modules: ClassMethods, NamespaceMethods
Constant Summary collapse
- DEBUG =
false
Class Method Summary collapse
Instance Method Summary collapse
-
#__name__ ⇒ Object
Retrieves the instance name.
-
#name ⇒ Object
(also: #ɴ)
Retrieves an instance name.
-
#name!(ɴ) ⇒ Object
Names an instance, aggresively (overwrites existing names).
-
#name=(ɴ) ⇒ Object
Names an instance, cautiously (ie. no overwriting of existing names).
-
#namespace ⇒ Object
The namespace of the instance’s class.
Class Method Details
.included(modul) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/y_support/name_magic.rb', line 71 def self.included modul if modul.is_a? Class then # decorate #new class << modul alias :new_before_name_magic :new end modul.extend NameMagic::NamespaceMethods modul.extend NameMagic::ClassMethods # Attach namespace methods also to the namespace, if given begin if modul.namespace == modul then modul.define_singleton_method :namespace do modul end else modul.namespace.extend NameMagic::NamespaceMethods end rescue NoMethodError end else # it is a Module -- infect it with this #include orig, this = modul.method( :included ), method( :included ) modul.define_singleton_method :included do |m| this.( m ); orig.( m ) end end end |
Instance Method Details
#__name__ ⇒ Object
Retrieves the instance name. Does not trigger #const_magic before doing so.
109 110 111 112 |
# File 'lib/y_support/name_magic.rb', line 109 def __name__ ɴ = self.class.__instances__[ self ] namespace.name_get_closure.( ɴ ) if ɴ end |
#name ⇒ Object Also known as: ɴ
Retrieves an instance name.
101 102 103 104 |
# File 'lib/y_support/name_magic.rb', line 101 def name self.class.const_magic __name__ or ( yield self if block_given? ) end |
#name!(ɴ) ⇒ Object
Names an instance, aggresively (overwrites existing names).
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/y_support/name_magic.rb', line 136 def name!( ɴ ) old_ɴ = namespace.__instances__[ self ] # previous name if ɴ then puts "NameMagic: Rudely naming with #{ɴ}." if DEBUG ɴ = namespace.send( :validate_name, # honor the hook namespace.name_set_closure.( ɴ, self, old_ɴ ) ).to_sym puts "NameMagic: Name adjusted to #{ɴ}." if DEBUG return false if old_ɴ == ɴ # already named as required pair = namespace.__instances__.rassoc( ɴ ) namespace.__forget__( pair[0] ) if pair # rudely forget the collider namespace.const_set ɴ, self # write a constant namespace.__instances__[ self ] = ɴ # write to @instances namespace.__forget__ old_ɴ # forget the old name of self else self.name = nil # unnaming, no collider issues end end |
#name=(ɴ) ⇒ Object
Names an instance, cautiously (ie. no overwriting of existing names).
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/y_support/name_magic.rb', line 116 def name=( ɴ ) old_ɴ = namespace.__instances__[ self ] # previous name if ɴ then puts "NameMagic: Naming with argument #{ɴ}." if DEBUG ɴ = namespace.send( :validate_name, # honor the hook namespace.name_set_closure.( ɴ, self, old_ɴ ) ).to_sym puts "NameMagic: Name adjusted to #{ɴ}." if DEBUG return if old_ɴ == ɴ # already named as required fail NameError, "Name '#{ɴ}' already exists in #{namespace} namespace!" if self.class.__instances__.rassoc( ɴ ) namespace.const_set ɴ, self # write a constant namespace.__instances__[ self ] = ɴ # write to @instances namespace.__forget__ old_ɴ # forget the old name of self else puts "NameMagic: Unnaming #{old_ɴ || self}" if DEBUG namespace.__instances__.update( self => nil ) # unname in @instances namespace.send :remove_const, old_ɴ if old_ɴ # remove namespace const. end end |
#namespace ⇒ Object
The namespace of the instance’s class.
95 96 97 |
# File 'lib/y_support/name_magic.rb', line 95 def namespace self.class.namespace end |