y_support 1.0.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 +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/lib/y_support/all.rb +40 -0
- data/lib/y_support/core_ext/array/misc.rb +45 -0
- data/lib/y_support/core_ext/array.rb +1 -0
- data/lib/y_support/core_ext/enumerable/misc.rb +32 -0
- data/lib/y_support/core_ext/enumerable.rb +1 -0
- data/lib/y_support/core_ext/hash/misc.rb +90 -0
- data/lib/y_support/core_ext/hash.rb +1 -0
- data/lib/y_support/core_ext/module/misc.rb +43 -0
- data/lib/y_support/core_ext/module.rb +2 -0
- data/lib/y_support/core_ext/numeric/misc.rb +13 -0
- data/lib/y_support/core_ext/numeric.rb +1 -0
- data/lib/y_support/core_ext/object/misc.rb +31 -0
- data/lib/y_support/core_ext/object.rb +1 -0
- data/lib/y_support/core_ext/string/misc.rb +80 -0
- data/lib/y_support/core_ext/string.rb +1 -0
- data/lib/y_support/core_ext/symbol/misc.rb +19 -0
- data/lib/y_support/core_ext/symbol.rb +1 -0
- data/lib/y_support/core_ext.rb +5 -0
- data/lib/y_support/inert_recorder.rb +51 -0
- data/lib/y_support/local_object.rb +39 -0
- data/lib/y_support/misc.rb +28 -0
- data/lib/y_support/name_magic.rb +373 -0
- data/lib/y_support/null_object.rb +96 -0
- data/lib/y_support/respond_to.rb +32 -0
- data/lib/y_support/stdlib_ext/matrix/misc.rb +134 -0
- data/lib/y_support/stdlib_ext/matrix.rb +2 -0
- data/lib/y_support/stdlib_ext.rb +3 -0
- data/lib/y_support/typing/array/typing.rb +17 -0
- data/lib/y_support/typing/array.rb +1 -0
- data/lib/y_support/typing/enumerable/typing.rb +75 -0
- data/lib/y_support/typing/enumerable.rb +1 -0
- data/lib/y_support/typing/hash/typing.rb +76 -0
- data/lib/y_support/typing/hash.rb +1 -0
- data/lib/y_support/typing/module/typing.rb +42 -0
- data/lib/y_support/typing/module.rb +1 -0
- data/lib/y_support/typing/object/typing.rb +178 -0
- data/lib/y_support/typing/object.rb +1 -0
- data/lib/y_support/typing.rb +43 -0
- data/lib/y_support/unicode.rb +76 -0
- data/lib/y_support/version.rb +3 -0
- data/lib/y_support.rb +33 -0
- data/test/inert_recorder_test.rb +34 -0
- data/test/local_object_test.rb +37 -0
- data/test/misc_test/test_module/fixture_class.rb +8 -0
- data/test/misc_test.rb +289 -0
- data/test/name_magic_test.rb +57 -0
- data/test/null_object_test.rb +50 -0
- data/test/respond_to_test.rb +46 -0
- data/test/typing_test.rb +213 -0
- data/test/unicode_test.rb +39 -0
- data/y_support.gemspec +22 -0
- metadata +137 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
module Enumerable
|
4
|
+
# Fails with TypeError unless all the members of the collection comply with
|
5
|
+
# the supplied block criterion. Optional arguments customize the error
|
6
|
+
# message. First optional argument describes the collection element, the
|
7
|
+
# second one describes the tested duck type. If the criterion block takes
|
8
|
+
# at least one argument, the receiver elemnts are passed to it (#all?
|
9
|
+
# method). If the criterion block takes no arguments (arity 0), it is
|
10
|
+
# gradually executed inside the elements (using #instance_exec method).
|
11
|
+
# If no block is given, all members are required to be truey.
|
12
|
+
#
|
13
|
+
def aT_all what_is_collection_element=nil, how_comply=nil, &b
|
14
|
+
e = what_is_collection_element || "collection element"
|
15
|
+
if block_given?
|
16
|
+
m = "Each #{e} must %s!" %
|
17
|
+
( how_comply ? how_comply : "comply with the given duck type" )
|
18
|
+
raise TErr, m unless ( b.arity == 0 ?
|
19
|
+
all? { |e| e.instance_exec( &b ) } :
|
20
|
+
all? { |e| b.( e ) } )
|
21
|
+
else
|
22
|
+
m = "No #{e} must be nil or false!"
|
23
|
+
raise TErr, m unless all? { |e| e }
|
24
|
+
end
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
# Fails with TypeError unless all collection members are #kind_of? the
|
29
|
+
# class supplied as argument. Second optional argument (collection element
|
30
|
+
# description) customizes the error message.
|
31
|
+
#
|
32
|
+
def aT_all_kind_of klass, what_is_collection_element=nil
|
33
|
+
e = what_is_collection_element || "collection element"
|
34
|
+
m = "Each #{e} must be kind of #{klass}!"
|
35
|
+
raise TErr, m unless all? { |e| e.kind_of? klass }
|
36
|
+
return self
|
37
|
+
end
|
38
|
+
|
39
|
+
# Fails with TypeError unless all collection members declare compliance with
|
40
|
+
# compliance with the class supplied as argument. Second optional argument
|
41
|
+
# (collection element description) customizes the error message.
|
42
|
+
#
|
43
|
+
def aT_all_comply klass, what_is_collection_element=nil
|
44
|
+
e = what_is_collection_element || "collection element"
|
45
|
+
m = "Each #{e} must declare compliance to #{klass}!"
|
46
|
+
raise TErr, m unless all? { |e| e.class_complies? klass }
|
47
|
+
return self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Fails with TypeError unless all the collection members declare compliance
|
51
|
+
# with Numeric. Second optional argument (collection element description)
|
52
|
+
# customizes the error message.
|
53
|
+
#
|
54
|
+
def aT_all_numeric what_is_collection_element=nil
|
55
|
+
e = what_is_collection_element || "collection element"
|
56
|
+
m = "Each #{e} must declare compliance with Numeric!"
|
57
|
+
raise TErr, m unless all? { |e| e.class_complies? Numeric }
|
58
|
+
return self
|
59
|
+
end
|
60
|
+
|
61
|
+
# Fails with TypeError unless all the collection members are included int the
|
62
|
+
# collection supplied as argument. Second optional argument (collection
|
63
|
+
# element description) customizes the error message.
|
64
|
+
#
|
65
|
+
def aT_subset_of other_collection, what_is_receiver_collection=nil,
|
66
|
+
what_is_other_collection=nil
|
67
|
+
rc = what_is_receiver_collection ?
|
68
|
+
what_is_receiver_collection.to_s.capitalize : "collection"
|
69
|
+
oc = what_is_other_collection ? what_is_other_collection.to_s.capitalize :
|
70
|
+
"the specified collection"
|
71
|
+
m = "The #{rc} must be a subset of #{oc}"
|
72
|
+
raise TErr, m unless all? { |e| other_collection.include? e }
|
73
|
+
return self
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/enumerable/typing'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# Merges the synonymous hash keys into a single key - useful for argument
|
5
|
+
# validation. Returns nil if neither main key, nor synonyms are found.
|
6
|
+
# Returns false (no merging) if the main key was found, but no synonym keys.
|
7
|
+
# Returns true (yes merging) if any of the synonym keys is found and
|
8
|
+
# renamed/merged to the main key. Value collisions in synonym keys (detected
|
9
|
+
# by #==) raise ArgumentError.
|
10
|
+
#
|
11
|
+
def merge_synonym_keys!( key, *synonyms )
|
12
|
+
synonyms.reduce has_key?( key ) ? false : nil do |acc, syn|
|
13
|
+
next acc unless has_key? syn
|
14
|
+
if acc.nil? then
|
15
|
+
self[key] = self[syn]
|
16
|
+
delete syn
|
17
|
+
next true
|
18
|
+
end
|
19
|
+
if self[key] == self[syn] then
|
20
|
+
delete syn
|
21
|
+
next true
|
22
|
+
else
|
23
|
+
raise TErr, "Value collision between #{key} and its synonym #{syn}!"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# This method uses #merge_synonym_keys! method first and then returns the
|
29
|
+
# value under the key. The first argument is the main key. Synonyms may be
|
30
|
+
# supplied as a named argument :syn!. (Bang indicates that the synonym keys
|
31
|
+
# will be merged with the main key, modifying the hash.)
|
32
|
+
#
|
33
|
+
def may_have key, options={}
|
34
|
+
merge_synonym_keys!( key, *options[:syn!] ).nil?
|
35
|
+
return self[key]
|
36
|
+
end
|
37
|
+
|
38
|
+
# This method behaves similarly to #may_have, with the difference that it
|
39
|
+
# does not return the value of the key, only true / false to indicate whether
|
40
|
+
# the key or any synonym has been found.
|
41
|
+
#
|
42
|
+
def has? key, options={}
|
43
|
+
!merge_synonym_keys!( key, *options[:syn!] ).nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# This enforcer method (aka. runtime assertion) raises TypeError when:
|
47
|
+
# 1. Neither the required key nor any of its synonyms are present.
|
48
|
+
# 2. The supplied criterion block, if any, returns false when applied
|
49
|
+
# to the value of the key in question. If the block takes an argument
|
50
|
+
# (or more arguments), the value is passed in. If the block takes no
|
51
|
+
# arguments (arity 0), it is executed inside the singleton class of the
|
52
|
+
# receiver (using #instance_exec method).
|
53
|
+
#
|
54
|
+
def aT_has key, options={}, &b
|
55
|
+
raise TErr, "Key '#{key}' absent!" unless has? key, options
|
56
|
+
# Now validate self[key] using the supplied block
|
57
|
+
if block_given?
|
58
|
+
m = "Value for #{key} fails its duck type!"
|
59
|
+
raise TErr, m unless ( b.arity == 0 ? self[key].instance_exec( &b ) :
|
60
|
+
b.( self[key] ) )
|
61
|
+
end
|
62
|
+
return self[key]
|
63
|
+
end
|
64
|
+
alias :must_have :aT_has
|
65
|
+
|
66
|
+
# This method behaves exactly like #aT_has, but with the difference, that
|
67
|
+
# it raises ArgumentError instead of TypeError
|
68
|
+
#
|
69
|
+
def aE_has key, options={}, &b
|
70
|
+
begin
|
71
|
+
options.empty? ? aT_has( key, &b ) : aT_has( key, options, &b )
|
72
|
+
rescue TypeError => e
|
73
|
+
raise AErr, e.message
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/hash/typing'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
class Module
|
4
|
+
# === Support for typing by declaration
|
5
|
+
|
6
|
+
# Compliance inquirer (declared compliance + ancestors).
|
7
|
+
#
|
8
|
+
def complies?( other_module )
|
9
|
+
other_module.aT_kind_of Module, "other module"
|
10
|
+
compliance.include? other_module
|
11
|
+
end
|
12
|
+
|
13
|
+
# Declared complience inquirer.
|
14
|
+
#
|
15
|
+
def declares_compliance?( other_module )
|
16
|
+
other_module.aT_kind_of Module, "other module"
|
17
|
+
declared_compliance.include? other_module
|
18
|
+
end
|
19
|
+
|
20
|
+
# Compliance (declared compliance + ancestors).
|
21
|
+
#
|
22
|
+
def compliance
|
23
|
+
( declared_compliance + ancestors ).uniq
|
24
|
+
end
|
25
|
+
|
26
|
+
# Declared compliance getter.
|
27
|
+
#
|
28
|
+
def declared_compliance
|
29
|
+
( ( @declared_compliance || [] ) + ancestors.map { |a|
|
30
|
+
a.instance_variable_get( :@declared_compliance ) || []
|
31
|
+
}.reduce( [], :+ ) ).uniq
|
32
|
+
end
|
33
|
+
|
34
|
+
# Declaration of module / class compliance.
|
35
|
+
#
|
36
|
+
def declare_compliance! other_module
|
37
|
+
other_module.aT_kind_of Module, "other module"
|
38
|
+
return false if declared_compliance.include? other_module
|
39
|
+
( @declared_compliance ||= [] ) << other_module
|
40
|
+
return true
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/module/typing'
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
|
5
|
+
class Object
|
6
|
+
# === Support for typing by declaration
|
7
|
+
|
8
|
+
# Class compliance inquirer (declared compliance + class ancestors).
|
9
|
+
#
|
10
|
+
def class_complies?( klass )
|
11
|
+
singleton_class_or_class.complies? klass
|
12
|
+
end
|
13
|
+
|
14
|
+
# Declared class compliance.
|
15
|
+
#
|
16
|
+
def class_declares_compliance?( klass )
|
17
|
+
singleton_class_or_class.declares_compliance? klass
|
18
|
+
end
|
19
|
+
|
20
|
+
# Class compliance (declared class compliance + ancestors).
|
21
|
+
#
|
22
|
+
def class_compliance
|
23
|
+
singleton_class_or_class.compliance
|
24
|
+
end
|
25
|
+
|
26
|
+
# Declared class compliance.
|
27
|
+
#
|
28
|
+
def declared_class_compliance
|
29
|
+
singleton_class_or_class.declared_compliance
|
30
|
+
end
|
31
|
+
|
32
|
+
# Declaration of class compliance.
|
33
|
+
#
|
34
|
+
def declare_class_compliance!( klass )
|
35
|
+
singleton_class_or_class.declare_compliance! klass
|
36
|
+
end
|
37
|
+
|
38
|
+
# === Duck typing support (aka. runtime assertions)
|
39
|
+
|
40
|
+
# This method takes a block and fails with TypeError, unless the receiver
|
41
|
+
# fullfills the block criterion. Optional arguments customize customize
|
42
|
+
# the error message. First optional argument describes the receiver, the
|
43
|
+
# second one describes the tested duck type. If the criterion block takes
|
44
|
+
# at least one argument, the receiver is passed to it. If the criterion block
|
45
|
+
# takes no arguments (arity 0), it is executed inside the singleton class of
|
46
|
+
# the receiver (using #instance_exec method). If no block is given, it is
|
47
|
+
# checked, whether the object is truey.
|
48
|
+
#
|
49
|
+
def aT what_is_receiver=nil, how_comply=nil, &b
|
50
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
51
|
+
"#{self.class} instance #{object_id}"
|
52
|
+
if block_given?
|
53
|
+
m = "#{r} fails #{how_comply ? 'to %s' % how_comply : 'its duck type'}!"
|
54
|
+
raise TErr, m unless ( b.arity == 0 ) ? instance_exec( &b ) : b.( self )
|
55
|
+
else
|
56
|
+
raise TErr, m unless self
|
57
|
+
end
|
58
|
+
return self
|
59
|
+
end
|
60
|
+
|
61
|
+
# This method takes a block and fails with TypeError, unless the receiver
|
62
|
+
# causes the supplied block <em>to return falsey value</em>. Optional arguments
|
63
|
+
# customize customize the error message. First optional argument describes the
|
64
|
+
# receiver, the second one describes the tested duck type. If the criterion
|
65
|
+
# block takes at least one argument (or more arguments), the receiver is passed
|
66
|
+
# to it. If the criterion block takes no arguments (arity 0), it is executed
|
67
|
+
# inside the singleton class of the receiver (using #instance_exec method). If
|
68
|
+
# no block is given, it is checked, whether the object is falsey.
|
69
|
+
#
|
70
|
+
def aT_not what_is_receiver=nil, how_comply=nil, &b
|
71
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
72
|
+
"#{self.class} instance #{object_id}"
|
73
|
+
if block_given?
|
74
|
+
m = how_comply ? "#{r} must not #{how_comply}!" :
|
75
|
+
"#{r} fails its duck type!"
|
76
|
+
raise TErr, m if ( b.arity == 0 ) ? instance_exec( &b ) : b.( self )
|
77
|
+
else
|
78
|
+
m = "#{r} is not falsey!"
|
79
|
+
raise TErr, m if self
|
80
|
+
end
|
81
|
+
return self
|
82
|
+
end
|
83
|
+
|
84
|
+
# Fails with TypeError unless the receiver is of the prescribed class. Second
|
85
|
+
# optional argument customizes the error message (receiver description).
|
86
|
+
#
|
87
|
+
def aT_kind_of klass, what_is_receiver=nil
|
88
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
89
|
+
"#{self.class} instance #{object_id}"
|
90
|
+
m = "#{r} is not a kind of #{klass}!"
|
91
|
+
raise TErr, m unless kind_of? klass
|
92
|
+
return self
|
93
|
+
end
|
94
|
+
alias :aT_is_a :aT_kind_of
|
95
|
+
|
96
|
+
# Fails with TypeError unless the receiver declares compliance with the
|
97
|
+
# given class, or is a descendant of that class. Second optional argument
|
98
|
+
# customizes the error message (receiver description).
|
99
|
+
#
|
100
|
+
def aT_class_complies klass, what_is_receiver=nil
|
101
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
102
|
+
"#{self.class} instance #{object_id}"
|
103
|
+
m = "#{r} does not comply or declare compliance with #{klass}!"
|
104
|
+
raise TErr, m unless class_complies? klass
|
105
|
+
return self
|
106
|
+
end
|
107
|
+
|
108
|
+
# Fails with TypeError unless the receiver responds to the given
|
109
|
+
# method. Second optional argument customizes the error message (receiver
|
110
|
+
# description).
|
111
|
+
#
|
112
|
+
def aT_respond_to method_name, what_is_receiver=nil
|
113
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
114
|
+
"#{self.class} instance #{object_id}"
|
115
|
+
m = "#{r} does not respond to method '#{method_name}'!"
|
116
|
+
raise TErr, m unless respond_to? method_name
|
117
|
+
return self
|
118
|
+
end
|
119
|
+
alias :aT_responds_to :aT_respond_to
|
120
|
+
|
121
|
+
# Fails with TypeError unless the receiver, according to #== method, is
|
122
|
+
# equal to the argument. Two more optional arguments customize the error
|
123
|
+
# message (receiver description and the description of the other object).
|
124
|
+
#
|
125
|
+
def aT_equal other, what_is_receiver=nil, what_is_other=nil
|
126
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
127
|
+
"#{self.class} instance #{object_id}"
|
128
|
+
o = what_is_other || "the prescribed value (#{other.class})"
|
129
|
+
m = "#{r} is not equal (==) to #{o}!"
|
130
|
+
raise TErr, m unless self == other
|
131
|
+
return self
|
132
|
+
end
|
133
|
+
|
134
|
+
# Fails with TypeError unless the receiver, according to #== method, differs
|
135
|
+
# from to the argument. Two more optional arguments customize the error
|
136
|
+
# message (receiver description and the description of the other object).
|
137
|
+
#
|
138
|
+
def aT_not_equal other, what_is_receiver=nil, what_is_other=nil
|
139
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
140
|
+
"#{self.class} instance #{object_id}"
|
141
|
+
o = what_is_other || "the prescribed value (#{other.class})"
|
142
|
+
m = "#{r} fails to differ from #{o}!"
|
143
|
+
raise TErr, m if self == other
|
144
|
+
return self
|
145
|
+
end
|
146
|
+
|
147
|
+
# Fails with TypeError unless the ActiveSupport method #blank returns true
|
148
|
+
# for the receiver.
|
149
|
+
#
|
150
|
+
def aT_blank what_is_receiver=nil
|
151
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
152
|
+
"#{self.class} instance #{object_id}"
|
153
|
+
m = "#{r} fails to be #blank?!"
|
154
|
+
raise TErr, m unless blank?
|
155
|
+
return self
|
156
|
+
end
|
157
|
+
|
158
|
+
# Fails with TypeError unless the ActiveSupport method #present returns true
|
159
|
+
# for the receiver.
|
160
|
+
#
|
161
|
+
def aT_present what_is_receiver=nil
|
162
|
+
r = what_is_receiver ? what_is_receiver.to_s.capitalize :
|
163
|
+
"#{self.class} instance #{object_id}"
|
164
|
+
m = "#{r} fails to be #present?!"
|
165
|
+
raise TErr, m unless present?
|
166
|
+
return self
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def singleton_class_or_class
|
172
|
+
begin
|
173
|
+
self.singleton_class
|
174
|
+
rescue TypeError
|
175
|
+
self.class
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/object/typing'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'y_support'
|
4
|
+
|
5
|
+
# Typing library.
|
6
|
+
#
|
7
|
+
# Apart from Ruby default way of typing objects <em>by class and ancestry</em>,
|
8
|
+
# exemplified eg. by built-in #kind_of?, alias #is_a? inquirers, y_support
|
9
|
+
# typing library provides support for typing <em>by declaration</em>, and
|
10
|
+
# runtime assertions for <em>duck type</em> examination.
|
11
|
+
#
|
12
|
+
# 1. Using method <b>declare_compliance</b>, a module (class) can explicitly
|
13
|
+
# declare, that it provides an interface compliant with another module (class).
|
14
|
+
# Corresponding inquirer methods are <b>declared_compliance</b> (returns a list
|
15
|
+
# of modules, to which the receiver declares compliance, or implicitly complies
|
16
|
+
# by ancestry), and <b>declares_compliance?( other_module )</b>, which tells,
|
17
|
+
# whether the receiver complies with a specific module. An object always
|
18
|
+
# implicitly complies with its class and ancestry.
|
19
|
+
#
|
20
|
+
# 2. Duck type examination is supported by a collection of runtime assertions.
|
21
|
+
# These start with <b>tE_...</b>, meaning "enforce ... by raising TypeError".
|
22
|
+
#
|
23
|
+
class Object
|
24
|
+
# Alias for ArgumentError
|
25
|
+
#
|
26
|
+
AErr = ArgumentError
|
27
|
+
|
28
|
+
# Alias for TypeError
|
29
|
+
#
|
30
|
+
TErr = TypeError
|
31
|
+
end
|
32
|
+
|
33
|
+
directories_to_look_in = [ :typing ]
|
34
|
+
|
35
|
+
# The fololowing code looks into the specified directory(ies) and requires
|
36
|
+
# all the files in it (them).
|
37
|
+
#
|
38
|
+
directories_to_look_in.each do |part|
|
39
|
+
Dir["#{File.dirname( __FILE__ )}/#{part}/*/typing.rb"].sort.each { |path|
|
40
|
+
dir = File.dirname( path ).match( "y_support/#{part}" ).post_match
|
41
|
+
require "y_support/#{part}#{dir}/typing"
|
42
|
+
}
|
43
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'y_support'
|
4
|
+
|
5
|
+
# This library sets forth 4 standard abbreviations of Ruby keywords:
|
6
|
+
#
|
7
|
+
# * <b>ç</b> – class (c with cedilla, U00E7, compose seq. [c, comma])
|
8
|
+
# * <b>ⓒ</b> – singleton class (copyright sign, U00A9, compose seq. [(, c, )])
|
9
|
+
# * <b>λ</b> – lambda (Greek character lambda)
|
10
|
+
# * <b>Λ</b> – proc (Greek character capital lambda)
|
11
|
+
#
|
12
|
+
# It is also encouraged that other on-letter Unicode abbreviations are
|
13
|
+
# used especially for local variables:
|
14
|
+
#
|
15
|
+
# * <b>ɱ</b> – module (m with hook, U2C6E, compose seq. [m, j])
|
16
|
+
# * <b>ꜧ</b> – hash (latin small letter heng, UA727, compose seq. [h, j])
|
17
|
+
# * <b>ᴀ</b> – array (small capital A, U1D00, compose seq. [a, `])
|
18
|
+
# * <b>ß</b> – symbol (German sharp s, U00DF, compose seq. [s, s])
|
19
|
+
# * <b>ς</b> – string (Greek final sigma, U03C2, compose seq. [*, w])
|
20
|
+
# * <b>w</b> – abbreviation for "with"
|
21
|
+
# * <b>wo</b> – abbreviation for "without"
|
22
|
+
#
|
23
|
+
# There are, however, no defined methods using these in YSupport. In other
|
24
|
+
# words, using these additional abbreviations is completely up to the goodwill
|
25
|
+
# of the developer.
|
26
|
+
#
|
27
|
+
# ==== Note on compose sequences
|
28
|
+
#
|
29
|
+
# Each compose sequence has to be preceded by pressing the <compose> key.
|
30
|
+
# The compose sequences comply with the standard Kragen's .XCompose file
|
31
|
+
# (https://github.com/kragen/xcompose). In some cases, the needed characters
|
32
|
+
# are not in Kragen's file and need to be defined manually.
|
33
|
+
#
|
34
|
+
class Object
|
35
|
+
alias :ç :class
|
36
|
+
alias :ⓒ :singleton_class
|
37
|
+
alias :© :singleton_class
|
38
|
+
|
39
|
+
# Square root (proxy for Math.sqrt(x)).
|
40
|
+
#
|
41
|
+
def √( number ); Math.sqrt( number ) end
|
42
|
+
|
43
|
+
# Sum. The argument is expected to be a collection; block can be specified.
|
44
|
+
# Basically same as chaining .reduce( :+ ) to the end; Σ() notation can be
|
45
|
+
# more readable at times.
|
46
|
+
#
|
47
|
+
def ∑( collection )
|
48
|
+
collection.reduce { |acc, element|
|
49
|
+
acc + ( block_given? ? yield( element ) : element )
|
50
|
+
}
|
51
|
+
end
|
52
|
+
alias :Σ :∑
|
53
|
+
|
54
|
+
# Product. The argument is expected to be a collection; block can be specified.
|
55
|
+
# Basically same as chaining .reduce( :* ) to the end; Π() notation can be
|
56
|
+
# more readable at times.
|
57
|
+
#
|
58
|
+
def ∏( collection )
|
59
|
+
collection.reduce { |acc, element|
|
60
|
+
acc * ( block_given? ? yield( element ) : element )
|
61
|
+
}
|
62
|
+
end
|
63
|
+
alias :Π :∏
|
64
|
+
end
|
65
|
+
|
66
|
+
class Module
|
67
|
+
alias :ç_variable_set :class_variable_set
|
68
|
+
alias :ç_variable_get :class_variable_get
|
69
|
+
alias :ç_variable_defined? :class_variable_defined?
|
70
|
+
alias :remove_ç_variable :remove_class_variable
|
71
|
+
end
|
72
|
+
|
73
|
+
module Kernel
|
74
|
+
alias :λ :lambda
|
75
|
+
alias :Λ :proc
|
76
|
+
end
|
data/lib/y_support.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require "y_support/version"
|
4
|
+
|
5
|
+
# What follows is a commented-out list of interesting StdLibs. They may
|
6
|
+
# or may no be required in various parts of y_support.
|
7
|
+
#
|
8
|
+
# require 'matrix' # in stdlib_ext/matrix/misc.rb
|
9
|
+
# require 'mathn'
|
10
|
+
# require 'set'
|
11
|
+
# require 'csv'
|
12
|
+
|
13
|
+
# What follows is a commented-out list of interesting ActiveSupport parts.
|
14
|
+
# These may or may not be required in various parts of y_support.
|
15
|
+
#
|
16
|
+
# require 'active_support/core_ext/module/delegation'
|
17
|
+
# require 'active_support/core_ext/object/blank' # in object/misc.rb, string/misc.rb
|
18
|
+
# require 'active_support/core_ext/object/duplicable'
|
19
|
+
# require 'active_support/core_ext/string/starts_ends_with'
|
20
|
+
# require 'active_support/core_ext/string/strip'
|
21
|
+
# require 'active_support/core_ext/string/inflections' # in autoreq; module/misc.rb
|
22
|
+
# require 'active_support/core_ext/integer/multiple'
|
23
|
+
# require 'active_support/core_ext/integer/inflections'
|
24
|
+
# require 'active_support/core_ext/enumerable'
|
25
|
+
# require 'active_support/core_ext/array/extract_options'
|
26
|
+
# require 'active_support/core_ext/hash/conversions' # such as #to_xml
|
27
|
+
# require 'active_support/core_ext/hash/reverse_merge' # aliased in hash/misc.rb
|
28
|
+
# require 'active_support/core_ext/hash/deep_merge'
|
29
|
+
# require 'active_support/core_ext/hash/diff'
|
30
|
+
# require 'active_support/core_ext/hash/except'
|
31
|
+
# require 'active_support/core_ext/hash/keys'
|
32
|
+
# require 'active_support/core_ext/hash/slice'
|
33
|
+
# require 'active_support/core_ext/hash/indifferent_access'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'shoulda'
|
6
|
+
|
7
|
+
class YSupportTest < Test::Unit::TestCase
|
8
|
+
context "Object" do
|
9
|
+
setup do
|
10
|
+
require 'y_support/inert_recorder'
|
11
|
+
end
|
12
|
+
|
13
|
+
should "have #InertRecorder() constructor" do
|
14
|
+
assert_equal InertRecorder, InertRecorder( :bull ).class
|
15
|
+
end
|
16
|
+
end # context Object
|
17
|
+
|
18
|
+
context "InertRecorder" do
|
19
|
+
setup do
|
20
|
+
require 'y_support/inert_recorder'
|
21
|
+
end
|
22
|
+
|
23
|
+
should "InertRecorder exist and comply" do
|
24
|
+
n = InertRecorder.new
|
25
|
+
assert_equal [true, false], [n.present?, n.blank?]
|
26
|
+
assert_respond_to InertRecorder.new, :arbitrary_message
|
27
|
+
n = InertRecorder.new :x, :y
|
28
|
+
n.arbitrary_message( :a, :b ) { "hello" }
|
29
|
+
assert_equal [:x, :y], n.init_args
|
30
|
+
assert_equal [ :arbitrary_message, [:a, :b] ], n.recorded_messages[0][0..1]
|
31
|
+
assert_equal "hello", n.recorded_messages[0][2].call
|
32
|
+
end
|
33
|
+
end # context InertRecorder
|
34
|
+
end # class InertRecorderTest
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'shoulda'
|
6
|
+
|
7
|
+
class LocalObjectTest < Test::Unit::TestCase
|
8
|
+
context "Object" do
|
9
|
+
setup do
|
10
|
+
require 'y_support/local_object'
|
11
|
+
end
|
12
|
+
|
13
|
+
should "have constructor #LocalObject, alias #L!" do
|
14
|
+
assert_equal LocalObject, LocalObject().class
|
15
|
+
assert_equal LocalObject, L!.class
|
16
|
+
end
|
17
|
+
|
18
|
+
should "have #local_object?, alias #ℓ?" do
|
19
|
+
assert_equal false, Object.new.local_object?
|
20
|
+
assert_equal false, Object.new.ℓ?
|
21
|
+
end
|
22
|
+
end # context Object
|
23
|
+
|
24
|
+
context "LocalObject" do
|
25
|
+
setup do
|
26
|
+
require 'y_support/local_object'
|
27
|
+
end
|
28
|
+
|
29
|
+
should "exist and comply" do
|
30
|
+
n = LocalObject.new 'whatever'
|
31
|
+
assert ! n.ℓ?
|
32
|
+
assert n.ℓ? 'whatever'
|
33
|
+
assert_equal 'whatever', n.signature
|
34
|
+
assert_equal 'whatever', n.σ
|
35
|
+
end
|
36
|
+
end # context LocalObject
|
37
|
+
end # class LocalObjectTest
|