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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 39372bbe12e6643f53e78e2b4fd8666477554a67
|
4
|
+
data.tar.gz: 9d1c8f648ab7369104ba1ca178fe6ca4abec4cf7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7e3457d0f805683af3c83018bb7174b161868f614a77b90e7ecc022937ec9b4768fbbfc904717b97beb71dbe0f96296cac46fe60f52db06f89c80c9afa5ce755
|
7
|
+
data.tar.gz: 8a57a47dcb40f4c286ffcdf3ad19c0ccd3cd6a58bb32f7d32861701c6907c4734db0eb6e72b6490afcf43e8c2797b0661fda1e7166ed15267736729d45fb06b8
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 boris
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# YSupport
|
2
|
+
|
3
|
+
Common support library for Y* gems.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'y_support'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install y_support
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Require 'y_support/all', or require 'y_support/something', and use it.
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'y_support'
|
4
|
+
require 'y_support/name_magic'
|
5
|
+
require 'y_support/typing'
|
6
|
+
require 'y_support/unicode'
|
7
|
+
require 'y_support/respond_to'
|
8
|
+
require 'y_support/null_object'
|
9
|
+
require 'y_support/inert_recorder'
|
10
|
+
require 'y_support/local_object'
|
11
|
+
require 'y_support/misc'
|
12
|
+
|
13
|
+
|
14
|
+
# # Test me!
|
15
|
+
# class BlankSlate
|
16
|
+
# class << self
|
17
|
+
# # Hide the method named +name+ in the BlankSlate class. Don't
|
18
|
+
# # hide +instance_eval+ or any method beginning with "__".
|
19
|
+
# def hide( name )
|
20
|
+
# if instance_methods.include? name and
|
21
|
+
# name !~ /^(__|instance_eval)/
|
22
|
+
# @hidden_methods ||= {}
|
23
|
+
# @hidden_methods[name] = instance_method name
|
24
|
+
# undef_method name
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def find_hidden_method name
|
29
|
+
# @hidden_methods ||= {}
|
30
|
+
# @hidden_methods[name] || superclass.find_hidden_method( name )
|
31
|
+
# end
|
32
|
+
|
33
|
+
# # Redefine a previously hidden method
|
34
|
+
# def reveal name
|
35
|
+
# unbound_method = find_hidden_method name
|
36
|
+
# fail "Don't know how to reveal method '#{name}'" unless unbound_method
|
37
|
+
# define_method( name, unbound_method )
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
# end # class BlankSlate
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Array
|
2
|
+
# Converts an array, whose elements are also arrays, to a hash. Head
|
3
|
+
# (position 0) of each array is made to point at the rest of the array
|
4
|
+
# (tail), normally starting immediately after the head (position 1). The
|
5
|
+
# starting position of the tail can be controlled by an optional
|
6
|
+
# argument. Tails of 2 and more elements are represented as arrays.
|
7
|
+
#
|
8
|
+
def to_hash( tail_from = 1 )
|
9
|
+
self.reject { | e | e[0].nil? }.reduce({}) { |a, e|
|
10
|
+
tail = e[tail_from..-1]
|
11
|
+
a.merge( { e[0] => tail.size >= 2 ? tail : tail[0] } )
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Does things for each consecutive pair (expects a binary block).
|
16
|
+
#
|
17
|
+
def each_consecutive_pair
|
18
|
+
if block_given?
|
19
|
+
return self if ( n = self.size - 1 ) <= 0
|
20
|
+
n.times.with_index{|i| yield( self[i], self[i+1] ) }
|
21
|
+
return self
|
22
|
+
else
|
23
|
+
return Enumerator.new do |yielder|
|
24
|
+
n.times.with_index{|i| yielder << [ self[i], self[i+1] ] } unless
|
25
|
+
( n = self.size - 1 ) <= 0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Allows style &[ function, *arguments ]
|
31
|
+
#
|
32
|
+
def to_proc
|
33
|
+
proc { |receiver| receiver.send *self }
|
34
|
+
end # def to_proc
|
35
|
+
|
36
|
+
# TEST ME
|
37
|
+
# def pretty_inspect
|
38
|
+
# each_slice( 4 ) { |slice|
|
39
|
+
# slice.map { |e|
|
40
|
+
# str = e.to_s[0..25]
|
41
|
+
# str + ' ' * ( 30 - str.size )
|
42
|
+
# }.reduce( :+ ) + "\n"
|
43
|
+
# }.reduce( :+ )
|
44
|
+
# end
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/array/misc'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
module Enumerable
|
4
|
+
# Checks whether #all? collection elements are #kind_of? module
|
5
|
+
# supplied as an argument
|
6
|
+
#
|
7
|
+
def all_kind_of?( kind )
|
8
|
+
all? {|e| e.kind_of? kind }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Checks whether #all? collection elements are #kind_of? Numeric.
|
12
|
+
#
|
13
|
+
def all_numeric?
|
14
|
+
all? {|e| e.kind_of? Numeric }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Checks whether the receiver collection is fully included in the
|
18
|
+
# collection supplied as an argument.
|
19
|
+
#
|
20
|
+
def subset_of?( other_collection )
|
21
|
+
all? {|e| other_collection.include? e }
|
22
|
+
end
|
23
|
+
alias :⊂? :subset_of?
|
24
|
+
|
25
|
+
# Checks whether the receiver collection contains every element of
|
26
|
+
# the collection supplied as an argument.
|
27
|
+
#
|
28
|
+
def superset_of?( other_collection )
|
29
|
+
other.all? {|e| self.include? e }
|
30
|
+
end
|
31
|
+
alias :⊃? :superset_of?
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/enumerable/misc'
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
4
|
+
|
5
|
+
class Hash
|
6
|
+
# reversed merge!: defaults.merge( self! )
|
7
|
+
alias :default! :reverse_merge!
|
8
|
+
|
9
|
+
# Applies a block as a mapping on all keys, returning a new hash
|
10
|
+
def with_keys
|
11
|
+
keys.each_with_object self.class.new do |hash_key, ꜧ|
|
12
|
+
ꜧ[ yield( hash_key ) ] = self[ hash_key ]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
alias :do_with_keys :with_keys
|
16
|
+
|
17
|
+
# The difference from do_with_keys is that modify_keys expects block
|
18
|
+
# that takes 2 arguments (key: value pair) and returns the new key.
|
19
|
+
def modify_keys
|
20
|
+
each_with_object self.class.new do |hash_pair, ꜧ|
|
21
|
+
ꜧ[ yield( hash_pair ) ] = self[ hash_pair[0] ]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Applies a block as a mapping on all values, returning a new hash
|
26
|
+
def with_values
|
27
|
+
each_with_object self.class.new do |hash_pair, ꜧ|
|
28
|
+
ꜧ[ hash_pair[0] ] = yield( hash_pair[1] )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias :do_with_values :with_values
|
32
|
+
|
33
|
+
# Like #do_with_values, but modifies the receiver.
|
34
|
+
def with_values!
|
35
|
+
each_with_object self do |hash_pair, ꜧ|
|
36
|
+
hash_key, hash_val = hash_pair
|
37
|
+
ꜧ[ hash_key ] = yield( hash_val )
|
38
|
+
end
|
39
|
+
end
|
40
|
+
alias :do_with_values! :with_values!
|
41
|
+
|
42
|
+
# The difference from #do_with_values is that modify_values expects block
|
43
|
+
# that takes 2 arguments (key: value pair) and returns the new value.
|
44
|
+
def modify_values
|
45
|
+
each_with_object self.class.new do |hash_pair, ꜧ|
|
46
|
+
ꜧ[ hash_pair[0] ] = yield( hash_pair )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Like #modify_values, but modifies the receiver
|
51
|
+
def modify_values!
|
52
|
+
each_with_object self do |hash_pair, ꜧ|
|
53
|
+
ꜧ[ hash_pair[0] ] = yield( hash_pair )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Like #map that returns a hash.
|
58
|
+
def modify
|
59
|
+
each_with_object self.class.new do |hash_pair, ꜧ|
|
60
|
+
key, val = yield hash_pair
|
61
|
+
ꜧ[key] = val
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Makes hash keys accessible as methods. If the hash keys collide with
|
66
|
+
# its methods, ArgumentError is raised, unless :overwrite_methods
|
67
|
+
# option == true.
|
68
|
+
#
|
69
|
+
def dot!( oo = {} )
|
70
|
+
keys.each do |key|
|
71
|
+
msg = "key #{key} of #dot!-ted hash is not convertible to a symbol"
|
72
|
+
raise ArgumentError, msg unless key.respond_to? :to_sym
|
73
|
+
unless oo[:overwrite_methods]
|
74
|
+
if methods.include? key.to_sym
|
75
|
+
raise ArgumentError, "#dot!-ted hash must not have key names " +
|
76
|
+
"colliding with its methods"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
define_singleton_method key.to_sym do
|
81
|
+
self[key]
|
82
|
+
end
|
83
|
+
|
84
|
+
define_singleton_method "#{key}=".to_sym do |value|
|
85
|
+
self[key] = value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
return self
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/hash/misc'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
class Module
|
4
|
+
# Further automation of soon-to-be-deprecated #autorequire.
|
5
|
+
#
|
6
|
+
def autoreq( *symbols, descending_path: '..', ascending_path_prefix: 'lib' )
|
7
|
+
|
8
|
+
require 'active_support/core_ext/string/inflections'
|
9
|
+
|
10
|
+
namespace = self.name
|
11
|
+
namespace_path = namespace.underscore
|
12
|
+
namespace_chain = namespace.split "::"
|
13
|
+
ascending_path = ascending_path_prefix + '/' + namespace_path
|
14
|
+
symbols.map( &:to_s ).each { |ς|
|
15
|
+
next if ς.strip.empty?
|
16
|
+
camelized_ß = ς.camelize.to_sym
|
17
|
+
path = './' + [ descending_path, ascending_path, ς ].join( '/' )
|
18
|
+
autoload camelized_ß, path
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# I didn't write this method by myself.
|
23
|
+
#
|
24
|
+
def attr_accessor_with_default *symbols, &block
|
25
|
+
raise ArgumentError, 'Block with default value required!' unless block
|
26
|
+
symbols.each { |ß|
|
27
|
+
module_eval {
|
28
|
+
define_method "#{ß}=" do |arg|
|
29
|
+
instance_variable_set "@#{ß}", arg
|
30
|
+
end
|
31
|
+
define_method ß do
|
32
|
+
singleton_class.class_eval { attr_reader ß }
|
33
|
+
if instance_variables.include? "@#{ß}".to_sym then
|
34
|
+
instance_variable_get "@#{ß}"
|
35
|
+
else
|
36
|
+
instance_variable_set "@#{ß}", block.call
|
37
|
+
end
|
38
|
+
end
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
alias :attr_accessor_w_default :attr_accessor_with_default
|
43
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/numeric/misc'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
class Object
|
4
|
+
def const_set_if_not_defined( const, value )
|
5
|
+
mod = self.is_a?(Module) ? self : self.singleton_class
|
6
|
+
mod.const_set( const, value ) unless mod.const_defined?( const )
|
7
|
+
end
|
8
|
+
|
9
|
+
def const_redefine_without_warning( const, value )
|
10
|
+
mod = self.is_a?(Module) ? self : self.singleton_class
|
11
|
+
mod.send(:remove_const, const) if mod.const_defined?( const )
|
12
|
+
mod.const_set( const, value )
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create public attributes (ie. with readers) and initialize them with
|
16
|
+
# prescribed values. Takes a hash of { symbol => value } pairs. Existing methods
|
17
|
+
# are not overwritten by the new getters, unless option :overwrite_methods
|
18
|
+
# is set to true.
|
19
|
+
def singleton_set_attr_with_readers( hash, oo = {} )
|
20
|
+
hash.each { |key, val|
|
21
|
+
key = key.aE_respond_to( :to_sym, "key of the attr hash" ).to_sym
|
22
|
+
instance_variable_set( "@#{key}", val )
|
23
|
+
if oo[:overwrite_methods] then ⓒ.module_exec { attr_reader key }
|
24
|
+
elsif methods.include? key
|
25
|
+
raise "Attempt to add \##{key} getter failed: " +
|
26
|
+
"method \##{key} already defined."
|
27
|
+
else ⓒ.module_exec { attr_reader key } end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
alias :ⓒ_set_attr_w_readers :singleton_set_attr_with_readers
|
31
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/object/misc'
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
|
5
|
+
class String
|
6
|
+
# Integer() style conversion, or false if conversion impossible.
|
7
|
+
#
|
8
|
+
def to_Integer
|
9
|
+
begin
|
10
|
+
int = Integer stripn
|
11
|
+
return int
|
12
|
+
rescue ArgumentError
|
13
|
+
return false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Float() style conversion, or false if conversion impossible.
|
18
|
+
#
|
19
|
+
def to_Float
|
20
|
+
begin
|
21
|
+
fl = Float stripn
|
22
|
+
return fl
|
23
|
+
rescue ArgumentError
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Like #strip, but also strips newlines.
|
29
|
+
#
|
30
|
+
def stripn
|
31
|
+
encode( universal_newline: true )
|
32
|
+
.gsub("\n", "")
|
33
|
+
.strip
|
34
|
+
end
|
35
|
+
|
36
|
+
# Joins a paragraph of possibly indented, newline separated lines into a
|
37
|
+
# single contiguous string.
|
38
|
+
#
|
39
|
+
def wring_heredoc
|
40
|
+
encode(universal_newline: true)
|
41
|
+
.split("\n") # split into lines
|
42
|
+
.map( &:strip ) # strip them
|
43
|
+
.delete_if( &:blank? ) # delete blank lines
|
44
|
+
.join " " # and join with whitspace
|
45
|
+
end
|
46
|
+
|
47
|
+
# If the string is empty, it gets replace with the string given as argument.
|
48
|
+
#
|
49
|
+
def default! default_string
|
50
|
+
strip.empty? ? clear << default_string.to_s : self
|
51
|
+
end
|
52
|
+
|
53
|
+
# As it says – replaces spaces with underscores.
|
54
|
+
#
|
55
|
+
def underscore_spaces
|
56
|
+
gsub ' ', '_'
|
57
|
+
end
|
58
|
+
|
59
|
+
# Converts a string into a standard symbol. While Symbol class objects can
|
60
|
+
# be created from any string, it is good practice to keep symbols free of
|
61
|
+
# whitespaces and weird characters, so that the are typed easily, usable as
|
62
|
+
# variable names etc. This method thus removes punctuation, removes
|
63
|
+
# superfluous spaces, and underscores the remaining ones, before returning
|
64
|
+
# the string.
|
65
|
+
#
|
66
|
+
def standardize
|
67
|
+
ς = self.dup
|
68
|
+
",.;".each_char { |c| ς.gsub! c, " " }
|
69
|
+
ς.stripn
|
70
|
+
.squeeze(" ")
|
71
|
+
.underscore_spaces
|
72
|
+
end
|
73
|
+
|
74
|
+
# Applies #standardize to the receiver and converts the result to a symbol.
|
75
|
+
#
|
76
|
+
def to_standardized_sym
|
77
|
+
standardize
|
78
|
+
.to_sym
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/string/misc'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
class Symbol
|
3
|
+
# This method applies String#default! method to the receiver converted to
|
4
|
+
# a string. Of course, symbols are immutable, so in spite of the exclamation
|
5
|
+
# mark in the method name, a new symbol (supplied as argument) is returned,
|
6
|
+
# if the original one is considered "defaulted" (otherwise, original symbol
|
7
|
+
# is returned unchanged).
|
8
|
+
#
|
9
|
+
def default! default_symbol
|
10
|
+
to_s.default!( default_symbol ).to_sym
|
11
|
+
end
|
12
|
+
|
13
|
+
# Applies String#to_standardized_sym method to the recevier converted to a
|
14
|
+
# string.
|
15
|
+
#
|
16
|
+
def to_standardized_sym
|
17
|
+
to_s.to_standardized_sym
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'y_support/core_ext/symbol/misc'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'y_support'
|
4
|
+
|
5
|
+
# Inert recorder is similar to a null object in the sense, that in response to
|
6
|
+
# almost all messages it returns self. But in addition, it records received
|
7
|
+
# messages along with their arguments and blocks (if given). Recoded messages
|
8
|
+
# are available via #recorded_messages reader, aliased #ρ (small Greek rho).
|
9
|
+
# Inert recorder does not require any arguments for initalization, but if they
|
10
|
+
# are supplied, they are silently recoded into @init_args (for arguments) and
|
11
|
+
# @init_block (for block, if given) instance variables, exposed via standard
|
12
|
+
# readers.
|
13
|
+
#
|
14
|
+
class InertRecorder
|
15
|
+
attr_reader :init_args, :init_block, :recorded_messages
|
16
|
+
alias ρ recorded_messages
|
17
|
+
|
18
|
+
# No arguments are required for initialization, but if they are supplied, they
|
19
|
+
# are silently recorded into @init_args (for argument array) and @init_block
|
20
|
+
# (for block, if given) instance variables, exposed via standard readers.
|
21
|
+
#
|
22
|
+
def initialize *args, &block
|
23
|
+
@init_args = args
|
24
|
+
@init_block = block
|
25
|
+
@recorded_messages = []
|
26
|
+
end
|
27
|
+
|
28
|
+
# Always true.
|
29
|
+
#
|
30
|
+
def present?; true end
|
31
|
+
|
32
|
+
# Always false.
|
33
|
+
#
|
34
|
+
def blank?; false end
|
35
|
+
|
36
|
+
# Always true.
|
37
|
+
#
|
38
|
+
def respond_to? ß, *args, █ true end
|
39
|
+
|
40
|
+
def method_missing ß, *args, &block # :nodoc:
|
41
|
+
@recorded_messages << [ ß, args, block ]
|
42
|
+
return self
|
43
|
+
end
|
44
|
+
end # class InertRecorder
|
45
|
+
|
46
|
+
|
47
|
+
class Object
|
48
|
+
# InertRecorder constructor.
|
49
|
+
#
|
50
|
+
def InertRecorder *args, █ InertRecorder.new *args, &block end
|
51
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'y_support'
|
4
|
+
|
5
|
+
# Object, whose business is to stay local to methods. Optional signature
|
6
|
+
# provides additional level of safety in ensuring object locality. (Signature
|
7
|
+
# accessor is :signature, aliased as :σ (small Greek sigma).)
|
8
|
+
#
|
9
|
+
class LocalObject
|
10
|
+
attr_reader :signature
|
11
|
+
alias σ signature
|
12
|
+
|
13
|
+
# Optional argument signature provides additional level of safety in
|
14
|
+
# ascertaining that the object indeed is of local origin.
|
15
|
+
#
|
16
|
+
def initialize signature=__callee__
|
17
|
+
@signature=signature
|
18
|
+
end
|
19
|
+
|
20
|
+
# True if the (optional) signature matches.
|
21
|
+
#
|
22
|
+
def local_object? signature=__callee__
|
23
|
+
signature == self.signature
|
24
|
+
end
|
25
|
+
alias ℓ? local_object?
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
class Object
|
30
|
+
# LocalObject constructor.
|
31
|
+
#
|
32
|
+
def LocalObject signature=nil; LocalObject.new signature end
|
33
|
+
alias L! LocalObject
|
34
|
+
|
35
|
+
# False for normal objects, overriden in the LocalObject class.
|
36
|
+
#
|
37
|
+
def local_object? signature=nil; false end
|
38
|
+
alias ℓ? local_object?
|
39
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require 'y_support'
|
3
|
+
|
4
|
+
# Typing library.
|
5
|
+
#
|
6
|
+
# Apart from usual <em>typing by class and ancestry</em>, supported by built-in
|
7
|
+
# #kind_of?, alias #is_a? inquirerers, this typing library provides support for
|
8
|
+
# provides support for <em>typing by declaration</em> and <em>duck typing</em>.
|
9
|
+
#
|
10
|
+
# 1. Using method <b>declare_compliance</b>, a module can explicitly declare that
|
11
|
+
# it provides the interface compliant with another module. Corresponding inquirer
|
12
|
+
# methods are <b>declared_compliance</b> (returning a list of modules with which
|
13
|
+
# the receiver declares compliance or implicitly complies) and
|
14
|
+
# <b>declares_compliance?( other_module )</b>, which anwers whether the receiver
|
15
|
+
# complies with other_module. An object always implicitly complies with its class
|
16
|
+
# and class ancestry.
|
17
|
+
#
|
18
|
+
# 2. Duck type enforcement for method parameters is supported by a collection of
|
19
|
+
# enforcer methods (aka. run-time assertions). These methods look very much like
|
20
|
+
# assertions, but they start with <b>tE_...</b>, meaning "enforce by raising
|
21
|
+
# TypeError".
|
22
|
+
|
23
|
+
[ :core_ext, :stdlib_ext ].each do |ext|
|
24
|
+
Dir["#{File.dirname( __FILE__ )}/#{ext}/*/misc.rb"].sort.each { |path|
|
25
|
+
dir = File.dirname( path ).match( "y_support/#{ext}" ).post_match
|
26
|
+
require "y_support/#{ext}#{dir}/misc"
|
27
|
+
}
|
28
|
+
end
|