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
@@ -1,260 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
# Module methods for the modules serving as +NameMagic+ namespaces. A namespace
|
4
|
-
# for a certain class featuring +NameMagic+ holds "civil registry" of all its
|
5
|
-
# instances, be they named or nameless. For this purpose, the namespace owns
|
6
|
-
# +@instances+ hash of pairs <tt>{ instance => name }</tt>, with _nil_ values
|
7
|
-
# denoting nameless instances. For named instances, the namespace also holds
|
8
|
-
# references to them in constants in the style <tt>Namespace::Name</tt>. This
|
9
|
-
# is one of the reasons why instance names in +NameMagic+ must start with
|
10
|
-
# a capital letter and generally must be usable as constant names. The list of
|
11
|
-
# instances is accessible via +#instances+ method. Individual instances can be
|
12
|
-
# queried by +#instance+ method, eg. by their names.
|
13
|
-
#
|
14
|
-
# === Life cycle of instances of classes featuring +NameMagic+
|
15
|
-
#
|
16
|
-
# +NameMagic+ offers 3 hooks for the instances of its user classes. These hooks
|
17
|
-
# are closures invoked at the relevant points of the instances' life cycle:
|
18
|
-
#
|
19
|
-
# * new instance hook -- when the instance is created
|
20
|
-
# * name set hook -- when the instance is offered a name
|
21
|
-
# * name get hook -- when the instance's name is queried
|
22
|
-
#
|
23
|
-
# These three hooks are stored in instance variables owned by the namespace,
|
24
|
-
# accesible by methods +#new_instance_hook, +#name_set_hook+ and
|
25
|
-
# +#name_get_hook+. If called with a block, these methods also serve to set
|
26
|
-
# their respective hook closures.
|
27
|
-
#
|
28
|
-
# When an instance is first created, unary +new_instance_hook+ is called.
|
29
|
-
# When an instance is offered a name, +name_set_hook+ is called. It is a
|
30
|
-
# ternary closure with 3 ordered arguments +name+, +instance+ and +old_name+,
|
31
|
-
# receiving respectively the name offered, the instance, and the previous
|
32
|
-
# name of the instance (if any). The return value of the closure will be used
|
33
|
-
# to actually name the instance. This closure can thus be used to check and
|
34
|
-
# modify the names before they are actually used. Finally, when the instances'
|
35
|
-
# name is queried, third closure, unary +name_get_hook+ is applied to modify
|
36
|
-
# the name output. The purpose of the name get hook is not to really change
|
37
|
-
# the name upon reading, but mainly to tweak the preferred form or spelling
|
38
|
-
# where multiple forms of are possible for the same name. (For example, the
|
39
|
-
# standard form in the +@instances+ hash could be in camel case, such as
|
40
|
-
# "AcinonyxJubatus", while preferred querying output would be a binomial name
|
41
|
-
# with whitespaces, "Acinonyx jubatus".)
|
42
|
-
#
|
43
|
-
# === Avidity of the instances
|
44
|
-
#
|
45
|
-
# After the offered name is checked and modified by the name set hook closure,
|
46
|
-
# there is one more remaining problem to worry about: Whether the name is
|
47
|
-
# already used by another instance in the same namespace. If the name is taken,
|
48
|
-
# the ensuing action depends on whether the instance being named is _avid_.
|
49
|
-
# Avid instances are so eager to get a name, that they will steal the offered
|
50
|
-
# name even if it is already in use, making the conflicting instance nameless
|
51
|
-
# in the process. In +NameMagic+, it turns out to be convenient to make the
|
52
|
-
# new instances avid by default, unless the name was explicitly supplied to the
|
53
|
-
# constructor by +:name+ argument, or avidity suppressed by setting +:name_avid
|
54
|
-
# option to _false_.
|
55
|
-
#
|
56
|
-
# Techincally, avid instances are registered as an array kept by the namespace
|
57
|
-
# under the variable +@avid_instances+.
|
58
|
-
#
|
59
|
-
# === Forgetting instances
|
60
|
-
#
|
61
|
-
# A namespace can de-register, or forget instances. For this purpose, see
|
62
|
-
# methods +#forget+, +#__forget__, +#forget_nameless_instances+,
|
63
|
-
# +#forget_all_instances+.
|
64
|
-
#
|
65
|
-
# === Ersatz constant magic
|
66
|
-
#
|
67
|
-
# To imitate built-in constant magic of some Ruby classes, +NamespaceMethods+
|
68
|
-
# provides ersatz method +#const_magic+, that searches all the modules in the
|
69
|
-
# object space for the pertinent instances newly assigned to constants. Method
|
70
|
-
# +#const_magic+ is then called before executing almost every public method of
|
71
|
-
# +NameMagic+, thus keeping the "civil registry" up-to-date. While not exactly
|
72
|
-
# computationally efficient, it tends to make the user code more readable and
|
73
|
-
# pays off in most usecases. For efficiency, we are looking forward to the
|
74
|
-
# +#const_assigned+ hook promised by Ruby core team...
|
75
|
-
#
|
76
|
-
# The namespace method versions that _do_ _not_ perform ersatz constant magic
|
77
|
-
# are generally denoted by underlines: Eg. methods +#__instances__+ and
|
78
|
-
# +#__forget__+ do not perform constant magic, while +#instances+ and +#forget+
|
79
|
-
# do.
|
80
|
-
#
|
81
|
-
module NameMagic::NamespaceMethods
|
82
|
-
# Presents the instances registered in this namespace.
|
83
|
-
#
|
84
|
-
def instances *args
|
85
|
-
const_magic
|
86
|
-
__instances__.keys
|
87
|
-
end
|
88
|
-
|
89
|
-
# Deprecated method to get full names of the named instances.
|
90
|
-
#
|
91
|
-
def instance_names
|
92
|
-
warn "Method #instance_names is deprecated. Use 'instances._names_' or 'instances.names' instead!"
|
93
|
-
instances.names false
|
94
|
-
end
|
95
|
-
|
96
|
-
# Presents namespace-owned +@instances+ hash. The hash consists of pairs
|
97
|
-
# <code>{ instance => instance_name }</code>. Unnamed instances have +nil+
|
98
|
-
# assigned to them as their name. (The method does not trigger
|
99
|
-
# +#const_magic+.)
|
100
|
-
#
|
101
|
-
def __instances__
|
102
|
-
@instances ||= {}
|
103
|
-
end
|
104
|
-
|
105
|
-
# Avid instances registered in this namespace. ("Avid" means that the
|
106
|
-
# instance is able to steal (overwrite) a name from another registered
|
107
|
-
# instance. (The method does not trigger +#const_magic+.)
|
108
|
-
#
|
109
|
-
def __avid_instances__
|
110
|
-
@avid_instances ||= []
|
111
|
-
end
|
112
|
-
|
113
|
-
# Returns the instance identified by the argument, which can be typically
|
114
|
-
# a name (string/symbol). If a registered instance is supplied, it will be
|
115
|
-
# returned unchanged.
|
116
|
-
#
|
117
|
-
def instance id, *args
|
118
|
-
# puts "#instance( #{identifier} )" if DEBUG
|
119
|
-
# In @instances hash, value 'nil' indicates a nameless instance!
|
120
|
-
fail TypeError, "'nil' is not an instance identifier!" if id.nil?
|
121
|
-
ii = instances
|
122
|
-
return id if ii.include? id # return the instance back
|
123
|
-
begin # identifier not a registered instance -- treat it as a name
|
124
|
-
ary = [id, id.to_sym]
|
125
|
-
ihsh = __instances__
|
126
|
-
ii.find { |inst| ary.include? ihsh[ inst ] or ary.include? inst.name }
|
127
|
-
rescue NoMethodError
|
128
|
-
end or fail NameError, "No instance #{id} in #{self}."
|
129
|
-
end
|
130
|
-
|
131
|
-
# Searches all the modules in the the object space for constants referring
|
132
|
-
# to receiver class objects, and names the found instances accordingly.
|
133
|
-
# Internally, it works by invoking private procedure +#search_all_modules.
|
134
|
-
# The return value is the remaining number of nameless instances.
|
135
|
-
#
|
136
|
-
def const_magic
|
137
|
-
puts "#{self}#const_magic invoked!" if ::NameMagic::DEBUG
|
138
|
-
return 0 if nameless_instances.size == 0
|
139
|
-
search_all_modules
|
140
|
-
return nameless_instances.size
|
141
|
-
end
|
142
|
-
|
143
|
-
# Returns those instances, which are nameless (whose name is set to nil).
|
144
|
-
#
|
145
|
-
def nameless_instances *args
|
146
|
-
__instances__.select { |key, val| val.nil? }.keys
|
147
|
-
end
|
148
|
-
|
149
|
-
# Clears namespace-owned references to a specified instance. (This is
|
150
|
-
# different from "unnaming" an instance by setting <code>inst.name =
|
151
|
-
# nil</code>, which makes the instance anonymous, but still registered.)
|
152
|
-
#
|
153
|
-
def forget instance_identifier, *args
|
154
|
-
inst = begin; instance( instance_identifier ); rescue ArgumentError
|
155
|
-
return nil # nothing to forget
|
156
|
-
end
|
157
|
-
ɴ = inst.nil? ? nil : inst.name
|
158
|
-
namespace.send :remove_const, ɴ if ɴ # clear constant assignment
|
159
|
-
__instances__.delete( inst ) # remove @instances entry
|
160
|
-
__avid_instances__.delete( inst ) # remove if any
|
161
|
-
return inst # return the forgotten instance
|
162
|
-
end
|
163
|
-
|
164
|
-
# Clears namespace-owned references to an instance, without performing
|
165
|
-
# #const_magic first. The argument should be a registered instance. Returns
|
166
|
-
# the instance name, or _false_, if there was no such registered instance.
|
167
|
-
#
|
168
|
-
def __forget__( instance, *args )
|
169
|
-
return false unless __instances__.keys.include? instance
|
170
|
-
namespace.send :remove_const, instance.name if instance.name
|
171
|
-
__avid_instances__.delete( instance )
|
172
|
-
__instances__.delete instance
|
173
|
-
end
|
174
|
-
|
175
|
-
# Clears namespace-owned references to all the anonymous instances.
|
176
|
-
#
|
177
|
-
def forget_nameless_instances
|
178
|
-
nameless_instances.each { |inst|
|
179
|
-
__instances__.delete( inst )
|
180
|
-
__avid_instances__.delete( inst ) # also from avid instances
|
181
|
-
}
|
182
|
-
end
|
183
|
-
|
184
|
-
# Clears namespace-owned references to all the instances.
|
185
|
-
#
|
186
|
-
def forget_all_instances
|
187
|
-
__instances__.clear
|
188
|
-
constants( false ).each { |sym|
|
189
|
-
namespace.send :remove_const, sym if const_get( sym ).is_a? self
|
190
|
-
}
|
191
|
-
end
|
192
|
-
|
193
|
-
# Registers a hook to execute upon instantiation. Expects a unary block, whose
|
194
|
-
# argument represents the new instance. It is called right after instantiation,
|
195
|
-
# but before naming the instance. Without a block, it acts as a getter.
|
196
|
-
#
|
197
|
-
def new_instance_hook &block
|
198
|
-
@new_instance_hook = block if block
|
199
|
-
@new_instance_hook ||= -> instance { instance }
|
200
|
-
end
|
201
|
-
|
202
|
-
# Registers a hook to execute upon instance naming. Expects a ternary block,
|
203
|
-
# with arguments name, instance and old_name, representing respectively the
|
204
|
-
# the requested name, the instance to be named, and the previous name of that
|
205
|
-
# instance (if any). The output of the block should be the name to actually
|
206
|
-
# be used. In other words, the hook can be used (among other things) to check
|
207
|
-
# and/or modify the requested name when christening the instance. It is the
|
208
|
-
# responsibility of this block to output a symbol that can be used as a Ruby
|
209
|
-
# constant name. Without a block, this method acts as a getter.
|
210
|
-
#
|
211
|
-
def name_set_hook &block
|
212
|
-
@name_set_hook = block if block
|
213
|
-
@name_set_hook ||= -> name, instance, old_name=nil { name }
|
214
|
-
end
|
215
|
-
|
216
|
-
# Registers a hook to execute whenever the instance is asked its name. The
|
217
|
-
# instance names are objects that are kept in a hash referred to by
|
218
|
-
# +@instances+ variable owned by the namespace. Normally, +NameMagic#name+
|
219
|
-
# simply returns the name of the instance, as found in the +@instances+ hash.
|
220
|
-
# When +name_get_hook+ is defined, this name is transformed by it before being
|
221
|
-
# returned. Without a block, this method acts as a getter.
|
222
|
-
#
|
223
|
-
def name_get_hook &block
|
224
|
-
@name_get_hook = block if block
|
225
|
-
@name_get_hook ||= -> name { name }
|
226
|
-
end
|
227
|
-
|
228
|
-
# Checks whether a name is acceptable as a constant name.
|
229
|
-
#
|
230
|
-
def validate_name name
|
231
|
-
name.to_s.tap do |ɴ| # check if the name starts with 'A'..'Z'
|
232
|
-
fail NameError, "#{self}-registered name must start with a capital " +
|
233
|
-
" letter 'A'..'Z' ('#{ɴ}' given)!" unless ( ?A..?Z ) === ɴ[0]
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
private
|
238
|
-
|
239
|
-
# Checks all the constants in some module's namespace, recursively.
|
240
|
-
#
|
241
|
-
def search_all_modules
|
242
|
-
todo = ( nameless_instances + __avid_instances__ ).map( &:object_id ).uniq
|
243
|
-
ObjectSpace.each_object Module do |ɱ|
|
244
|
-
ɱ.constants( false ).each do |const_ß|
|
245
|
-
begin; instance = ɱ.const_get( const_ß ) # Some constants cause
|
246
|
-
rescue LoadError, StandardError; next end # errors upon loading.
|
247
|
-
next unless todo.include? instance.object_id
|
248
|
-
# puts "NameMagic: Anonymous object under #{const_ß}!" if DEBUG
|
249
|
-
if instance.avid? then # puts "NameMagic: It is avid." if DEBUG
|
250
|
-
instance.make_not_avid! # Remove from the avid list.
|
251
|
-
instance.name! const_ß # Name it rudely.
|
252
|
-
else # puts "NameMagic: It is not avid." if DEBUG
|
253
|
-
instance.name = const_ß # Name it cautiously.
|
254
|
-
end
|
255
|
-
todo.delete instance.object_id # Remove from todo list.
|
256
|
-
break if todo.empty? # Abandon the loop if done.
|
257
|
-
end
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end # module NameMagic::NamespaceMethods
|
data/lib/y_support/try.rb
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'y_support'
|
4
|
-
require 'y_support/core_ext/array/misc'
|
5
|
-
|
6
|
-
# Provides +Try+ class, and +Object#try+ method that constructs and calls a
|
7
|
-
# +Consciously::Try+ instance. This +#try+ method has nothing to do with the
|
8
|
-
# error-swallowing +#try+ method frequently seen elsewhere. On the contrary,
|
9
|
-
# our +#try+ method _facilitates_ raising and ultimately, correcting errors
|
10
|
-
# by providing well-formed error messages.
|
11
|
-
#
|
12
|
-
# Constructing error messages is labor-intensive. +Consciously::Try+ allows one
|
13
|
-
# to construct verbose error messages with +#note+ statements inside the block,
|
14
|
-
# that act as comments at the same time.
|
15
|
-
#
|
16
|
-
# "FooBar".try "to do something" do
|
17
|
-
# note has: "#{size} letters", is: "a #{self.class} instance"
|
18
|
-
# unless include? "Quux"
|
19
|
-
# note "Quux", is: "not a part of it"
|
20
|
-
# try "to append Quux to it" do
|
21
|
-
# self << "Quux"
|
22
|
-
# fail "EPIC FAIL"
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
#
|
27
|
-
# Should produce an automatic error message like this: "When trying to do
|
28
|
-
# something, FooBar having 6 letters, being a String instance, Quux being
|
29
|
-
# not a part of it, RuntimeError occurred: When trying to append Quux to it,
|
30
|
-
# RuntimeError occurred: EPIC FAIL"
|
31
|
-
#
|
32
|
-
module Consciously
|
33
|
-
class Try < BasicObject
|
34
|
-
DECORATE = -> str, prefix: '', postfix: '' {
|
35
|
-
str.to_s.tap { |ς| return ς.empty? ? '' : prefix + ς + postfix }
|
36
|
-
}
|
37
|
-
TRANSITIVE = ::Hash.new do |ꜧ, key| "#{key}ing %s" end
|
38
|
-
.update( is: "being %s",
|
39
|
-
has: "having %s" )
|
40
|
-
STATE = ::Hash.new do |ꜧ, key| "#{key} %s" end
|
41
|
-
.update( is: "%s",
|
42
|
-
has: "has %s" )
|
43
|
-
|
44
|
-
attr_reader :__obj__, :__txt__, :__bl__, :__facts__
|
45
|
-
|
46
|
-
# This
|
47
|
-
def initialize( object: nil, text: nil, &block )
|
48
|
-
@__obj__, @__txt__, @__bl__ = object, text, block
|
49
|
-
@__facts__ = ::Hash.new do |hsh, key| hsh[key] = [ {} ] end
|
50
|
-
end
|
51
|
-
|
52
|
-
# The syntax of this method, available inside the #try block, is:
|
53
|
-
#
|
54
|
-
# note "Concatenation of Foo and Bar", is: "FooBar", has: "6 letters"
|
55
|
-
#
|
56
|
-
def note *subjects, **statements, &block
|
57
|
-
return Array( subjects ).each { |s| __facts__[s].push_ordered s } if
|
58
|
-
statements.empty?
|
59
|
-
subjects << __obj__ if subjects.empty?
|
60
|
-
Array( subjects ).each { |subj|
|
61
|
-
statements.each { |verb, obj| __facts__[subj].push_named verb => obj }
|
62
|
-
}
|
63
|
-
return statements.first[1]
|
64
|
-
end
|
65
|
-
|
66
|
-
# Invokes the Try object's block.
|
67
|
-
#
|
68
|
-
def __invoke__ *args
|
69
|
-
begin
|
70
|
-
instance_exec *args, &__bl__
|
71
|
-
rescue ::StandardError => err
|
72
|
-
txt1 = "When trying #{__txt__}"
|
73
|
-
thing, statements = __describe__
|
74
|
-
txt2 = DECORATE.( thing, prefix: ' ' )
|
75
|
-
txt3 = DECORATE.( statements.map { |verb, object|
|
76
|
-
STATE[verb] % object
|
77
|
-
}.join( ', ' ),
|
78
|
-
prefix: ' (', postfix: ')' )
|
79
|
-
txt4 = DECORATE.( __circumstances__, prefix: ', ' )
|
80
|
-
txt5 = DECORATE.( "#{err.class} occurred: #{err}", prefix: ', ' )
|
81
|
-
raise err, txt1 + txt2 + txt3 + txt4 + txt5
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def try *args, &block
|
86
|
-
__obj__.try *args, &block
|
87
|
-
end
|
88
|
-
|
89
|
-
def method_missing sym, *args
|
90
|
-
__obj__.send sym, *args
|
91
|
-
end
|
92
|
-
|
93
|
-
def __describe__ obj=__obj__
|
94
|
-
facts = __facts__[obj].dup
|
95
|
-
statements = if facts.last.is_a? ::Hash then facts.pop else {} end
|
96
|
-
fs = facts.join ', '
|
97
|
-
if statements.empty? then
|
98
|
-
return fs, statements
|
99
|
-
else
|
100
|
-
return facts.empty? ? obj.to_s : fs, statements
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def __circumstances__
|
105
|
-
__facts__.reject { |subj, _| subj == __obj__ }.map { |subj, _|
|
106
|
-
thing, statements = __describe__( subj )
|
107
|
-
thing + DECORATE.( statements.map { |v, o|
|
108
|
-
TRANSITIVE[v] % o
|
109
|
-
}.join( ', ' ),
|
110
|
-
prefix: ' ' )
|
111
|
-
}.join( ', ' )
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
|
117
|
-
class Object
|
118
|
-
# Try method takes two textual arguments and one block. The first (optional)
|
119
|
-
# argument is a natural language description of the method's receiver (with
|
120
|
-
# #to_s of the receiver used by default). The second argument is a natural
|
121
|
-
# language description of the supplied block's _contract_ -- in other words,
|
122
|
-
# what the supplied block tries to do. Finally, the block contains the code
|
123
|
-
# to perform the described risky action. Inside the block, +#note+ method is
|
124
|
-
# available, which builds up the context information for a good error message,
|
125
|
-
# should the risky action raise one.
|
126
|
-
#
|
127
|
-
def try receiver_NL_description=self, attempt_NL_description, &block
|
128
|
-
Consciously::Try.new( object: receiver_NL_description,
|
129
|
-
text: attempt_NL_description,
|
130
|
-
&block ).__invoke__
|
131
|
-
end
|
132
|
-
alias consciously try
|
133
|
-
end
|
@@ -1,138 +0,0 @@
|
|
1
|
-
#! /usr/bin/ruby
|
2
|
-
#encoding: utf-8
|
3
|
-
|
4
|
-
fail NotImplementedError # TODO: This part doesn't work yet
|
5
|
-
|
6
|
-
require 'minitest/autorun'
|
7
|
-
|
8
|
-
describe "Algebra" do
|
9
|
-
before do
|
10
|
-
require './../lib/y_support/abstract_algebra'
|
11
|
-
# Define the stupidest monoid:
|
12
|
-
@monoid = Class.new { include Algebra::Monoid } # make some class
|
13
|
-
zero = @monoid.new # call arbitrary instance zero
|
14
|
-
@monoid.class_exec {
|
15
|
-
# Define the stupidest #add method.
|
16
|
-
define_method :add do |other|
|
17
|
-
if self == zero then other
|
18
|
-
elsif other == zero then self
|
19
|
-
else self.class.addition_table[[self, other]] end
|
20
|
-
end
|
21
|
-
# Define the stupidest addition table.
|
22
|
-
instance_variable_set :@addition_table,
|
23
|
-
Hash.new { |ꜧ, k|
|
24
|
-
ꜧ[k] = if k[0].object_id <= k[1].object_id
|
25
|
-
new # just make up an instance
|
26
|
-
else
|
27
|
-
ꜧ[k[1], k[0]] # swap operands
|
28
|
-
end
|
29
|
-
}
|
30
|
-
}
|
31
|
-
# And refine the @monoid's singleton class.
|
32
|
-
@monoid.singleton_class.class_exec { attr_reader :addition_table }
|
33
|
-
@monoid.define_singleton_method :additive_identity do zero end
|
34
|
-
end
|
35
|
-
|
36
|
-
describe "Algebra" do
|
37
|
-
it "should have working Monoid" do
|
38
|
-
m = @monoid.random # choose an instance
|
39
|
-
|
40
|
-
# #== method
|
41
|
-
assert m == m
|
42
|
-
|
43
|
-
# closure
|
44
|
-
# (not tested)
|
45
|
-
|
46
|
-
# associativity
|
47
|
-
n, o = @monoid.random, @monoid.random
|
48
|
-
assert ( m + n ) + o == m + ( n + o )
|
49
|
-
|
50
|
-
# identity element
|
51
|
-
assert m + @monoid.zero == m
|
52
|
-
assert @monoid.zero + m == m
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should have working Group" do
|
56
|
-
g = @group.random
|
57
|
-
|
58
|
-
# (monoid properties not tested)
|
59
|
-
|
60
|
-
# inverse element
|
61
|
-
assert g + (-g) == @group.zero
|
62
|
-
assert (-g) + g == @group.zero
|
63
|
-
end
|
64
|
-
|
65
|
-
it "should define AbelianGroup" do
|
66
|
-
ag = @abelian_group.random
|
67
|
-
|
68
|
-
# (group properties not tested)
|
69
|
-
|
70
|
-
# commutativity
|
71
|
-
bh = @abelian_group.random
|
72
|
-
assert ag + bh == bh + ag
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should define Ring" do
|
76
|
-
r = @ring.random
|
77
|
-
|
78
|
-
# (abelian group properties with respect to addition not tested)
|
79
|
-
|
80
|
-
# (multiplication closure not tested)
|
81
|
-
|
82
|
-
# multiplication associativity
|
83
|
-
s, t = @ring.random, @ring.random
|
84
|
-
assert r * ( s * t ) == ( r * s ) * t
|
85
|
-
|
86
|
-
# multiplication identity
|
87
|
-
mi = @ring.one
|
88
|
-
assert r * mi == r
|
89
|
-
assert mi * r == r
|
90
|
-
|
91
|
-
# distributivity
|
92
|
-
assert r * ( s + t ) == ( r * s ) + ( s * t )
|
93
|
-
end
|
94
|
-
|
95
|
-
it "should define Field" do
|
96
|
-
f = @field.random
|
97
|
-
|
98
|
-
# (ring properties not tested)
|
99
|
-
|
100
|
-
# multiplicative inverse
|
101
|
-
mi = @ring.multiplicative_identity
|
102
|
-
assert f * f.multiplicative_inverse == mi
|
103
|
-
assert f.multiplicative_inverse * f == mi
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
describe "numerics" do
|
108
|
-
it "should have patched Integer" do
|
109
|
-
assert Integer.zero.equal? 0
|
110
|
-
end
|
111
|
-
|
112
|
-
it "should have patched Float" do
|
113
|
-
assert Float.zero.equal? 0.0
|
114
|
-
end
|
115
|
-
|
116
|
-
it "should have patched Rational" do
|
117
|
-
assert Rational.zero.equal? Rational( 0, 0 )
|
118
|
-
end
|
119
|
-
|
120
|
-
it "should have patched Complex" do
|
121
|
-
assert Complex.zero.equal? Complex( 0, 0 )
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
describe "Matrix" do
|
126
|
-
it "should have Matrix.wildcard_zero public instance method" do
|
127
|
-
# FIXME
|
128
|
-
end
|
129
|
-
|
130
|
-
it "should be able to perform #* with nonnumerics in the matrix" do
|
131
|
-
# FIXME
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should numeric matrix multiplication still be working normally" do
|
135
|
-
# FIXME
|
136
|
-
end
|
137
|
-
end # context Matrix
|
138
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
#! /usr/bin/ruby
|
2
|
-
|
3
|
-
require 'minitest/autorun'
|
4
|
-
require 'minitest/benchmark'
|
5
|
-
|
6
|
-
class TestCoreMethods < Minitest::Benchmark
|
7
|
-
def setup
|
8
|
-
@arrays = ( 1 .. 11_000 ).map { |n| [ 42 ] * n }
|
9
|
-
end
|
10
|
-
|
11
|
-
# Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000]
|
12
|
-
def bench_size
|
13
|
-
assert_performance_linear 0.99 do |n| ( [ 0 ] * n ).reduce :+ end
|
14
|
-
assert_performance_constant 0.99 do |n| 42.times { 42 } end
|
15
|
-
# assert_performance_linear 0.99 do |n| @arrays[ n ].size end
|
16
|
-
assert_performance_constant 0.99 do |n| @arrays[ n ].size end
|
17
|
-
# TODO: For some reason, assert_performance_constant doesn't fail even if
|
18
|
-
# I artificially introduce eg. quadratic algorithm. All the while, the
|
19
|
-
# line assert_performance_linear does fail if uncommented (since the perf.
|
20
|
-
# here is constant).
|
21
|
-
# TODO: In other words, I'm not very experienced in performance testing yet.
|
22
|
-
end
|
23
|
-
end
|
data/test/try_test.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
#! /usr/bin/ruby
|
2
|
-
|
3
|
-
require 'minitest/autorun'
|
4
|
-
# require 'y_support/try' # tested component itself
|
5
|
-
require './../lib/y_support/try'
|
6
|
-
|
7
|
-
describe Consciously do
|
8
|
-
before do
|
9
|
-
@try = Consciously::Try.new object: "Dummy", text: "to fire" do
|
10
|
-
note is: "dummy"
|
11
|
-
note has: "no care in the world"
|
12
|
-
n = note "its number", is: 42
|
13
|
-
raise TypeError, 'foo'
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should have basic functionality" do
|
18
|
-
assert_equal "to fire", @try.__txt__
|
19
|
-
assert_equal "Dummy", @try.__obj__
|
20
|
-
assert_equal 0, @try.__facts__.size # haven't tried anything yet
|
21
|
-
@try.__facts__["something"]
|
22
|
-
assert_equal 1, @try.__facts__.size
|
23
|
-
@try.note is: 'dummy'
|
24
|
-
@try.note has: 'no care in the world'
|
25
|
-
assert_equal 2, @try.__facts__.size
|
26
|
-
assert_equal ["something", "Dummy"], @try.__facts__.keys
|
27
|
-
assert_equal( [ { is: "dummy", has: "no care in the world" } ],
|
28
|
-
@try.__facts__["Dummy"] )
|
29
|
-
assert_equal " hello!", Consciously::Try::DECORATE.( :hello, prefix: ' ', postfix: '!' )
|
30
|
-
assert_equal( ['Dummy', {is: 'dummy', has: 'no care in the world'}],
|
31
|
-
@try.__describe__( "Dummy" ) )
|
32
|
-
end
|
33
|
-
|
34
|
-
describe 'case 1' do
|
35
|
-
it "should work" do
|
36
|
-
begin
|
37
|
-
@try.__invoke__
|
38
|
-
rescue TypeError => err
|
39
|
-
expected_msg = "When trying to fire Dummy (dummy, has no care in " +
|
40
|
-
"the world), its number being 42, TypeError occurred: foo"
|
41
|
-
assert_equal expected_msg, err.message
|
42
|
-
else
|
43
|
-
flunk "Expected TypeError error not raised!"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe 'case 2' do
|
49
|
-
it "should work" do
|
50
|
-
begin
|
51
|
-
try "to call constant Nonexistant" do Nonexistant end
|
52
|
-
rescue NameError => err
|
53
|
-
expected_msg = 'When trying to call constant Nonexistant, ' +
|
54
|
-
'NameError occurred: uninitialized constant Nonexistant'
|
55
|
-
assert_equal( expected_msg, err.message )
|
56
|
-
else
|
57
|
-
flunk "Expected NameError error not raised!"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe 'case 3' do
|
63
|
-
it "should work" do
|
64
|
-
o = Object.new
|
65
|
-
class << o
|
66
|
-
def to_s; "THIS OBJECT" end
|
67
|
-
def hello!; "hello hello" end
|
68
|
-
end
|
69
|
-
# Object's methods must be callable
|
70
|
-
o.try "to say hello" do hello! end.must_equal "hello hello"
|
71
|
-
begin
|
72
|
-
o.try "to call a weird method" do goodbye! end
|
73
|
-
rescue NoMethodError => err
|
74
|
-
err.message.must_include "When trying to call a weird method, " +
|
75
|
-
"NoMethodError occurred: undefined method"
|
76
|
-
err.message.must_include "goodbye!"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe 'case 4' do
|
82
|
-
it "should work" do
|
83
|
-
begin
|
84
|
-
"FooBar".try "to do something" do
|
85
|
-
note has: "#{size} letters", is: "a #{self.class} instance"
|
86
|
-
unless include? "Quux"
|
87
|
-
note "Quux", is: "not a part of it"
|
88
|
-
try "to append Quux to it" do
|
89
|
-
self << "Quux"
|
90
|
-
fail "EPIC FAIL"
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
rescue => err
|
95
|
-
err.message.must_equal 'When trying to do something, FooBar having ' +
|
96
|
-
'6 letters, being a String instance, Quux being not a part of it, ' +
|
97
|
-
'RuntimeError occurred: When trying to append Quux to it, ' +
|
98
|
-
'RuntimeError occurred: EPIC FAIL'
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|