y_support 2.1.18 → 2.4.4
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/all.rb +2 -32
- data/lib/y_support/core_ext/array.rb +2 -2
- data/lib/y_support/core_ext/class.rb +2 -2
- data/lib/y_support/core_ext/enumerable.rb +2 -2
- data/lib/y_support/core_ext/hash/misc.rb +23 -10
- data/lib/y_support/core_ext/hash.rb +2 -2
- data/lib/y_support/core_ext/module/misc.rb +9 -0
- data/lib/y_support/core_ext/module.rb +2 -2
- data/lib/y_support/core_ext/numeric.rb +2 -2
- data/lib/y_support/core_ext/object/inspection.rb +8 -2
- data/lib/y_support/core_ext/object.rb +3 -3
- data/lib/y_support/core_ext/string/misc.rb +9 -12
- data/lib/y_support/core_ext/string.rb +2 -2
- data/lib/y_support/core_ext/symbol.rb +2 -2
- data/lib/y_support/core_ext.rb +1 -1
- data/lib/y_support/flex_coerce/class_methods.rb +49 -0
- data/lib/y_support/flex_coerce/flex_proxy.rb +121 -0
- data/lib/y_support/flex_coerce/module_methods.rb +37 -0
- data/lib/y_support/flex_coerce.rb +24 -0
- data/lib/y_support/kde.rb +1 -1
- data/lib/y_support/literate.rb +253 -0
- data/lib/y_support/local_object.rb +1 -1
- data/lib/y_support/name_magic/array_methods.rb +48 -0
- data/lib/y_support/name_magic/class_methods.rb +205 -161
- data/lib/y_support/name_magic/hash_methods.rb +33 -0
- data/lib/y_support/name_magic/namespace.rb +449 -0
- data/lib/y_support/name_magic.rb +358 -100
- data/lib/y_support/null_object.rb +1 -1
- data/lib/y_support/respond_to.rb +1 -1
- data/lib/y_support/stdlib_ext/matrix/misc.rb +2 -2
- data/lib/y_support/stdlib_ext/matrix.rb +2 -2
- data/lib/y_support/stdlib_ext.rb +1 -1
- data/lib/y_support/typing/array.rb +1 -1
- data/lib/y_support/typing/enumerable.rb +1 -1
- data/lib/y_support/typing/hash.rb +1 -1
- data/lib/y_support/typing/module.rb +1 -1
- data/lib/y_support/typing/object/typing.rb +17 -15
- data/lib/y_support/typing/object.rb +1 -1
- data/lib/y_support/typing.rb +14 -10
- data/lib/y_support/unicode.rb +1 -1
- data/lib/y_support/version.rb +1 -1
- data/lib/y_support/x.rb +2 -1
- data/test/flex_coerce_test.rb +134 -0
- data/test/literate_test.rb +231 -0
- data/test/misc_test.rb +49 -27
- data/test/name_magic_test.rb +907 -60
- data/test/typing_test.rb +7 -7
- metadata +14 -13
- data/lib/y_support/abstract_algebra.rb +0 -234
- data/lib/y_support/name_magic/array.rb +0 -38
- data/lib/y_support/name_magic/hash.rb +0 -31
- data/lib/y_support/name_magic/namespace_methods.rb +0 -260
- data/lib/y_support/try.rb +0 -133
- data/test/abstract_algebra_test.rb +0 -138
- data/test/performance_test_example.rb +0 -23
- data/test/try_test.rb +0 -102
@@ -3,210 +3,254 @@
|
|
3
3
|
# Class methods for the classes that include NameMagic.
|
4
4
|
#
|
5
5
|
module NameMagic::ClassMethods
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# those instances registered by the namespace, which are of exactly the
|
10
|
-
# same class as the receiver (ie. excluding the instances of the subclasses
|
11
|
-
# of this class). Example:
|
6
|
+
# Delegates methods to the namespace used by the class. Since the
|
7
|
+
# class frequently acts as its own namespace, this delegation
|
8
|
+
# requires special handling.
|
12
9
|
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# Dog.instances( false ) #=> 2 instances again (all the animals)
|
21
|
-
# </code>
|
22
|
-
#
|
23
|
-
def instances option=true
|
24
|
-
return super if namespace == self
|
25
|
-
ii = namespace.instances
|
26
|
-
option ? ii.select { |i| i.kind_of? self } : ii
|
10
|
+
def self.delegate_to_namespace *symbols
|
11
|
+
symbols.each { |ß|
|
12
|
+
module_eval "def #{ß} *args\n" +
|
13
|
+
" return super if namespace == self\n" +
|
14
|
+
" namespace.#{ß}( *args )\n" +
|
15
|
+
"end"
|
16
|
+
}
|
27
17
|
end
|
28
18
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
19
|
+
delegate_to_namespace :permanent_names!
|
20
|
+
delegate_to_namespace :permanent_names?
|
21
|
+
delegate_to_namespace :__instances__
|
22
|
+
delegate_to_namespace :__avid_instances__
|
23
|
+
delegate_to_namespace :const_magic
|
24
|
+
delegate_to_namespace :validate_name
|
25
|
+
delegate_to_namespace :forget_nameless_instances
|
26
|
+
delegate_to_namespace :instantiation_exec
|
27
|
+
delegate_to_namespace :exec_when_naming
|
28
|
+
delegate_to_namespace :exec_when_unnaming
|
37
29
|
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
# +#const_magic+.)
|
42
|
-
#
|
43
|
-
def __instances__
|
44
|
-
namespace == self ? super : namespace.__instances__
|
45
|
-
end
|
30
|
+
# Note: These aliases must stay while the dependencies need them.
|
31
|
+
alias new_instance_hook instantiation_exec
|
32
|
+
alias name_set_hook exec_when_naming
|
46
33
|
|
47
|
-
#
|
48
|
-
# means that the instance is able to overwrite a name used by another
|
49
|
-
# registered instance. (This method does not trigger +#const_magic+.)
|
34
|
+
# Sets the namespace for the class.
|
50
35
|
#
|
51
|
-
def
|
52
|
-
|
36
|
+
def namespace= modul
|
37
|
+
fail "Namespace cannot be redefined when instance registry " +
|
38
|
+
"is not empty!" unless instances.empty?
|
39
|
+
modul.extend ::NameMagic::Namespace
|
40
|
+
define_singleton_method :namespace do modul end
|
53
41
|
end
|
54
42
|
|
55
|
-
#
|
56
|
-
# be a name (string/symbol). If a registered instance is supplied, it is
|
57
|
-
# returned without change. The second argument is optional, with the same
|
58
|
-
# meaning as in +NameMagic::ClassMethods#instances+ method.
|
43
|
+
# Sets the namespace for the class to self.
|
59
44
|
#
|
60
|
-
def
|
61
|
-
|
62
|
-
return namespace.instance( instance ) unless option
|
63
|
-
namespace.instance( instance ).tap { |instance|
|
64
|
-
fail NameError, "No #{self} instance #{instance} registered in " +
|
65
|
-
"#{namespace}!" unless instance.kind_of? self
|
66
|
-
}
|
45
|
+
def namespace!
|
46
|
+
nil.tap { self.namespace = self }
|
67
47
|
end
|
68
48
|
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
49
|
+
# Returns the registered instances. Example:
|
50
|
+
#
|
51
|
+
# <code>
|
52
|
+
# class Animal; include NameMagic end
|
53
|
+
# Cat, Dog = Class.new( Animal ), Class.new( Animal )
|
54
|
+
# Spot, Livia = Dog.new, Cat.new
|
55
|
+
# Animal.instances #=> [Spot, Livia]
|
56
|
+
# Dog.instances #=> [Spot]
|
57
|
+
# Cat.instances #=> [Livia]
|
58
|
+
# </code>
|
72
59
|
#
|
73
|
-
def
|
74
|
-
namespace == self
|
60
|
+
def instances
|
61
|
+
return super if namespace == self
|
62
|
+
namespace.instances.select { |i| i.kind_of? self }
|
75
63
|
end
|
76
64
|
|
77
|
-
# Returns the
|
78
|
-
# as in +NameMagic::ClassMethods#instances+ method.
|
65
|
+
# Returns the instance identified by the first argument.
|
79
66
|
#
|
80
|
-
def
|
67
|
+
def instance instance
|
81
68
|
return super if namespace == self
|
82
|
-
|
83
|
-
|
69
|
+
namespace.instance( instance ).tap do |i|
|
70
|
+
fail NameError, "No #{self} instance #{instance} " +
|
71
|
+
"registered in #{namespace}!" unless i.kind_of? self
|
72
|
+
end
|
84
73
|
end
|
85
74
|
|
86
|
-
#
|
87
|
-
# different from de-naming an instance by setting <code>inst.name =
|
88
|
-
# nil</code>, which makes the instance anonymous, but still registered.)
|
75
|
+
# Returns those of the registered instances, which are nameless.
|
89
76
|
#
|
90
|
-
def
|
91
|
-
|
77
|
+
def nameless_instances
|
78
|
+
return super if namespace == self
|
79
|
+
__instances__
|
80
|
+
.select { |key, val| val.nil? and key.is_a? self }
|
81
|
+
.keys
|
92
82
|
end
|
93
83
|
|
94
|
-
# Clears namespace-owned references to
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
# argument has the same meaning as in +NameMaic::ClassMethods#instances+.
|
84
|
+
# Clears namespace-owned references to the specified
|
85
|
+
# instance. (This is different from de-naming an instance by
|
86
|
+
# setting <code>inst.name = nil</code>, which makes the instance
|
87
|
+
# anonymous, but still registered.)
|
99
88
|
#
|
100
|
-
def
|
89
|
+
def forget instance
|
101
90
|
return super if namespace == self
|
102
|
-
|
103
|
-
instance.is_a? self if option
|
104
|
-
namespace.__forget__ instance
|
91
|
+
namespace.forget( instance instance )
|
105
92
|
end
|
106
93
|
|
107
|
-
#
|
94
|
+
# De-registers an instance without performing #const_magic
|
95
|
+
# first. The argument must be a registered instance, or TypeError
|
96
|
+
# ensues. Returns instance name for forgotten named instances,
|
97
|
+
# _nil_ for forgotten nameless instances.
|
108
98
|
#
|
109
|
-
def
|
110
|
-
|
99
|
+
def __forget__ instance
|
100
|
+
fail TypeError, "Supplied argument is not an instance " +
|
101
|
+
"of #{self}!" unless instance.is_a? self
|
102
|
+
return super if namespace == self
|
103
|
+
namespace.__forget__ instance
|
111
104
|
end
|
112
105
|
|
113
|
-
# Clears
|
106
|
+
# Clears references to all the instances.
|
114
107
|
#
|
115
108
|
def forget_all_instances
|
116
|
-
namespace == self
|
109
|
+
return super if namespace == self
|
110
|
+
instances.map { |instance| __forget__ instance }
|
117
111
|
end
|
118
112
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
113
|
+
# In addition to the ability to name objects by constant
|
114
|
+
# assignment it provides, +NameMagic+ modifies #new method so
|
115
|
+
# that it will swallow certain parameters, namely +:name+ (alias
|
116
|
+
# +:ɴ+), +:name!+ and +:avid+. These can be used to name
|
117
|
+
# instances right off the bat with #new constructor:
|
118
|
+
#
|
119
|
+
# Human = Class.new do include NameMagic end
|
120
|
+
# Human.new name: "Fred"
|
121
|
+
# Human.instances #=> [Fred]
|
122
122
|
#
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
# be used. In other words, the hook can be used (among other things) to check
|
132
|
-
# and/or modify the requested name when christening the instance. It is the
|
133
|
-
# responsibility of this block to output a symbol that can be used as a Ruby
|
134
|
-
# constant name.
|
123
|
+
# Option +:avid+ (_true_ or _false_), when set to _true_, makes
|
124
|
+
# the instance so eager to be named that it will overwrite
|
125
|
+
# (steal) names already given to other instances. This allows us
|
126
|
+
# to redefine names to which we have already assigned something
|
127
|
+
# else.
|
128
|
+
#
|
129
|
+
# Finally, parameter +:name!+ acts as +:name+ with +:avid+ set to
|
130
|
+
# _true_:
|
135
131
|
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
# When +name_get_hook+ is defined, this name is transformed by it before being
|
145
|
-
# returned.
|
132
|
+
# instance_1 = Human.new name: "Joe"
|
133
|
+
# instance_1.name #=> :Joe
|
134
|
+
# Human.instance( :Joe ) == instance_1 #=> true
|
135
|
+
# instance_2 = Human.new name!: "Joe"
|
136
|
+
# instance_2.name #=> :Joe
|
137
|
+
# instance_1.name #=> nil
|
138
|
+
# Human.instance( :Joe ) == instance_1 #=> false
|
139
|
+
# Human.instance( :Joe ) == instance_2 #=> true
|
146
140
|
#
|
147
|
-
def
|
148
|
-
|
141
|
+
def new *args, &block
|
142
|
+
# Extract hash from args.
|
143
|
+
oo = if args.last.is_a? Hash then args.pop else {} end
|
144
|
+
# Swallow :name / :ɴ parameters.
|
145
|
+
requested_name = oo.delete( :name ) || oo.delete( :ɴ )
|
146
|
+
# Swallow :name! parameter.
|
147
|
+
if oo[ :name! ] then
|
148
|
+
fail ArgumentError, "Parameters :name! and :name (:ɴ) " +
|
149
|
+
"cannot be supplied both at once!" if requested_name
|
150
|
+
requested_name = oo.delete( :name! )
|
151
|
+
exclamation_mark = true
|
152
|
+
else
|
153
|
+
exclamation_mark = false
|
154
|
+
end
|
155
|
+
# Prepare the arguments for instantiation.
|
156
|
+
args << oo unless oo.empty?
|
157
|
+
# Instantiate.
|
158
|
+
instance = super *args, &block
|
159
|
+
# Instantiation contract specifies that instances are created
|
160
|
+
# unnamed. Thus, register the instance and set its name to nil.
|
161
|
+
__instances__.update( instance => nil )
|
162
|
+
# Instantiation contract specifies that instances are created
|
163
|
+
# avid. Thus, make the instance avid.
|
164
|
+
instance.send :make_avid!
|
165
|
+
# Now, we have prepared the new instance nameless and avid
|
166
|
+
# exactly according to the instantiation contract. Depending on
|
167
|
+
# the arguments supplied to this method, the instance may soon
|
168
|
+
# lose its avid state and get a name, but now, before any of
|
169
|
+
# that happens, is the time to honor .instantiation_exec hook.
|
170
|
+
honor_instantiation_exec( instance )
|
171
|
+
# Return the instance if no name was requested for it.
|
172
|
+
return instance unless requested_name
|
173
|
+
# Now we know that a name was requested. The necessary action
|
174
|
+
# depends on whether :name (:ɴ) or :name! parameter was used.
|
175
|
+
# But already now, we know that the instance no longer needs
|
176
|
+
# to be avid.
|
177
|
+
instance.make_not_avid!
|
178
|
+
# Depending on whether :name (:ɴ) or :name! was supplied...
|
179
|
+
if exclamation_mark then
|
180
|
+
# Name the instance aggresively.
|
181
|
+
instance.name! requested_name
|
182
|
+
else
|
183
|
+
# Name the instance only if the name is not already in use.
|
184
|
+
instance.name = requested_name
|
185
|
+
end
|
186
|
+
# Return the instance.
|
187
|
+
return instance
|
149
188
|
end
|
150
189
|
|
151
|
-
|
152
|
-
#
|
153
|
-
def namespace= modul
|
154
|
-
puts "Assigning #{modul} as the namespace of #{self}." if ::NameMagic::DEBUG
|
155
|
-
modul.extend ::NameMagic::NamespaceMethods
|
156
|
-
define_singleton_method :namespace do modul end
|
157
|
-
end
|
190
|
+
private
|
158
191
|
|
159
|
-
#
|
192
|
+
# Honors class'es hook .instantiation_exec. Takes one argument,
|
193
|
+
# the newly constructed instance.
|
160
194
|
#
|
161
|
-
def
|
162
|
-
|
195
|
+
def honor_instantiation_exec( instance )
|
196
|
+
# Method #instantiation_exec, when called without a block,
|
197
|
+
# returns the block defined earlier.
|
198
|
+
block = instantiation_exec
|
199
|
+
# Block is executed within the context of this class.
|
200
|
+
instance_exec instance, &block
|
201
|
+
# The method returns nil.
|
202
|
+
return nil
|
163
203
|
end
|
164
204
|
|
165
|
-
#
|
166
|
-
# redefines #new method so as to swallow name argument +:name+ (alias :ɴ), and
|
167
|
-
# naming the constructed instance by it. Also, +:name_avid+ option may be
|
168
|
-
# supplied, which, if _true_, makes the instance capable of avid naming:
|
169
|
-
# Overwriting (stealing) a name already given to another instance.
|
170
|
-
#
|
171
|
-
def new *args, &block
|
172
|
-
oo = if args[-1].is_a? Hash then args.pop else {} end # extract hash
|
173
|
-
nm = oo.delete( :name ) || oo.delete( :ɴ ) # consume :name / :ɴ if given
|
174
|
-
avid = oo.delete( :name_avid )
|
175
|
-
# Avoid overwriting existing names unless avid:
|
176
|
-
fail NameError, "#{self} instance #{nm} already exists!" if
|
177
|
-
__instances__.keys.include? nm unless avid
|
178
|
-
args << oo unless oo.empty? # prepare the arguments
|
179
|
-
super( *args, &block ).tap do |inst| # instantiate
|
180
|
-
__instances__.update( inst => nil ) # Instances are created unnamed...
|
181
|
-
namespace.new_instance_hook.tap { |λ|
|
182
|
-
λ.( inst ) if λ
|
183
|
-
if nm then # Name supplied, name the instance.
|
184
|
-
avid ? inst.name!( nm ) : inst.name = nm
|
185
|
-
else # Name not given, make the inst. avid unless expressly prohibited.
|
186
|
-
__avid_instances__ << inst unless avid == false
|
187
|
-
end
|
188
|
-
}
|
189
|
-
end
|
190
|
-
end
|
205
|
+
# Backup of the #new method internals.
|
191
206
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
207
|
+
# # Extract hash from args.
|
208
|
+
# oo = if args.last.is_a? Hash then args.pop else {} end
|
209
|
+
# # Swallow :name / :ɴ parameters.
|
210
|
+
# requested_name = oo.delete( :name ) || oo.delete( :ɴ )
|
211
|
+
# # Swallow :name! parameter.
|
212
|
+
# if oo[ :name! ] then
|
213
|
+
# fail ArgumentError, "Parameters :name! and :name (:ɴ) " +
|
214
|
+
# "cannot be supplied both at once!" if requested_name
|
215
|
+
# fail ArgumentError, "When parameter :name! is used, :avid " +
|
216
|
+
# "must not be used!" if oo.keys.include? :avid
|
217
|
+
# requested_name = oo.delete( :name! )
|
218
|
+
# avid = true
|
219
|
+
# else
|
220
|
+
# # Swallow :avid parameter.
|
221
|
+
# avid = oo.delete( :avid )
|
222
|
+
# end
|
223
|
+
# # I think this is a program error. The construct below never
|
224
|
+
# # executes, since in the first place it searches names in the
|
225
|
+
# # array of instances.
|
226
|
+
# #
|
227
|
+
# # # Avoid overwriting existing names unless avid:
|
228
|
+
# # fail NameError, "#{self} instance named #{requested_name} " +
|
229
|
+
# # "already exists!" if __instances__.keys.include? nm unless avid
|
230
|
+
# # Prepare the arguments for instantiation.
|
231
|
+
# args << oo unless oo.empty?
|
232
|
+
# # Instantiate.
|
233
|
+
# new_instance = super *args, &block
|
234
|
+
# # Instance construction contract specifies that the instances
|
235
|
+
# # are created unnamed. Thus, enter the instance into the
|
236
|
+
# # registry and set its name to nil.
|
237
|
+
# __instances__.update( instance => nil )
|
238
|
+
# # Instance construction contract specifies that the instances
|
239
|
+
# # are created avid Make the instance avid.
|
240
|
+
|
241
|
+
# # Honor the #instantiation_exec hook.
|
242
|
+
# honor_instantiation_exec( instance )
|
198
243
|
|
199
|
-
# Performs general name validation.
|
200
|
-
#
|
201
|
-
def validate_name name
|
202
|
-
namespace == self ? super : namespace.validate_name( name )
|
203
|
-
end
|
204
244
|
|
205
|
-
|
245
|
+
# # Name the instance if name has been given.
|
246
|
+
# if nm then
|
247
|
+
# # If name has been supplied, name the instance.
|
248
|
+
# avid ? instance.name!( nm ) : instance.name = nm
|
249
|
+
# else # Name has not been given.
|
250
|
+
# # Make the instance avid unless expressly prohibited.
|
251
|
+
# __avid_instances__ << instance unless avid == false
|
252
|
+
# end
|
206
253
|
|
207
|
-
|
208
|
-
|
209
|
-
def serve_all_modules
|
210
|
-
namespace == self ? super : namespace.serve_all_modules
|
211
|
-
end
|
254
|
+
# # Return the constructed instance.
|
255
|
+
# return new_instance
|
212
256
|
end # module NameMagic::ClassMethods
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module NameMagic::HashMethods
|
4
|
+
# Maps the hash into one whose keys have been replaced with full
|
5
|
+
# names of the keys (using #full_name method).
|
6
|
+
#
|
7
|
+
def keys_to_names # FIXME: Change to #keys_to_full_names
|
8
|
+
with_keys do |key| key.name || key end
|
9
|
+
# FIXME: Change #name to #full_name
|
10
|
+
end
|
11
|
+
|
12
|
+
# Modifies a hash in place so that the keys are replaced with key
|
13
|
+
# names (key objects are assumed to respond to +#name+ method).
|
14
|
+
#
|
15
|
+
def keys_to_names! # FIXME: Change to #keys_to_full_names!
|
16
|
+
with_keys! do |key| key.name || key end
|
17
|
+
# FIXME: Change #name to #full_name
|
18
|
+
end
|
19
|
+
|
20
|
+
# Maps the hash into one whose keys have been replaced with
|
21
|
+
# names of the key objects (using #_name_ method).
|
22
|
+
#
|
23
|
+
def keys_to_ɴ
|
24
|
+
with_keys do |key| key._name_ || key end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Modifies a hash in place so that the keys are replaced with key
|
28
|
+
# names (using +#_name_+ method).
|
29
|
+
#
|
30
|
+
def keys_to_ɴ!
|
31
|
+
with_keys! do |key| key._name_ || key end
|
32
|
+
end
|
33
|
+
end
|