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,45 @@
|
|
1
|
+
module Kernel
|
2
|
+
|
3
|
+
# Set attribute writers using like readers
|
4
|
+
# from another object.
|
5
|
+
#
|
6
|
+
# class X
|
7
|
+
# attr_accessor :a, :b
|
8
|
+
# def initialize( a, b )
|
9
|
+
# @a,@b = a,b
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# obj1 = X.new(1, 2)
|
14
|
+
# obj2 = X.new
|
15
|
+
#
|
16
|
+
# obj2.assign_from(obj1)
|
17
|
+
#
|
18
|
+
# obj2.a #=> 1
|
19
|
+
# obj2.b #=> 2
|
20
|
+
#
|
21
|
+
# TODO: Should this be called #set_from ?
|
22
|
+
|
23
|
+
def assign_from(obj, *fields)
|
24
|
+
unless fields.empty?
|
25
|
+
fields.each do |k|
|
26
|
+
send( "#{k}=", obj.send("#{k}") ) #if self.respond_to?("#{k}=") && obj.respond_to?("#{k}")
|
27
|
+
end
|
28
|
+
else
|
29
|
+
setters = methods.collect { |m| m =~ /=$/ }
|
30
|
+
setters.each do |setter|
|
31
|
+
getter = setter.chomp('=')
|
32
|
+
if obj.respond_to?(getter)
|
33
|
+
send( setter, obj.send(getter) )
|
34
|
+
fields < getter
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
fields
|
39
|
+
end
|
40
|
+
|
41
|
+
# Original name for #assign_from.
|
42
|
+
alias_method :set_from, :assign_from
|
43
|
+
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Kernel
|
2
|
+
# Override this in a child class if it cannot be dup'ed.
|
3
|
+
#
|
4
|
+
# CREDIT: Dan Kubb (extlib)
|
5
|
+
def dup!
|
6
|
+
dup
|
7
|
+
end
|
8
|
+
|
9
|
+
# Original name for dup! as defined by extlib.
|
10
|
+
# This will eventually be deprecated. Use #dup! instead.
|
11
|
+
def try_dup
|
12
|
+
dup!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TrueClass
|
17
|
+
# Since TrueClass is immutable it cannot be duplicated.
|
18
|
+
# For this reason #dup! returns +self+.
|
19
|
+
def dup!
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class FalseClass
|
25
|
+
# Since FalseClass is immutable it cannot be duplicated.
|
26
|
+
# For this reason #dup! returns +self+.
|
27
|
+
def dup!
|
28
|
+
self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class NilClass
|
33
|
+
# Since NilClass is immutable it cannot be duplicated.
|
34
|
+
# For this reason #dup! returns +self+.
|
35
|
+
def dup!
|
36
|
+
self
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Numeric
|
41
|
+
# Since Numeric is immutable it cannot be duplicated.
|
42
|
+
# For this reason #dup! returns +self+.
|
43
|
+
def dup!
|
44
|
+
self
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Symbol
|
49
|
+
# Since Symbol is immutable it cannot be duplicated.
|
50
|
+
# For this reason #dup! returns +self+.
|
51
|
+
def dup!
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#class Module
|
57
|
+
# # Since Module is immutable it cannot be duplicated.
|
58
|
+
# # For this reason #dup! returns +self+.
|
59
|
+
# def dup!
|
60
|
+
# self
|
61
|
+
# end
|
62
|
+
#end
|
63
|
+
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Kernel
|
2
|
+
INSTANCES = {}
|
3
|
+
|
4
|
+
# Returns an instance of Instance for +self+,
|
5
|
+
# which allows convenient access to an object's
|
6
|
+
# internals.
|
7
|
+
|
8
|
+
def instance
|
9
|
+
INSTANCES[self] ||= Instance.new(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
# = Instance Class
|
15
|
+
#
|
16
|
+
# class Friend
|
17
|
+
# attr_accessor :name, :age, :phone
|
18
|
+
# def initialize(name, age, phone)
|
19
|
+
# @name, @age, @phone = name, age, phone
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# f1 = Friend.new("John", 30, "555-1212")
|
24
|
+
# p f1.instance
|
25
|
+
# f1.instance.update({:name=>'Jerry'})
|
26
|
+
# p f1.instance
|
27
|
+
#
|
28
|
+
class Instance
|
29
|
+
|
30
|
+
include Enumerable
|
31
|
+
|
32
|
+
#
|
33
|
+
def initialize(delegate)
|
34
|
+
@delegate = delegate
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
def instance_delegate
|
39
|
+
@delegate
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
def each
|
44
|
+
@delegate.instance_variables.each do |name|
|
45
|
+
yield(name[1..-1].to_sym, @delegate.instance_variable_get(name))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return instance variables with values as a hash.
|
50
|
+
#
|
51
|
+
# class X
|
52
|
+
# def initialize(a,b)
|
53
|
+
# @a, @b = a, b
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# x = X.new(1,2)
|
58
|
+
#
|
59
|
+
# x.instance.to_h #=> { :a=>1, :b=>2 }
|
60
|
+
#
|
61
|
+
def to_h(at=false)
|
62
|
+
h = {}
|
63
|
+
if at
|
64
|
+
@delegate.instance_variables.each do |name|
|
65
|
+
h[name] = @delegate.instance_variable_get(name)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
each do |key, value|
|
69
|
+
h[key] = value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
h
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: Not sure if this should be used.
|
76
|
+
alias_method :to_hash, :to_h
|
77
|
+
|
78
|
+
#
|
79
|
+
def [](name)
|
80
|
+
name = atize(name)
|
81
|
+
@delegate.instance_variable_get(name)
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
def []=(name, value)
|
86
|
+
name = atize(name)
|
87
|
+
@delegate.instance_variable_set(name,value)
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
def <<(pair)
|
92
|
+
name, value = *pair
|
93
|
+
name = atize(name)
|
94
|
+
@delegate.instance_variable_set(name, value)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Set instance variables given a +hash+.
|
98
|
+
#
|
99
|
+
# instance.update('@a'=>1, '@b'=>2)
|
100
|
+
# @a #=> 1
|
101
|
+
# @b #=> 2
|
102
|
+
#
|
103
|
+
# Also, +@+ sign is not neccessary.
|
104
|
+
#
|
105
|
+
# instance.update(:a=>1, :b=>2)
|
106
|
+
# @a #=> 1
|
107
|
+
# @b #=> 2
|
108
|
+
#
|
109
|
+
def update(hash)
|
110
|
+
hash.each do |pair|
|
111
|
+
self << pair
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# A hold-over from the the old #instance_assign method.
|
116
|
+
alias_method :assign, :update
|
117
|
+
|
118
|
+
# Same as #instance_variables.
|
119
|
+
def variables
|
120
|
+
@delegate.instance_variables
|
121
|
+
end
|
122
|
+
|
123
|
+
# Instance vairable names as symbols.
|
124
|
+
def keys
|
125
|
+
@delegate.instance_variables.collect do |name|
|
126
|
+
name[1..-1].to_sym
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Instance variable names as strings.
|
131
|
+
def names
|
132
|
+
@delegate.instance_variables.collect do |name|
|
133
|
+
name[1..-1]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Instance variable values.
|
138
|
+
def values
|
139
|
+
@delegate.instance_variables.collect do |name|
|
140
|
+
@delegate.instance_variable_get(name)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Instance evaluation.
|
145
|
+
def eval(*a,&b)
|
146
|
+
@delegate.instance_eval(*a,&b)
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def atize(name)
|
152
|
+
name.to_s !~ /^@/ ? "@#{name}" : name
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
@@ -1,33 +1,12 @@
|
|
1
1
|
module Kernel
|
2
2
|
|
3
|
-
# Return instance variable values in an array.
|
4
|
-
#
|
5
|
-
# class X
|
6
|
-
# def initialize(a,b)
|
7
|
-
# @a, @b = a, b
|
8
|
-
# end
|
9
|
-
# end
|
10
|
-
#
|
11
|
-
# x = X.new(1,2)
|
12
|
-
#
|
13
|
-
# x.instance_values #=> { "a"=>1, "b"=>2 }
|
14
|
-
#
|
15
|
-
# WARNING: #instance_values will be deprecated. Use instance_vars.to_hash instead.
|
16
|
-
|
17
|
-
def instance_values
|
18
|
-
instance_variables.inject({}) do |values, name|
|
19
|
-
values[name[1..-1]] = instance_variable_get(name)
|
20
|
-
values
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
3
|
# Set instance variables using a hash.
|
25
4
|
#
|
26
5
|
# instance_assign('@a'=>1, '@b'=>2)
|
27
6
|
# @a #=> 1
|
28
7
|
# @b #=> 2
|
29
8
|
#
|
30
|
-
#
|
9
|
+
# DEPRECATE: Use instance.update instead of #instance_assign.
|
31
10
|
|
32
11
|
def instance_assign(hash)
|
33
12
|
hash.each do |k,v|
|
@@ -1,75 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Assign via accessor methods using a hash, associative
|
4
|
-
# array or block.
|
5
|
-
#
|
6
|
-
# object.populate( :a => 1, :b => 2 )
|
7
|
-
# object.populate( :a, 1, :b, 2 )
|
8
|
-
# object.populate( [:a, 1], [:b, 2] )
|
9
|
-
# object.populate( *[[:a, 1], [:b, 2]] )
|
10
|
-
# object.populate{ |s| s.a = 1; s.b = 2 }
|
11
|
-
#
|
12
|
-
# These are all the same as doing:
|
13
|
-
#
|
14
|
-
# object.a = 1
|
15
|
-
# object.b = 2
|
16
|
-
#
|
17
|
-
# Using an associative array instead of hash guarentees
|
18
|
-
# order of assignemnt.
|
19
|
-
#
|
20
|
-
# Using a hash or array will not raise an error if the
|
21
|
-
# accessor does not exits -- it will simply be skipped.
|
22
|
-
#
|
23
|
-
# (See also: instance_vars.update, which sets instance variables directly, bypassing accessor method.)
|
24
|
-
#
|
25
|
-
# TODO: Better name, #set_with ?
|
26
|
-
|
27
|
-
def populate(data=nil) #:yield:
|
28
|
-
if data
|
29
|
-
data.each do |k,v|
|
30
|
-
send("#{k}=", v) if respond_to?("#{k}=")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
yield(self) if block_given?
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
# Set setter methods using a another object.
|
38
|
-
#
|
39
|
-
# class X
|
40
|
-
# attr_accessor :a, :b
|
41
|
-
# def initialize( a, b )
|
42
|
-
# @a,@b = a,b
|
43
|
-
# end
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# obj1 = X.new( 1, 2 )
|
47
|
-
# obj2 = X.new
|
48
|
-
#
|
49
|
-
# obj2.set_from(obj1)
|
50
|
-
#
|
51
|
-
# obj2.a #=> 1
|
52
|
-
# obj2.b #=> 2
|
53
|
-
#
|
54
|
-
# TODO: populate_from(obj) ?
|
55
|
-
|
56
|
-
def set_from(obj, *fields)
|
57
|
-
unless fields.empty?
|
58
|
-
fields.each do |k|
|
59
|
-
send( "#{k}=", obj.send("#{k}") ) #if self.respond_to?("#{k}=") && obj.respond_to?("#{k}")
|
60
|
-
end
|
61
|
-
else
|
62
|
-
setters = methods.collect { |m| m =~ /=$/ }
|
63
|
-
setters.each do |setter|
|
64
|
-
getter = setter.chomp('=')
|
65
|
-
if obj.respond_to?(getter)
|
66
|
-
send( setter, obj.send(getter) )
|
67
|
-
fields < getter
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
fields
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
1
|
+
require 'facets/kernel/assign'
|
75
2
|
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'facets/kernel/dup'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
unless method_defined?(:set)
|
4
|
+
|
5
|
+
# Sets an option to the given value. If the value is a proc,
|
6
|
+
# the proc will be called every time the option is accessed.
|
7
|
+
#
|
8
|
+
# CREDIT: ? (Sinatra)
|
9
|
+
|
10
|
+
def set(option, value=self, &block)
|
11
|
+
raise ArgumentError if block && value != self
|
12
|
+
value = block if block
|
13
|
+
if value.kind_of?(Proc)
|
14
|
+
if value.arity == 1
|
15
|
+
yield self
|
16
|
+
else
|
17
|
+
(class << self; self; end).module_eval do
|
18
|
+
define_method(option, &value)
|
19
|
+
define_method("#{option}?"){ !!__send__(option) }
|
20
|
+
define_method("#{option}="){ |val| set(option, Proc.new{val}) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
elsif value == self
|
24
|
+
option.each{ |k,v| set(k, v) }
|
25
|
+
elsif respond_to?("#{option}=")
|
26
|
+
__send__("#{option}=", value)
|
27
|
+
else
|
28
|
+
set(option, Proc.new{value})
|
29
|
+
end
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'facets/functor'
|
2
|
+
|
3
|
+
class << ObjectSpace
|
4
|
+
|
5
|
+
# Reflection ensures that information about an object
|
6
|
+
# is actual according to Ruby's Kernel definitions, just
|
7
|
+
# in case such methods have been overridden.
|
8
|
+
#
|
9
|
+
# ObjectSpace.reflect(obj).id
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
# There is also a global short-cut for this method to ease
|
13
|
+
# meta-programming with it.
|
14
|
+
#
|
15
|
+
# $ref[obj].id
|
16
|
+
#++
|
17
|
+
#
|
18
|
+
# Typically theis method will be used to gather the object's
|
19
|
+
# id, as in the example given, or it's class, but any Kernel
|
20
|
+
# method can be used.
|
21
|
+
#
|
22
|
+
# Care should be taken in utilizing this technique. In most
|
23
|
+
# cases it is not needed, but in certain cases is useful
|
24
|
+
# for improving the robustness of meta-programming solutions.
|
25
|
+
#
|
26
|
+
# Note that this is also equivalent to using +as(Kernel)+:
|
27
|
+
#
|
28
|
+
# obj.as(Kernel).id
|
29
|
+
#
|
30
|
+
# But obviously, in this case there is the risk that #as has
|
31
|
+
# be overridden too.
|
32
|
+
#
|
33
|
+
def reflect(obj)
|
34
|
+
Functor.new do |meth, *a, &b|
|
35
|
+
Kernel.instance_method(meth).bind(obj).call(*a, &b)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# TODO: Consider this "Shorcut for +ObjectSpace.reflect+."
|
42
|
+
#$ref = lambda do |obj|
|
43
|
+
# ObjectSpace.reflect(obj)
|
44
|
+
#end
|
45
|
+
|