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.
-
#avid? ⇒ Boolean
Is the instance avid for a name? (Will it overwrite other instance names?).
-
#make_not_avid! ⇒ Object
Make the instance not avid.
-
#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(target) ⇒ Object
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 74 def self.included target if target.is_a? Class then # decorate #new target.singleton_class.class_exec do # Primer that sets the namespace of the class to self if the user has # not defined otherwise when this method is first called. # define_method :namespace do target.extend ::NameMagic::NamespaceMethods define_singleton_method :namespace do target end # redefines itself namespace end end target.singleton_class.class_exec { prepend NameMagic::ClassMethods } else # it is a Module -- infect it with this #include orig, this = target.method( :included ), method( :included ) target.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_hook.( ɴ ) if ɴ end |
#avid? ⇒ Boolean
Is the instance avid for a name? (Will it overwrite other instance names?)
155 156 157 |
# File 'lib/y_support/name_magic.rb', line 155 def avid? namespace.__avid_instances__.any? &method( :equal? ) end |
#make_not_avid! ⇒ Object
Make the instance not avid.
161 162 163 |
# File 'lib/y_support/name_magic.rb', line 161 def make_not_avid! namespace.__avid_instances__.delete_if { |i| i.object_id == object_id } 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_hook.( ɴ, 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_hook.( ɴ, 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 |