y_support 2.0.43 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|