facets 2.8.2 → 2.8.3
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.
- data/AUTHORS +13 -11
- data/HISTORY.rdoc +58 -0
- data/lib/core/facets/array/recursive.rb +91 -0
- data/lib/core/facets/array/recursively.rb +2 -2
- data/lib/core/facets/array/traverse.rb +23 -6
- data/lib/core/facets/enumerable/collisions.rb +1 -0
- data/lib/core/facets/enumerable/commonality.rb +4 -2
- data/lib/core/facets/enumerable/graph.rb +37 -1
- data/lib/core/facets/enumerable/mash.rb +1 -39
- data/lib/core/facets/enumerable/recursive.rb +75 -0
- data/lib/core/facets/enumerable/visit.rb +30 -0
- data/lib/core/facets/file/ext.rb +36 -0
- data/lib/core/facets/hash/graph.rb +18 -0
- data/lib/core/facets/hash/mash.rb +1 -18
- data/lib/core/facets/hash/recursive.rb +180 -0
- data/lib/core/facets/hash/recursive_merge.rb +6 -0
- data/lib/core/facets/hash/recursively.rb +2 -2
- data/lib/core/facets/hash/to_module.rb +26 -0
- data/lib/core/facets/hash/to_proc.rb +2 -2
- data/lib/core/facets/hash/traverse.rb +19 -13
- data/lib/core/facets/kernel/assign.rb +63 -0
- data/lib/core/facets/kernel/assign_from.rb +45 -0
- data/lib/core/facets/kernel/dup.rb +63 -0
- data/lib/core/facets/kernel/instance.rb +156 -0
- data/lib/core/facets/kernel/instance_assign.rb +1 -22
- data/lib/core/facets/kernel/meta_def.rb +4 -0
- data/lib/core/facets/kernel/populate.rb +1 -74
- data/lib/core/facets/kernel/set_from.rb +2 -0
- data/lib/core/facets/kernel/try_dup.rb +1 -0
- data/lib/core/facets/module/set.rb +36 -0
- data/lib/core/facets/objectspace/reflect.rb +45 -0
- data/lib/core/facets/struct/attributes.rb +6 -2
- data/lib/core/facets/symbol/op_div.rb +19 -0
- data/lib/core/facets/to_hash.rb +12 -0
- data/lib/more/facets/casting_hash.rb +172 -0
- data/lib/more/facets/pathname.rb +36 -0
- data/lib/more/facets/prepend.rb +57 -0
- data/lib/more/facets/random.rb +19 -3
- data/lib/more/facets/roman.rb +46 -153
- data/lib/more/facets/stash.rb +148 -33
- data/meta/released +1 -1
- data/meta/version +1 -1
- data/test/core/array/test_recursive.rb +18 -0
- data/test/core/enumerable/test_recursive.rb +18 -0
- data/test/core/file/test_ext.rb +31 -0
- data/test/core/hash/test_recursive.rb +23 -0
- data/test/core/hash/test_to_module.rb +21 -0
- data/test/core/kernel/test_assign.rb +57 -0
- data/test/core/kernel/test_assign_from.rb +20 -0
- data/test/more/test_prepend.rb +28 -0
- data/test/more/test_random.rb +40 -4
- metadata +39 -10
- data/lib/core/facets/kernel/instance_variables.rb +0 -97
- data/lib/more/facets/instance_eval.rb +0 -50
- data/lib/more/facets/ioredirect.rb +0 -77
- data/lib/more/facets/plugin_manager.rb +0 -50
- data/test/core/kernel/test_populate.rb +0 -46
@@ -0,0 +1,36 @@
|
|
1
|
+
class File
|
2
|
+
|
3
|
+
# Takes a file name string and returns or changes its extension.
|
4
|
+
#
|
5
|
+
# Without a new extension argument, returns the extension of the
|
6
|
+
# file name. In this respect #ext is like #extname, but unlike
|
7
|
+
# #extname it does not include the dot prefix.
|
8
|
+
#
|
9
|
+
# With a new extension argument, changes the exension of the file
|
10
|
+
# name to the new extension and returns it.
|
11
|
+
#
|
12
|
+
# Examples:
|
13
|
+
#
|
14
|
+
# File.ext('file.rb') => 'rb'
|
15
|
+
# File.ext('file.rb', 'txt') => 'file.txt'
|
16
|
+
# File.ext('file.rb', '.txt') => 'file.txt'
|
17
|
+
# File.ext('file.rb', '') => 'file'
|
18
|
+
#
|
19
|
+
# This method can be used with String#file for more object-oriented notation.
|
20
|
+
#
|
21
|
+
# 'file.rb'.file.ext('txt') => 'file.txt'
|
22
|
+
#
|
23
|
+
# CREDIT: Lavir the Whiolet
|
24
|
+
|
25
|
+
def self.ext(filename, new_ext=nil)
|
26
|
+
old_ext = extname(filename)
|
27
|
+
if new_ext == nil
|
28
|
+
old_ext.sub(/^\./, '')
|
29
|
+
else
|
30
|
+
new_ext = '.' + new_ext unless (new_ext.empty? || new_ext[0,1] == '.')
|
31
|
+
filename.chomp(old_ext) + new_ext
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'facets/enumerable/mash'
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
|
5
|
+
# In place version of #graph.
|
6
|
+
#
|
7
|
+
# NOTE: Hash#graph! is only useful for Hash.
|
8
|
+
# It is not generally applicable to Enumerable.
|
9
|
+
|
10
|
+
def graph!(&yld)
|
11
|
+
replace(graph(&yld))
|
12
|
+
end
|
13
|
+
|
14
|
+
# Alias for #graph! as an alliteration for "map hash".
|
15
|
+
alias_method :mash!, :graph!
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -1,18 +1 @@
|
|
1
|
-
require 'facets/
|
2
|
-
|
3
|
-
class Hash
|
4
|
-
|
5
|
-
# In place version of #mash.
|
6
|
-
#
|
7
|
-
# NOTE: Hash#mash! is only useful for Hash. It is not generally
|
8
|
-
# applicable to Enumerable.
|
9
|
-
|
10
|
-
def mash!(&yld)
|
11
|
-
replace(mash(&yld))
|
12
|
-
end
|
13
|
-
|
14
|
-
# Alias for #mash!. This is the original name for this method.
|
15
|
-
alias_method :graph!, :mash!
|
16
|
-
|
17
|
-
end
|
18
|
-
|
1
|
+
require 'facets/hash/graph'
|
@@ -0,0 +1,180 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
# Apply a block to hash, and recursively apply that block
|
4
|
+
# to each subhash.
|
5
|
+
#
|
6
|
+
# h = {:a=>1, :b=>{:b1=>1, :b2=>2}}
|
7
|
+
# h.recursively{|h| h.rekey(&:to_s) }
|
8
|
+
# => {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}}
|
9
|
+
#
|
10
|
+
def recursive(opts={}, &block)
|
11
|
+
if block
|
12
|
+
h = inject({}) do |hash, (key, value)|
|
13
|
+
if value.is_a?(Hash)
|
14
|
+
hash[key] = value.recursive(&block)
|
15
|
+
else
|
16
|
+
hash[key] = value
|
17
|
+
end
|
18
|
+
hash
|
19
|
+
end
|
20
|
+
yield h
|
21
|
+
else
|
22
|
+
Recursor.new(self, opts)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
|
28
|
+
def recursive!(&block)
|
29
|
+
r = recursive(&block)
|
30
|
+
raise TypeError unless Hash === r
|
31
|
+
replace(r)
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
class Recursor
|
36
|
+
|
37
|
+
#
|
38
|
+
def initialize(enum, opts)
|
39
|
+
@enum = enum
|
40
|
+
@opts = opts
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns a new hash created by traversing the hash and its subhashes,
|
44
|
+
# executing the given block on the key and value. The block should
|
45
|
+
# return a 2-element array of the form +[key, value]+.
|
46
|
+
#
|
47
|
+
# h = { "A"=>"A", "B"=>"B", { "X"=>"X" } }
|
48
|
+
#
|
49
|
+
# h.recursive_each{ |k,v| p [k.downcase, v] }
|
50
|
+
#
|
51
|
+
# produces
|
52
|
+
#
|
53
|
+
# ["a", "A"]
|
54
|
+
# ["b", "B"]
|
55
|
+
# ["x", "X"]
|
56
|
+
#
|
57
|
+
# CREDIT: Trans
|
58
|
+
|
59
|
+
def each(&block)
|
60
|
+
@enum.each do |k,v|
|
61
|
+
if Hash === v
|
62
|
+
v = v.recursive.each(&block)
|
63
|
+
elsif v.respond_to?(:to_hash)
|
64
|
+
v = v.to_hash.recursive.each(&block)
|
65
|
+
end
|
66
|
+
block.call(k,v)
|
67
|
+
end
|
68
|
+
#@enum.each do |k,v|
|
69
|
+
# if Hash === v
|
70
|
+
# v.recursive.each(&block)
|
71
|
+
# else
|
72
|
+
# block.call(k,v)
|
73
|
+
# end
|
74
|
+
#end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns a new hash created by traversing the hash and its subhashes,
|
78
|
+
# executing the given block on the key and value. The block should
|
79
|
+
# return a 2-element array of the form +[key, value]+.
|
80
|
+
#
|
81
|
+
# h = { "A"=>"A", "B"=>"B", { "X"=>"X" } }
|
82
|
+
#
|
83
|
+
# g = h.recursive_map{ |k,v| [k.downcase, v] }
|
84
|
+
#
|
85
|
+
# g #=> [["a", "A"], ["b", "B"], [["x", "X"]]]
|
86
|
+
#
|
87
|
+
# CREDIT: Trans
|
88
|
+
|
89
|
+
def map(&block)
|
90
|
+
@enum.inject([]) do |a,(k,v)|
|
91
|
+
if Hash === v
|
92
|
+
v = v.recursive.map(&block)
|
93
|
+
elsif v.respond_to?(:to_hash)
|
94
|
+
v = v.to_hash.recursive.map(&block)
|
95
|
+
end
|
96
|
+
nk, nv = block.call(k,v)
|
97
|
+
a << [nk, nv]
|
98
|
+
a
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# In-place rendition of #recursive_map.
|
103
|
+
|
104
|
+
def map!(&b)
|
105
|
+
@enum.replace(map(&b))
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns a new hash created by traversing the hash and its subhashes,
|
109
|
+
# executing the given block on the key and value. The block should
|
110
|
+
# return a 2-element array of the form +[key, value]+.
|
111
|
+
#
|
112
|
+
# h = {"A"=>"A", "B"=>"B", {"X"=>"X"}}
|
113
|
+
#
|
114
|
+
# g = h.recursive_graph{ |k,v| [k.downcase, v] }
|
115
|
+
#
|
116
|
+
# g #=> {"a"=>"A", "b"=>"B", {"x"=>"X"}}
|
117
|
+
#
|
118
|
+
# CREDIT: Trans
|
119
|
+
|
120
|
+
def graph(&block)
|
121
|
+
@enum.inject({}) do |h,(k,v)|
|
122
|
+
if Hash === v
|
123
|
+
v = v.recursive.graph(&block)
|
124
|
+
elsif v.respond_to?(:to_hash)
|
125
|
+
v = v.to_hash.recursive.graph(&block)
|
126
|
+
end
|
127
|
+
nk, nv = block.call(k,v)
|
128
|
+
h[nk] = nv
|
129
|
+
h
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# In place version of traverse, which traverses the hash and its
|
134
|
+
# subhashes, executing the given block on the key and value.
|
135
|
+
#
|
136
|
+
# h = { "A"=>"A", "B"=>"B" }
|
137
|
+
#
|
138
|
+
# h.traverse! { |k,v| [k.downcase, v] }
|
139
|
+
#
|
140
|
+
# h #=> { "a"=>"A", "b"=>"B" }
|
141
|
+
#
|
142
|
+
# CREDIT: Trans
|
143
|
+
|
144
|
+
def graph!(&block)
|
145
|
+
@enum.replace(graph(&block))
|
146
|
+
end
|
147
|
+
|
148
|
+
# Same as Hash#merge but recursively merges sub-hashes.
|
149
|
+
|
150
|
+
def merge(other)
|
151
|
+
hash = @enum.dup
|
152
|
+
other.each do |key, value|
|
153
|
+
myval = @enum[key]
|
154
|
+
if value.is_a?(Hash) && myval.is_a?(Hash)
|
155
|
+
hash[key] = myval.recursive.merge(value)
|
156
|
+
else
|
157
|
+
hash[key] = value
|
158
|
+
end
|
159
|
+
end
|
160
|
+
hash
|
161
|
+
end
|
162
|
+
|
163
|
+
# Same as Hash#merge! but recursively merges sub-hashes.
|
164
|
+
|
165
|
+
def merge!(other)
|
166
|
+
other.each do |key, value|
|
167
|
+
myval = @enum[key]
|
168
|
+
if value.is_a?(Hash) && myval.is_a?(Hash)
|
169
|
+
myval.recursive.merge!(value)
|
170
|
+
else
|
171
|
+
@enum[key] = value
|
172
|
+
end
|
173
|
+
end
|
174
|
+
@enum
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
@@ -1,6 +1,9 @@
|
|
1
1
|
class Hash
|
2
2
|
|
3
3
|
# Same as Hash#merge but recursively merges sub-hashes.
|
4
|
+
#
|
5
|
+
# DEPRECATE: This method will be deprecated in favor of
|
6
|
+
# <code>recursive.merge</code>.
|
4
7
|
|
5
8
|
def recursive_merge(other)
|
6
9
|
hash = self.dup
|
@@ -16,6 +19,9 @@ class Hash
|
|
16
19
|
end
|
17
20
|
|
18
21
|
# Same as Hash#merge! but recursively merges sub-hashes.
|
22
|
+
#
|
23
|
+
# DEPRECATE: This method will be deprecated in favor of
|
24
|
+
# <code>recursive.merge!</code>.
|
19
25
|
|
20
26
|
def recursive_merge!(other)
|
21
27
|
other.each do |key, value|
|
@@ -8,6 +8,7 @@ class Hash
|
|
8
8
|
# => {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}}
|
9
9
|
#
|
10
10
|
def recursively(&block)
|
11
|
+
warn "Use #recusive instead of #recursively for future versions"
|
11
12
|
h = inject({}) do |hash, (key, value)|
|
12
13
|
if value.is_a?(Hash)
|
13
14
|
hash[key] = value.recursively(&block)
|
@@ -19,11 +20,10 @@ class Hash
|
|
19
20
|
yield h
|
20
21
|
end
|
21
22
|
|
22
|
-
#
|
23
|
+
# In place form of #recursively.
|
23
24
|
|
24
25
|
def recursively!(&block)
|
25
26
|
replace(recursively(&block))
|
26
27
|
end
|
27
28
|
|
28
29
|
end
|
29
|
-
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
# Convert a hash into a mixin.
|
4
|
+
#
|
5
|
+
# CREDIT: Jay Fields
|
6
|
+
#
|
7
|
+
#--
|
8
|
+
# TODO: Consider #to_object option.
|
9
|
+
#++
|
10
|
+
|
11
|
+
def to_module
|
12
|
+
hash = self
|
13
|
+
Module.new do
|
14
|
+
hash.each do |key, value|
|
15
|
+
define_method key do
|
16
|
+
value #.to_object
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
#def to_object
|
23
|
+
# Object.new.extend(to_module)
|
24
|
+
#end
|
25
|
+
end
|
26
|
+
|
@@ -24,11 +24,11 @@ class Hash
|
|
24
24
|
# A fault-tolerent version of #to_proc.
|
25
25
|
#
|
26
26
|
# It works just like #to_proc, but the block will make
|
27
|
-
# sure
|
27
|
+
# sure the object responds to the assignment.
|
28
28
|
#
|
29
29
|
# CREDIT: Trans
|
30
30
|
|
31
|
-
def
|
31
|
+
def to_proc_with_response
|
32
32
|
lambda do |o|
|
33
33
|
self.each do |k,v|
|
34
34
|
ke = "#{k}="
|
@@ -4,22 +4,26 @@ class Hash
|
|
4
4
|
# executing the given block on the key and value. The block should
|
5
5
|
# return a 2-element array of the form +[key, value]+.
|
6
6
|
#
|
7
|
-
# h = {
|
8
|
-
#
|
9
|
-
# g
|
7
|
+
# h = {"A"=>"A", "B"=>"B", {"X"=>"X"}}
|
8
|
+
#
|
9
|
+
# g = h.traverse{ |k,v| [k.downcase, v] }
|
10
10
|
#
|
11
|
-
#
|
11
|
+
# g #=> {"a"=>"A", "b"=>"B", {"x"=>"X"}}
|
12
12
|
#
|
13
|
-
#
|
14
|
-
#
|
13
|
+
# NOTE: Hash#traverse is the same as <code>recursive.graph</code> and
|
14
|
+
# will likely be deprecated in the future because of it.
|
15
15
|
#
|
16
16
|
# CREDIT: Trans
|
17
17
|
|
18
|
-
def traverse(&
|
18
|
+
def traverse(&block)
|
19
19
|
inject({}) do |h,(k,v)|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
if Hash === v
|
21
|
+
v = v.traverse(&block)
|
22
|
+
elsif v.respond_to?(:to_hash)
|
23
|
+
v = v.to_hash.traverse(&block)
|
24
|
+
end
|
25
|
+
nk, nv = block.call(k,v)
|
26
|
+
h[nk] = nv
|
23
27
|
h
|
24
28
|
end
|
25
29
|
end
|
@@ -28,13 +32,15 @@ class Hash
|
|
28
32
|
# subhashes, executing the given block on the key and value.
|
29
33
|
#
|
30
34
|
# h = { "A"=>"A", "B"=>"B" }
|
31
|
-
#
|
35
|
+
#
|
36
|
+
# h.traverse!{ |k,v| [k.downcase, v] }
|
37
|
+
#
|
32
38
|
# h #=> { "a"=>"A", "b"=>"B" }
|
33
39
|
#
|
34
40
|
# CREDIT: Trans
|
35
41
|
|
36
|
-
def traverse!(&
|
37
|
-
|
42
|
+
def traverse!(&block)
|
43
|
+
replace(traverse(&block))
|
38
44
|
end
|
39
45
|
|
40
46
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Kernel
|
2
|
+
|
3
|
+
# Assign via writer using a arguments, hash or
|
4
|
+
# associative array, and son on, or assign via
|
5
|
+
# a block.
|
6
|
+
#
|
7
|
+
# Using name-value arguments:
|
8
|
+
#
|
9
|
+
# object.assign(:a, 1)
|
10
|
+
# object.assign(:b, 2)
|
11
|
+
#
|
12
|
+
# Using a hash:
|
13
|
+
#
|
14
|
+
# object.assign( :a => 1, :b => 2 )
|
15
|
+
#
|
16
|
+
# Use an associative array:
|
17
|
+
#
|
18
|
+
# object.assign( [[:a, 1], [:b, 2]] )
|
19
|
+
#
|
20
|
+
# Using a block:
|
21
|
+
#
|
22
|
+
# object.assign do |s|
|
23
|
+
# s.a = 1
|
24
|
+
# s.b = 2
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# These are all equivalent to:
|
28
|
+
#
|
29
|
+
# object.a = 1
|
30
|
+
# object.b = 2
|
31
|
+
#
|
32
|
+
# Unless assigned via a block, undefined setters will not
|
33
|
+
# raise an error if they do not exist. They will simply be
|
34
|
+
# skipped.
|
35
|
+
#
|
36
|
+
# Using an associative array instead of hash guarentees
|
37
|
+
# order of assignemnt for older versions of Ruby (< 1.8.7).
|
38
|
+
#
|
39
|
+
# TODO: Should this be called #set instead? Consider
|
40
|
+
# Module#set in this question, and also #set_from as
|
41
|
+
# the alias of #assign_from.
|
42
|
+
|
43
|
+
def assign(data=nil, value=Exception) #:yield:
|
44
|
+
if data
|
45
|
+
if value==Exception
|
46
|
+
data.each do |(k,v)|
|
47
|
+
__send__("#{k}=", v) if respond_to?("#{k}=")
|
48
|
+
end
|
49
|
+
else
|
50
|
+
__send__("#{data}=", value) if respond_to?("#{data}=")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
yield(self) if block_given?
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# DEPRECATE: Use #assign instead.
|
58
|
+
def populate(*a,&b)
|
59
|
+
warn 'use #assign instead of #populate for future versions'
|
60
|
+
assign(*a,&b)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|