y_support 2.0.43 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/y_support/name_magic/class_methods.rb +181 -29
- data/lib/y_support/name_magic/hash.rb +1 -1
- data/lib/y_support/name_magic/namespace_methods.rb +71 -98
- data/lib/y_support/name_magic.rb +34 -25
- data/lib/y_support/version.rb +1 -1
- data/test/name_magic_test.rb +13 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d09cacddac5d80bc24a3064513b05fe98bb55535
|
4
|
+
data.tar.gz: a17182ae74bb384a3c4d13abf7dc34c3a4bf5060
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 148b04b34ba5dc66cb8d09543ae78c8558203fd8107844c0958a06e609c9dced068bbbce52052a1a66040dafa199e6a6d8f95269f6fb3fc8402a5151d4500dba
|
7
|
+
data.tar.gz: bb923dc9a8b48d19bd89705e104f63251078c5e78800bbaac7b58dc182b1000e6514d3241f57b077963038af8f1b0daae2f8fd5cc454dfd55e0839cbf308688e
|
@@ -4,30 +4,168 @@ module NameMagic::ClassMethods
|
|
4
4
|
# Presents the instances registered by the namespace. Takes one optional
|
5
5
|
# argument. If set to _false_, the method returns all the instances
|
6
6
|
# registered by the namespace. If set to _true_ (default), only returns
|
7
|
-
# those instances registered by the namespace, which are of the
|
8
|
-
# class as the
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
7
|
+
# those instances registered by the namespace, which are of exactly the same
|
8
|
+
# class as the receiver. Example:
|
9
|
+
#
|
10
|
+
# <code>
|
11
|
+
# class Animal; include NameMagic end
|
12
|
+
# Cat, Dog = Class.new( Animal ), Class.new( Animal )
|
13
|
+
# Spot = Dog.new
|
14
|
+
# Livia = Cat.new
|
15
|
+
# Animal.instances #=> returns 2 instances (2 animals)
|
16
|
+
# Dog.instances #=> returns 1 instance (only 1 is of Dog subclass)
|
17
|
+
# Dog.instances( false ) #=> 2 instances again (all the animals)
|
18
|
+
# </code>
|
17
19
|
#
|
18
|
-
def instances option=
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def instances option=true
|
21
|
+
return super if namespace == self
|
22
|
+
ii = namespace.instances
|
23
|
+
option ? ii.select { |i| i.kind_of? self } : ii
|
22
24
|
end
|
23
25
|
|
24
26
|
# Presents the instance names. Takes one optional argument, same as
|
25
|
-
#
|
27
|
+
# +#instances+ method.
|
26
28
|
#
|
27
|
-
def instance_names option=
|
29
|
+
def instance_names option=true
|
28
30
|
instances( option ).names( false )
|
29
31
|
end
|
30
32
|
|
33
|
+
# Presents namespace-owned +@instances+ hash. The hash consists of pairs
|
34
|
+
# <code>{ instance => instance_name }</code>. Unnamed instances have +nil+
|
35
|
+
# assigned to them as their name. (The method does not trigger
|
36
|
+
# +#const_magic+.)
|
37
|
+
#
|
38
|
+
def __instances__
|
39
|
+
return super if namespace == self
|
40
|
+
namespace.__instances__
|
41
|
+
end
|
42
|
+
|
43
|
+
# Presents namespace-owned +@avid_instances+ (array of avid instances). "Avid"
|
44
|
+
# means that the instance is able to overwrite a name used by another
|
45
|
+
# registered instance. (This method does not trigger +#const_magic+.)
|
46
|
+
#
|
47
|
+
def __avid_instances__
|
48
|
+
return super if namespace == self
|
49
|
+
namespace.__avid_instances__
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the instance identified by the first argument, which can typically
|
53
|
+
# be a name (string/symbol). If a registered instance is supplied, it is
|
54
|
+
# returned without change. The second argument is optional, with the same
|
55
|
+
# meaning as in +NameMagic::ClassMethods#instances+ method.
|
56
|
+
#
|
57
|
+
def instance id, option=true
|
58
|
+
return super if namespace == self
|
59
|
+
namespace.instance( id ).tap { |inst|
|
60
|
+
fail NameError, "No #{self} instance #{id} registered in " +
|
61
|
+
"#{namespace}!" unless inst.kind_of? self if option
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Searches all the modules in the the object space for constants containing
|
66
|
+
# receiver class objects, and names the found instances accordingly. The
|
67
|
+
# number of the remaining nameless instances is returned.
|
68
|
+
#
|
69
|
+
def const_magic
|
70
|
+
puts "#{self}#const_magic invoked!" if ::NameMagic::DEBUG
|
71
|
+
return super if namespace == self
|
72
|
+
puts "self is not namespace, #const_magic delegated to #{namespace}" if ::NameMagic::DEBUG
|
73
|
+
namespace.const_magic
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns the nameless instances. The optional argument has the same meaning
|
77
|
+
# as in +NameMagic::ClassMethods#instances+ method.
|
78
|
+
#
|
79
|
+
def nameless_instances option=true
|
80
|
+
return super if namespace == self
|
81
|
+
ii = namespace.nameless_instances
|
82
|
+
option ? ii.select { |i| i.kind_of? self } : ii
|
83
|
+
end
|
84
|
+
|
85
|
+
# Clears namespace-owned references to a specified instance. (This is
|
86
|
+
# different from "unnaming" an instance by setting <code>inst.name =
|
87
|
+
# nil</code>, which makes the instance anonymous, but still registered.)
|
88
|
+
#
|
89
|
+
def forget instance_identifier, option=true
|
90
|
+
if namespace == self || ! option then super else
|
91
|
+
namespace.forget instance( instance_identifier )
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Clears namespace-owned references to an instance, without performing
|
96
|
+
# #const_magic first. The argument should be a registered instance. Returns
|
97
|
+
# the instance name, or _false_, if there was no such registered instance.
|
98
|
+
#
|
99
|
+
def __forget__( instance, option=true )
|
100
|
+
return super if namespace == self
|
101
|
+
fail NameError, "Supplied argument not an instance of #{self}!" unless
|
102
|
+
instance.is_a? self if option
|
103
|
+
namespace.__forget__ instance
|
104
|
+
end
|
105
|
+
|
106
|
+
# Clears namespace-owned references to all the anonymous instances.
|
107
|
+
#
|
108
|
+
def forget_nameless_instances
|
109
|
+
return super if namespace == self
|
110
|
+
namespace.forget_nameless_instances
|
111
|
+
end
|
112
|
+
|
113
|
+
# Clears namespace-owned references to all the instances.
|
114
|
+
#
|
115
|
+
def forget_all_instances
|
116
|
+
return super if namespace == self
|
117
|
+
namespace.forget_all_instances
|
118
|
+
end
|
119
|
+
|
120
|
+
# Registers a hook to execute upon instantiation. Expects a unary block, whose
|
121
|
+
# argument represents the new instance. It is called right after instantiation,
|
122
|
+
# but before naming the instance.
|
123
|
+
#
|
124
|
+
def new_instance_hook &block
|
125
|
+
return super if namespace == self
|
126
|
+
namespace.new_instance_hook &block
|
127
|
+
end
|
128
|
+
|
129
|
+
# Registers a hook to execute upon instance naming. Expects a ternary block,
|
130
|
+
# with arguments instance, name, old_name, representing respectively the
|
131
|
+
# instance to be named, the requested name, and the previous name of that
|
132
|
+
# instance (if any). The output of the block should be the name to actually
|
133
|
+
# be used. In other words, the hook can be used (among other things) to check
|
134
|
+
# and/or modify the requested name when christening the instance. It is the
|
135
|
+
# responsibility of this block to output a symbol that can be used as a Ruby
|
136
|
+
# constant name.
|
137
|
+
#
|
138
|
+
def name_set_hook &block
|
139
|
+
return super if namespace == self
|
140
|
+
namespace.name_set_hook &block
|
141
|
+
end
|
142
|
+
|
143
|
+
# Registers a hook to execute whenever the instance is asked its name. The
|
144
|
+
# instance names are objects that are kept in a hash referred to by
|
145
|
+
# +@instances+ variable owned by the namespace. Normally, +NameMagic#name+
|
146
|
+
# simply returns the name of the instance, as found in the +@instances+ hash.
|
147
|
+
# When +name_get_hook+ is defined, this name is transformed by it before being
|
148
|
+
# returned.
|
149
|
+
#
|
150
|
+
def name_get_hook &block
|
151
|
+
return super if namespace == self
|
152
|
+
namespace.name_get_hook &block
|
153
|
+
end
|
154
|
+
|
155
|
+
# Sets the namespace of the class.
|
156
|
+
#
|
157
|
+
def namespace= modul
|
158
|
+
puts "Assigning #{modul} as the namespace of #{self}." if ::NameMagic::DEBUG
|
159
|
+
modul.extend ::NameMagic::NamespaceMethods
|
160
|
+
define_singleton_method :namespace do modul end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Sets the namespace for the class to self.
|
164
|
+
#
|
165
|
+
def namespace!
|
166
|
+
nil.tap { self.namespace = self }
|
167
|
+
end
|
168
|
+
|
31
169
|
# In addition the ability to name objects upon constant assignment, as common
|
32
170
|
# with eg. Class instances, NameMagic redefines class method #new so that it
|
33
171
|
# swallows the named argument :name (alias :ɴ), and takes care of naming the
|
@@ -36,23 +174,21 @@ module NameMagic::ClassMethods
|
|
36
174
|
# another object) if set to _true_.
|
37
175
|
#
|
38
176
|
def new *args, &block
|
39
|
-
oo = args[-1].is_a?
|
40
|
-
nm =
|
41
|
-
|
42
|
-
else nil end
|
43
|
-
avid = oo[:name_avid] ? oo.delete( :name_avid ) : false # => true/false
|
177
|
+
oo = if args[-1].is_a? Hash then args.pop else {} end # extract hash
|
178
|
+
nm = oo.delete( :name ) || oo.delete( :ɴ ) # consume :name / :ɴ if given
|
179
|
+
avid = !!oo.delete( :name_avid )
|
44
180
|
# Avoid overwriting existing names unless avid:
|
45
181
|
fail NameError, "#{self} instance #{nm} already exists!" if
|
46
182
|
__instances__.keys.include? nm unless avid
|
47
183
|
args << oo unless oo.empty? # prepare the arguments
|
48
|
-
|
49
|
-
__instances__.update
|
50
|
-
namespace.
|
51
|
-
λ.(
|
52
|
-
if nm then #
|
53
|
-
avid ?
|
54
|
-
else #
|
55
|
-
__avid_instances__ <<
|
184
|
+
super( *args, &block ).tap do |inst| # instantiate
|
185
|
+
__instances__.update( inst => nil ) # Instances are created unnamed...
|
186
|
+
namespace.new_instance_hook.tap { |λ|
|
187
|
+
λ.( inst ) if λ
|
188
|
+
if nm then # Name supplied, name the instance.
|
189
|
+
avid ? inst.name!( nm ) : inst.name = nm
|
190
|
+
else # Name not supplied, make the instance avid.
|
191
|
+
__avid_instances__ << inst
|
56
192
|
end
|
57
193
|
}
|
58
194
|
end
|
@@ -65,4 +201,20 @@ module NameMagic::ClassMethods
|
|
65
201
|
oo = args[-1].is_a?( Hash ) ? args.pop : {} # extract options
|
66
202
|
new *args, oo.update( name_avid: true ), &block
|
67
203
|
end
|
204
|
+
|
205
|
+
private
|
206
|
+
|
207
|
+
# Checks all the constants in some module's namespace, recursively.
|
208
|
+
#
|
209
|
+
def serve_all_modules
|
210
|
+
return super if namespace == self
|
211
|
+
namespace.serve_all_modules
|
212
|
+
end
|
213
|
+
|
214
|
+
# Performs general name validation.
|
215
|
+
#
|
216
|
+
def validate_name name
|
217
|
+
return super if namespace == self
|
218
|
+
namespace.validate_name name
|
219
|
+
end
|
68
220
|
end # module NameMagic::ClassMethods
|
@@ -1,76 +1,52 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
3
|
module NameMagic
|
4
4
|
module NamespaceMethods
|
5
|
-
# Presents
|
6
|
-
# may be overriden to use some other module as a namespace.
|
7
|
-
#
|
8
|
-
def namespace
|
9
|
-
self
|
10
|
-
end
|
11
|
-
|
12
|
-
# Sets the namespace of the class.
|
13
|
-
#
|
14
|
-
def namespace= modul
|
15
|
-
modul.extend ::NameMagic::NamespaceMethods unless modul == self
|
16
|
-
tap { define_singleton_method :namespace do modul end }
|
17
|
-
end
|
18
|
-
|
19
|
-
# Makes the class/module its own namespace. This is useful especially to tell
|
20
|
-
# the subclasses of a class using NameMagic to maintain their own namespaces.
|
21
|
-
#
|
22
|
-
def namespace!
|
23
|
-
nil.tap { self.namespace = self }
|
24
|
-
end
|
25
|
-
|
26
|
-
# Presents the instances registered by the namespace.
|
5
|
+
# Presents the instances registered in this namespace.
|
27
6
|
#
|
28
|
-
def instances
|
7
|
+
def instances *args
|
29
8
|
const_magic
|
30
9
|
__instances__.keys
|
31
10
|
end
|
32
11
|
|
33
|
-
# Presents the instance names
|
34
|
-
# #instances method. Unnamed instances are completely disregarded.
|
12
|
+
# Presents the instance names registered in this namespace.
|
35
13
|
#
|
36
|
-
def instance_names
|
14
|
+
def instance_names *args
|
37
15
|
instances.names( false )
|
38
16
|
end
|
39
17
|
|
40
|
-
# Presents namespace-owned
|
41
|
-
# instance_name }</code>. Unnamed instances have nil
|
42
|
-
# method does not trigger
|
18
|
+
# Presents namespace-owned +@instances+ hash. The hash consists of pairs
|
19
|
+
# <code>{ instance => instance_name }</code>. Unnamed instances have +nil+
|
20
|
+
# assigned to them as their name. (The method does not trigger
|
21
|
+
# +#const_magic+.)
|
43
22
|
#
|
44
|
-
def __instances__
|
45
|
-
|
46
|
-
namespace.instance_variable_set( :@instances, {} )
|
23
|
+
def __instances__ *args
|
24
|
+
@instances ||= {}
|
47
25
|
end
|
48
26
|
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
27
|
+
# Avid instances registered in this namespace. ("Avid" means that the
|
28
|
+
# instance is able to steal (overwrite) a name from another registered
|
29
|
+
# instance. (The method does not trigger +#const_magic+.)
|
52
30
|
#
|
53
|
-
def __avid_instances__
|
54
|
-
|
55
|
-
namespace.instance_variable_set( :@avid_instances, [] )
|
31
|
+
def __avid_instances__ *args
|
32
|
+
@avid_instances ||= []
|
56
33
|
end
|
57
34
|
|
58
|
-
# Returns the instance identified by the argument
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# back without changes.)
|
35
|
+
# Returns the instance identified by the argument, which can be typically
|
36
|
+
# a name (string/symbol). If a registered instance is supplied, it will be
|
37
|
+
# returned unchanged.
|
62
38
|
#
|
63
|
-
def instance
|
64
|
-
puts "#instance( #{identifier} )" if DEBUG
|
39
|
+
def instance id, *args
|
40
|
+
# puts "#instance( #{identifier} )" if DEBUG
|
65
41
|
# In @instances hash, value 'nil' indicates a nameless instance!
|
66
|
-
fail TypeError, "'nil' is not an instance identifier!" if
|
42
|
+
fail TypeError, "'nil' is not an instance identifier!" if id.nil?
|
67
43
|
ii = instances
|
68
|
-
return
|
44
|
+
return id if ii.include? id # return the instance back
|
69
45
|
begin # identifier not a registered instace -- treat it as a name
|
70
|
-
ary = [
|
71
|
-
ii.find
|
46
|
+
ary = [id, id.to_sym]
|
47
|
+
ii.find { |inst| ary.include? inst.name }
|
72
48
|
rescue NoMethodError
|
73
|
-
end or
|
49
|
+
end or fail NameError, "No instance #{id} in #{self}."
|
74
50
|
end
|
75
51
|
|
76
52
|
# Searches all the modules in the the object space for constants containing
|
@@ -78,24 +54,23 @@ module NameMagic
|
|
78
54
|
# number of the remaining nameless instances is returned.
|
79
55
|
#
|
80
56
|
def const_magic
|
57
|
+
puts "#{self}#const_magic invoked!" if ::NameMagic::DEBUG
|
81
58
|
return 0 if nameless_instances.size == 0
|
82
59
|
serve_all_modules
|
83
60
|
return nameless_instances.size
|
84
|
-
end
|
85
|
-
|
61
|
+
end
|
62
|
+
|
86
63
|
# Returns those instances, which are nameless (whose name is set to nil).
|
87
64
|
#
|
88
|
-
def nameless_instances
|
65
|
+
def nameless_instances *args
|
89
66
|
__instances__.select { |key, val| val.nil? }.keys
|
90
67
|
end
|
91
|
-
alias unnamed_instances nameless_instances
|
92
|
-
alias anonymous_instances nameless_instances
|
93
68
|
|
94
69
|
# Clears namespace-owned references to a specified instance. (This is
|
95
70
|
# different from "unnaming" an instance by setting <code>inst.name =
|
96
71
|
# nil</code>, which makes the instance anonymous, but still registered.)
|
97
72
|
#
|
98
|
-
def forget
|
73
|
+
def forget instance_identifier, *args
|
99
74
|
inst = begin
|
100
75
|
instance( instance_identifier )
|
101
76
|
rescue ArgumentError
|
@@ -112,7 +87,7 @@ module NameMagic
|
|
112
87
|
# #const_magic first. The argument should be a registered instance. Returns
|
113
88
|
# the instance name, or _false_, if there was no such registered instance.
|
114
89
|
#
|
115
|
-
def __forget__( instance )
|
90
|
+
def __forget__( instance, *args )
|
116
91
|
return false unless __instances__.keys.include? instance
|
117
92
|
namespace.send :remove_const, instance.name if instance.name
|
118
93
|
__avid_instances__.delete( instance )
|
@@ -127,8 +102,6 @@ module NameMagic
|
|
127
102
|
__avid_instances__.delete inst # also from here
|
128
103
|
}
|
129
104
|
end
|
130
|
-
alias forget_unnamed_instances forget_nameless_instances
|
131
|
-
alias forget_anonymous_instances forget_nameless_instances
|
132
105
|
|
133
106
|
# Clears namespace-owned references to all the instances.
|
134
107
|
#
|
@@ -139,48 +112,50 @@ module NameMagic
|
|
139
112
|
}
|
140
113
|
end
|
141
114
|
|
142
|
-
# Registers a hook to execute
|
143
|
-
# the
|
144
|
-
#
|
145
|
-
# instantiation, but before naming.
|
115
|
+
# Registers a hook to execute upon instantiation. Expects a unary block, whose
|
116
|
+
# argument represents the new instance. It is called right after instantiation,
|
117
|
+
# but before naming the instance.
|
146
118
|
#
|
147
|
-
def
|
148
|
-
|
149
|
-
@
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
#
|
155
|
-
# instance. The block should
|
156
|
-
#
|
157
|
-
#
|
158
|
-
# responsibility of
|
159
|
-
#
|
119
|
+
def new_instance_hook &block
|
120
|
+
@new_instance_hook = block if block
|
121
|
+
@new_instance_hook ||= -> instance { instance }
|
122
|
+
end
|
123
|
+
|
124
|
+
# Registers a hook to execute upon instance naming. Expects a ternary block,
|
125
|
+
# with arguments instance, name, old_name, representing respectively the
|
126
|
+
# instance to be named, the requested name, and the previous name of that
|
127
|
+
# instance (if any). The output of the block should be the name to actually
|
128
|
+
# be used. In other words, the hook can be used (among other things) to check
|
129
|
+
# and/or modify the requested name when christening the instance. It is the
|
130
|
+
# responsibility of this block to output a symbol that can be used as a Ruby
|
131
|
+
# constant name.
|
160
132
|
#
|
161
|
-
def
|
162
|
-
|
163
|
-
@
|
164
|
-
@name_set_closure ||= -> name, instance, old_name=nil { name }
|
133
|
+
def name_set_hook &block
|
134
|
+
@name_set_hook = block if block
|
135
|
+
@name_set_hook ||= -> name, instance, old_name=nil { name }
|
165
136
|
end
|
166
|
-
alias name_set_hook name_set_closure
|
167
137
|
|
168
|
-
# Registers a hook to execute whenever the instance is asked
|
169
|
-
#
|
170
|
-
#
|
138
|
+
# Registers a hook to execute whenever the instance is asked its name. The
|
139
|
+
# instance names are objects that are kept in a hash referred to by
|
140
|
+
# +@instances+ variable owned by the namespace. Normally, +NameMagic#name+
|
141
|
+
# simply returns the name of the instance, as found in the +@instances+ hash.
|
142
|
+
# When +name_get_hook+ is defined, this name is transformed by it before being
|
143
|
+
# returned.
|
171
144
|
#
|
172
|
-
def
|
173
|
-
|
174
|
-
@
|
175
|
-
@name_get_closure ||= -> name { name }
|
145
|
+
def name_get_hook &block
|
146
|
+
@name_get_hook = block if block
|
147
|
+
@name_get_hook ||= -> name { name }
|
176
148
|
end
|
177
|
-
alias name_get_hook name_get_closure
|
178
149
|
|
179
150
|
private
|
180
151
|
|
181
152
|
# Checks all the constants in some module's namespace, recursively.
|
182
153
|
#
|
183
154
|
def serve_all_modules
|
155
|
+
if DEBUG then
|
156
|
+
puts "#{self}#serve_all_modules invoked!"
|
157
|
+
if name.nil? then puts "(ancestors: #{ancestors.take( 4 ).join ', '}" end
|
158
|
+
end
|
184
159
|
todo = ( nameless_instances + __avid_instances__ ).map( &:object_id ).uniq
|
185
160
|
ObjectSpace.each_object Module do |ɱ|
|
186
161
|
ɱ.constants( false ).each do |const_ß|
|
@@ -189,21 +164,19 @@ module NameMagic
|
|
189
164
|
rescue LoadError, StandardError; next end
|
190
165
|
next unless todo.include? ◉.object_id
|
191
166
|
puts "NameMagic: Anonymous object under #{const_ß}!" if DEBUG
|
192
|
-
if
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
else puts "NameMagic: It is not avid." if DEBUG # not avid
|
198
|
-
ɴ = validate_name( name_set_closure.( const_ß, ◉, nil ) ).to_sym
|
167
|
+
if ◉.avid? then puts "NameMagic: It is avid." if DEBUG
|
168
|
+
◉.make_not_avid! # 1. Remove it from the list of avid instances.
|
169
|
+
◉.name! const_ß # 2. Name it rudely.
|
170
|
+
else puts "NameMagic: It is not avid." if DEBUG
|
171
|
+
ɴ = validate_name( name_set_hook.( const_ß, ◉, nil ) ).to_sym
|
199
172
|
puts "NameMagic: Name adjusted to #{ɴ}." if DEBUG
|
200
|
-
conflicter = begin;
|
173
|
+
conflicter = begin; const_get( ɴ ); rescue NameError; end
|
201
174
|
if conflicter then
|
202
175
|
msg = "Another #{self}-registered instance named '#{ɴ}' exists!"
|
203
176
|
fail NameError, msg unless conflicter == ◉
|
204
177
|
else # add the instance to the namespace
|
205
178
|
__instances__.update( ◉ => ɴ )
|
206
|
-
|
179
|
+
const_set( ɴ, ◉ )
|
207
180
|
end
|
208
181
|
end
|
209
182
|
todo.delete ◉.object_id # remove the id from todo list
|
data/lib/y_support/name_magic.rb
CHANGED
@@ -71,25 +71,22 @@ require_relative 'name_magic/class_methods'
|
|
71
71
|
module NameMagic
|
72
72
|
DEBUG = false
|
73
73
|
|
74
|
-
def self.included
|
75
|
-
if
|
76
|
-
class <<
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
modul.define_singleton_method :namespace do modul end
|
85
|
-
else
|
86
|
-
modul.namespace.extend NameMagic::NamespaceMethods
|
74
|
+
def self.included target
|
75
|
+
if target.is_a? Class then # decorate #new
|
76
|
+
class << target
|
77
|
+
# Primer that sets the namespace of the class to self if the user has
|
78
|
+
# not defined otherwise when this method is first called.
|
79
|
+
#
|
80
|
+
def namespace
|
81
|
+
extend ::NameMagic::NamespaceMethods
|
82
|
+
define_singleton_method :namespace do self end # redefines itself
|
83
|
+
namespace
|
87
84
|
end
|
88
|
-
rescue NoMethodError
|
89
85
|
end
|
86
|
+
target.singleton_class.class_exec { prepend NameMagic::ClassMethods }
|
90
87
|
else # it is a Module -- infect it with this #include
|
91
|
-
orig, this =
|
92
|
-
|
88
|
+
orig, this = target.method( :included ), method( :included )
|
89
|
+
target.define_singleton_method :included do |m| this.( m ); orig.( m ) end
|
93
90
|
end
|
94
91
|
end # self.included
|
95
92
|
|
@@ -111,24 +108,24 @@ module NameMagic
|
|
111
108
|
#
|
112
109
|
def __name__
|
113
110
|
ɴ = self.class.__instances__[ self ]
|
114
|
-
namespace.
|
111
|
+
namespace.name_get_hook.( ɴ ) if ɴ
|
115
112
|
end
|
116
113
|
|
117
114
|
# Names an instance, cautiously (ie. no overwriting of existing names).
|
118
115
|
#
|
119
116
|
def name=( ɴ )
|
120
117
|
old_ɴ = namespace.__instances__[ self ] # previous name
|
121
|
-
if ɴ then puts "NameMagic: Naming with argument #{ɴ}." if DEBUG
|
122
|
-
ɴ = namespace.send( :validate_name,
|
123
|
-
namespace.
|
124
|
-
puts "NameMagic: Name adjusted to #{ɴ}." if DEBUG
|
118
|
+
if ɴ then # puts "NameMagic: Naming with argument #{ɴ}." if DEBUG
|
119
|
+
ɴ = namespace.send( :validate_name, # honor the hook
|
120
|
+
namespace.name_set_hook.( ɴ, self, old_ɴ ) ).to_sym
|
121
|
+
# puts "NameMagic: Name adjusted to #{ɴ}." if DEBUG
|
125
122
|
return if old_ɴ == ɴ # already named as required
|
126
123
|
fail NameError, "Name '#{ɴ}' already exists in #{namespace} namespace!" if
|
127
124
|
self.class.__instances__.rassoc( ɴ )
|
128
125
|
namespace.const_set ɴ, self # write a constant
|
129
126
|
namespace.__instances__[ self ] = ɴ # write to @instances
|
130
127
|
namespace.__forget__ old_ɴ # forget the old name of self
|
131
|
-
else puts "NameMagic: Unnaming #{old_ɴ || self}" if DEBUG
|
128
|
+
else # puts "NameMagic: Unnaming #{old_ɴ || self}" if DEBUG
|
132
129
|
namespace.__instances__.update( self => nil ) # unname in @instances
|
133
130
|
namespace.send :remove_const, old_ɴ if old_ɴ # remove namespace const.
|
134
131
|
end
|
@@ -138,10 +135,10 @@ module NameMagic
|
|
138
135
|
#
|
139
136
|
def name!( ɴ )
|
140
137
|
old_ɴ = namespace.__instances__[ self ] # previous name
|
141
|
-
if ɴ then puts "NameMagic: Rudely naming with #{ɴ}." if DEBUG
|
138
|
+
if ɴ then # puts "NameMagic: Rudely naming with #{ɴ}." if DEBUG
|
142
139
|
ɴ = namespace.send( :validate_name, # honor the hook
|
143
|
-
namespace.
|
144
|
-
puts "NameMagic: Name adjusted to #{ɴ}." if DEBUG
|
140
|
+
namespace.name_set_hook.( ɴ, self, old_ɴ ) ).to_sym
|
141
|
+
# puts "NameMagic: Name adjusted to #{ɴ}." if DEBUG
|
145
142
|
return false if old_ɴ == ɴ # already named as required
|
146
143
|
pair = namespace.__instances__.rassoc( ɴ )
|
147
144
|
namespace.__forget__( pair[0] ) if pair # rudely forget the collider
|
@@ -152,4 +149,16 @@ module NameMagic
|
|
152
149
|
self.name = nil # unnaming, no collider issues
|
153
150
|
end
|
154
151
|
end
|
152
|
+
|
153
|
+
# Is the instance avid for a name? (Will it overwrite other instance names?)
|
154
|
+
#
|
155
|
+
def avid?
|
156
|
+
namespace.__avid_instances__.any? &method( :equal? )
|
157
|
+
end
|
158
|
+
|
159
|
+
# Make the instance not avid.
|
160
|
+
#
|
161
|
+
def make_not_avid!
|
162
|
+
namespace.__avid_instances__.delete_if { |i| i.object_id == object_id }
|
163
|
+
end
|
155
164
|
end # module NameMagic
|
data/lib/y_support/version.rb
CHANGED
data/test/name_magic_test.rb
CHANGED
@@ -11,18 +11,20 @@ describe NameMagic do
|
|
11
11
|
@reporter = Object.new
|
12
12
|
puts "..."
|
13
13
|
@reporter.singleton_class.class_exec { attr_reader :report, :naming }
|
14
|
-
@ç.
|
14
|
+
@ç.ancestors.must_include NameMagic
|
15
|
+
@ç.singleton_class.ancestors.must_include NameMagic::ClassMethods
|
16
|
+
@ç.namespace.new_instance_hook do |instance|
|
15
17
|
@reporter.define_singleton_method :report do "Instance reported" end
|
16
18
|
end
|
17
|
-
@ç.namespace.
|
19
|
+
@ç.namespace.name_set_hook do |name, instance, old_name|
|
18
20
|
@reporter.define_singleton_method :name_set do
|
19
21
|
"Name of the new instance was #{name}"
|
20
22
|
end
|
21
23
|
name
|
22
24
|
end
|
23
|
-
@ç.
|
25
|
+
@ç.name_get_hook do |name_object|
|
24
26
|
@reporter.define_singleton_method :name_get do
|
25
|
-
"Name get
|
27
|
+
"Name get hook called on #{name_object}"
|
26
28
|
end
|
27
29
|
name_object
|
28
30
|
end
|
@@ -37,7 +39,7 @@ describe NameMagic do
|
|
37
39
|
@reporter.report.must_equal "Instance reported"
|
38
40
|
@reporter.name_set.must_equal "Name of the new instance was Boris"
|
39
41
|
x.name.must_equal :Boris
|
40
|
-
@reporter.name_get.must_equal "Name get
|
42
|
+
@reporter.name_get.must_equal "Name get hook called on Boris"
|
41
43
|
ufo = @ç.new
|
42
44
|
@ç.nameless_instances.must_equal [ufo]
|
43
45
|
UFO = @ç.new
|
@@ -45,17 +47,21 @@ describe NameMagic do
|
|
45
47
|
@reporter.name_set.must_equal "Name of the new instance was Boris"
|
46
48
|
UFO.name
|
47
49
|
@reporter.name_set.must_equal "Name of the new instance was UFO"
|
48
|
-
@reporter.name_get.must_equal "Name get
|
50
|
+
@reporter.name_get.must_equal "Name get hook called on UFO"
|
49
51
|
Elaine = @ç.new
|
50
52
|
Elaine.name.must_equal :Elaine
|
51
53
|
m = Module.new
|
52
54
|
XXX = m
|
53
55
|
@ç.namespace = XXX
|
54
56
|
@ç.namespace.must_equal m
|
57
|
+
@ç.singleton_class.must_include ::NameMagic::ClassMethods
|
58
|
+
m.singleton_class.must_include ::NameMagic::NamespaceMethods
|
55
59
|
Rover = @ç.new
|
60
|
+
@ç.namespace.must_equal XXX
|
61
|
+
@ç.nameless_instances.must_equal [ Rover ]
|
56
62
|
@ç.const_magic
|
57
|
-
XXX::Rover.must_be_kind_of @ç
|
58
63
|
Rover.name.must_equal :Rover
|
64
|
+
XXX::Rover.must_be_kind_of @ç
|
59
65
|
@ç.namespace!
|
60
66
|
Spot = @ç.new
|
61
67
|
@ç.const_magic
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: y_support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- boris
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|