Module: NameMagic
- Defined in:
- lib/y_support/name_magic.rb
Overview
This mixin imitates Ruby constant magic and automates the named argument :name, alias :ɴ (Character “ɴ”, Unicode small capital N, generally stands for “name” ins YSupport). One can write:
require 'y_support/name_magic'
class Foo;
include NameMagic
end
Bar = Foo.new
The resulting object will know its #name
:
Bar.name #=> "Bar"
This is done by searching whole Ruby namespace for constants, via #const_magic defined in the namespace mixin. (Once the object is named, its assignments to other constants have no further effects.) By default, the class, in which NameMagic is included acts as a namespace: holds a list of instances and their names, which is often useful.
Foo.instances #=> [Bar]
It is possible to set another module as namespace:
Quux = Module.new
class FooBar
include NameMagic
end
FooBar.namespace = Quux
FooBar.new name: "Baz"
Quux.instances #=> [Baz]
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.instances._names_ #=> []
Animal.instances._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.instances._names_ #=> [:Spot, :Rover]
Animal.instances._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: #ɴ, #name)
Retrieves the instance’s name not prefixed by the namespace as a symbol.
-
#avid? ⇒ Boolean
Is the instance avid for a name? (Will it overwrite other instance names?).
-
#full_name ⇒ Object
Returns the instance’s full name, a string in the style of those returned by Module#name method, eg.
-
#inspect ⇒ Object
Default
#inspect
method forNameMagic
includers. -
#make_not_avid! ⇒ Object
Make the instance not avid.
-
#name!(name) ⇒ Object
Names an instance, aggresively (overwrites existing names).
-
#name=(name) ⇒ Object
Names an instance, cautiously (ie. no overwriting of existing names).
-
#name_set_hook(&block) ⇒ Object
Registers a hook to execute upon instance naming.
-
#namespace ⇒ Object
The namespace of the instance’s class.
-
#to_s ⇒ Object
Default
#to_s
method forNameMagic
includers, returning the name.
Class Method Details
.included(target) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/y_support/name_magic.rb', line 79 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.
127 128 129 130 |
# File 'lib/y_support/name_magic.rb', line 127 def __name__ ɴ = self.class.__instances__[ self ] namespace.name_get_hook.( ɴ ) if ɴ end |
#_name_ ⇒ Object Also known as: ɴ, name
Retrieves the instance’s name not prefixed by the namespace as a symbol. Underlines (#name
) distinguish this method from #name
method, which returns full name string for compatibility with vanilla Ruby Module#name.
108 109 110 111 |
# File 'lib/y_support/name_magic.rb', line 108 def _name_ self.class.const_magic __name__ or ( yield self if block_given? ) end |
#avid? ⇒ Boolean
Is the instance avid for a name? (Will it overwrite other instance names?)
166 167 168 |
# File 'lib/y_support/name_magic.rb', line 166 def avid? namespace.__avid_instances__.any? &method( :equal? ) end |
#full_name ⇒ Object
Returns the instance’s full name, a string in the style of those returned by Module#name method, eg. “Namespace::Name”.
119 120 121 |
# File 'lib/y_support/name_magic.rb', line 119 def full_name "#{namespace.name || namespace.inspect}::#{namespace.instances[ self ]}" end |
#inspect ⇒ Object
Default #inspect
method for NameMagic
includers.
195 196 197 |
# File 'lib/y_support/name_magic.rb', line 195 def inspect to_s end |
#make_not_avid! ⇒ Object
Make the instance not avid.
172 173 174 |
# File 'lib/y_support/name_magic.rb', line 172 def make_not_avid! namespace.__avid_instances__.delete_if { |i| i.object_id == object_id } end |
#name!(name) ⇒ Object
Names an instance, aggresively (overwrites existing names).
152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/y_support/name_magic.rb', line 152 def name!( name ) old_ɴ = namespace.__instances__[ self ] # previous name return self.name = nil if name.nil? # no collider concerns ɴ = honor_name_set_hooks( name, old_ɴ ) return false if old_ɴ == ɴ # already named as required pair = namespace.__instances__.rassoc( ɴ ) namespace.__forget__( pair[0] ) if pair # rudely forget the collider namespace.__forget__ old_ɴ # forget the old name of self namespace.const_set ɴ, self # write a constant namespace.__instances__[ self ] = ɴ # write to @instances end |
#name=(name) ⇒ Object
Names an instance, cautiously (ie. no overwriting of existing names).
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/y_support/name_magic.rb', line 134 def name=( name ) old_ɴ = namespace.__instances__[ self ] # previous name if name.nil? then namespace.__instances__.update( self => nil ) # unname in @instances namespace.send :remove_const, old_ɴ if old_ɴ # remove namespace const. else ɴ = honor_name_set_hooks( name, old_ɴ ) return if old_ɴ == ɴ # already named as required fail NameError, "Name '#{ɴ}' already exists in #{namespace} namespace!" if self.class.__instances__.rassoc( ɴ ) namespace.__forget__ old_ɴ # forget the old name of self namespace.const_set ɴ, self # write a constant namespace.__instances__[ self ] = ɴ # write to @instances end end |
#name_set_hook(&block) ⇒ Object
Registers a hook to execute upon instance naming. Instance’s ‘#name_set_hook` Behaves analogically as namespace’s ‘#name_set_hook`, and is executed right after the namespace’s hook. Expects a block with a single argument, name of the instance. The return value of the block is not used and should be nil. Without a block, this method acts as a getter.
182 183 184 185 |
# File 'lib/y_support/name_magic.rb', line 182 def name_set_hook &block tap { @name_set_hook = block } if block @name_set_hook ||= -> name { nil } end |
#namespace ⇒ Object
The namespace of the instance’s class.
100 101 102 |
# File 'lib/y_support/name_magic.rb', line 100 def namespace self.class.namespace end |
#to_s ⇒ Object
Default #to_s
method for NameMagic
includers, returning the name.
189 190 191 |
# File 'lib/y_support/name_magic.rb', line 189 def to_s name ? name.to_s : super end |