Module: NameMagic::ClassMethods

Defined in:
lib/y_support/name_magic/class_methods.rb

Overview

Class methods for the classes that include NameMagic.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.delegate_to_namespace(*symbols) ⇒ Object

Delegates methods to the namespace used by the class. Since the class frequently acts as its own namespace, this delegation requires special handling.



10
11
12
13
14
15
16
17
# File 'lib/y_support/name_magic/class_methods.rb', line 10

def self.delegate_to_namespace *symbols
  symbols.each { |ß|
    module_eval "def #{ß} *args\n" +
                "  return super if namespace == self\n" +
                "  namespace.#{ß}( *args )\n" +
                "end"
  }
end

Instance Method Details

#__forget__(instance) ⇒ Object

De-registers an instance without performing #const_magic first. The argument must be a registered instance, or TypeError ensues. Returns instance name for forgotten named instances, nil for forgotten nameless instances.



99
100
101
102
103
104
# File 'lib/y_support/name_magic/class_methods.rb', line 99

def __forget__ instance
  fail TypeError, "Supplied argument is not an instance " +
                  "of #{self}!" unless instance.is_a? self
  return super if namespace == self
  namespace.__forget__ instance
end

#forget(instance) ⇒ Object

Clears namespace-owned references to the specified instance. (This is different from de-naming an instance by setting inst.name = nil, which makes the instance anonymous, but still registered.)



89
90
91
92
# File 'lib/y_support/name_magic/class_methods.rb', line 89

def forget instance
  return super if namespace == self
  namespace.forget( instance instance )
end

#forget_all_instancesObject

Clears references to all the instances.



108
109
110
111
# File 'lib/y_support/name_magic/class_methods.rb', line 108

def forget_all_instances
  return super if namespace == self
  instances.map { |instance| __forget__ instance }
end

#instance(instance) ⇒ Object

Returns the instance identified by the first argument.



67
68
69
70
71
72
73
# File 'lib/y_support/name_magic/class_methods.rb', line 67

def instance instance
  return super if namespace == self
  namespace.instance( instance ).tap do |i|
    fail NameError, "No #{self} instance #{instance} " +
      "registered in #{namespace}!" unless i.kind_of? self
  end
end

#instancesObject

Returns the registered instances. Example:

class Animal; include NameMagic end Cat, Dog = Class.new( Animal ), Class.new( Animal ) Spot, Livia = Dog.new, Cat.new Animal.instances #=> [Spot, Livia] Dog.instances #=> [Spot] Cat.instances #=> [Livia]



60
61
62
63
# File 'lib/y_support/name_magic/class_methods.rb', line 60

def instances
  return super if namespace == self
  namespace.instances.select { |i| i.kind_of? self }
end

#nameless_instancesObject

Returns those of the registered instances, which are nameless.



77
78
79
80
81
82
# File 'lib/y_support/name_magic/class_methods.rb', line 77

def nameless_instances
  return super if namespace == self
  __instances__
    .select { |key, val| val.nil? and key.is_a? self }
    .keys
end

#namespace!Object

Sets the namespace for the class to self.



45
46
47
# File 'lib/y_support/name_magic/class_methods.rb', line 45

def namespace!
  nil.tap { self.namespace = self }
end

#namespace=(modul) ⇒ Object

Sets the namespace for the class.



36
37
38
39
40
41
# File 'lib/y_support/name_magic/class_methods.rb', line 36

def namespace= modul
  fail "Namespace cannot be redefined when instance registry " +
       "is not empty!" unless instances.empty?
  modul.extend ::NameMagic::Namespace
  define_singleton_method :namespace do modul end
end

#new(*args, &block) ⇒ Object

In addition to the ability to name objects by constant assignment it provides, NameMagic modifies #new method so that it will swallow certain parameters, namely :name (alias ), :name! and :avid. These can be used to name instances right off the bat with #new constructor:

Human = Class.new do include NameMagic end Human.new name: “Fred” Human.instances #=> [Fred]

Option :avid (true or false), when set to true, makes the instance so eager to be named that it will overwrite (steal) names already given to other instances. This allows us to redefine names to which we have already assigned something else.

Finally, parameter :name! acts as :name with :avid set to true:

instance_1 = Human.new name: “Joe” instance_1.name #=> :Joe Human.instance( :Joe ) == instance_1 #=> true instance_2 = Human.new name!: “Joe” instance_2.name #=> :Joe instance_1.name #=> nil Human.instance( :Joe ) == instance_1 #=> false Human.instance( :Joe ) == instance_2 #=> true



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/y_support/name_magic/class_methods.rb', line 141

def new *args, &block
  # Extract hash from args.
  oo = if args.last.is_a? Hash then args.pop else {} end
  # Swallow :name / :ɴ parameters.
  requested_name = oo.delete( :name ) || oo.delete(  )
  # Swallow :name! parameter.
  if oo[ :name! ] then
    fail ArgumentError, "Parameters :name! and :name (:ɴ) " +
      "cannot be supplied both at once!" if requested_name
    requested_name = oo.delete( :name! )
    exclamation_mark = true
  else
    exclamation_mark = false
  end
  # Prepare the arguments for instantiation.
  args << oo unless oo.empty?
  # Instantiate.
  instance = super *args, &block
  # Instantiation contract specifies that instances are created
  # unnamed. Thus, register the instance and set its name to nil.
  __instances__.update( instance => nil )
  # Instantiation contract specifies that instances are created
  # avid. Thus, make the instance avid.
  instance.send :make_avid!
  # Now, we have prepared the new instance nameless and avid
  # exactly according to the instantiation contract. Depending on
  # the arguments supplied to this method, the instance may soon
  # lose its avid state and get a name, but now, before any of
  # that happens, is the time to honor .instantiation_exec hook.
  honor_instantiation_exec( instance )
  # Return the instance if no name was requested for it.
  return instance unless requested_name
  # Now we know that a name was requested. The necessary action
  # depends on whether :name (:ɴ) or :name! parameter was used.
  # But already now, we know that the instance no longer needs
  # to be avid.
  instance.make_not_avid!
  # Depending on whether :name (:ɴ) or :name! was supplied...
  if exclamation_mark then
    # Name the instance aggresively.
    instance.name! requested_name
  else
    # Name the instance only if the name is not already in use.
    instance.name = requested_name
  end
  # Return the instance.
  return instance
end