gemmyrb 0.0.3 → 0.0.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/README.md +8 -3
- data/lib/gemmy/patches/array_patch.rb +9 -1
- data/lib/gemmy/patches/class_patch.rb +14 -0
- data/lib/gemmy/patches/exception_patch.rb +40 -0
- data/lib/gemmy/patches/float_patch.rb +16 -0
- data/lib/gemmy/patches/hash_patch.rb +184 -0
- data/lib/gemmy/patches/integer_patch.rb +21 -0
- data/lib/gemmy/patches/object_patch.rb +200 -0
- data/lib/gemmy/patches/proc_patch.rb +83 -0
- data/lib/gemmy/patches/string_patch.rb +217 -0
- data/lib/gemmy/patches/symbol_patch.rb +10 -1
- data/lib/gemmy/patches.rb +5 -1
- data/lib/gemmy/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 959c5dce4ee3611f0e6a9a1ee91a8da5ed128b3b
|
|
4
|
+
data.tar.gz: 2a2349bd342e424e17246d58d951b6e99dd74538
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7115fb4d4a8f4a152be9e24ac51bfd120101cd73d69d3356579aeda8526a83e7f77b99362571fdd2d1646849b0b6bbe703d34619f1234077b51245b61efcacd5
|
|
7
|
+
data.tar.gz: dc1d6dafb2a9e55032622f6aebbd38e540a6ba55998f1d3aa3048a71248fd50dfe9ef228e394c5072290ae8de90afadbc350d350e26ca14a596f549bef402207
|
data/README.md
CHANGED
|
@@ -19,7 +19,12 @@ documents:
|
|
|
19
19
|
- _Loading the gem's code in different scopes_
|
|
20
20
|
- [examples/01_using_as_refinement.rb](./examples/01_using_as_refinement.rb)
|
|
21
21
|
- [examples/02_using_globally.rb](./examples/02_using_globally.rb)
|
|
22
|
-
- _List of methods intended for general Ruby use_
|
|
23
|
-
- [examples/03_ruby_extensions_list.rb](./examples/03_ruby_extensions_list.rb)
|
|
24
22
|
- _Shell commands and other one-off processes_
|
|
25
|
-
- [examples/
|
|
23
|
+
- [examples/03_shell_commands.rb](./examples/03_shell_commands.rb)
|
|
24
|
+
|
|
25
|
+
**To see a full list of the patched methods (there are a lot since I've
|
|
26
|
+
included many from facets), see the [rubydoc](http://www.rubydoc.info/gems/gemmyrb)**
|
|
27
|
+
|
|
28
|
+
Specifically, look at the constants defined on Gemmy::Patches. There is one
|
|
29
|
+
module for each of the core classes being patched. Each individual method
|
|
30
|
+
is also contained in its own module (to make modular inclusion possible)
|
|
@@ -6,7 +6,7 @@ module Gemmy::Patches::ArrayPatch
|
|
|
6
6
|
|
|
7
7
|
module Zip
|
|
8
8
|
# facets
|
|
9
|
-
def
|
|
9
|
+
def zip(*arrays)
|
|
10
10
|
return [] if arrays.empty?
|
|
11
11
|
return arrays[0].zip(*arrays[1..-1])
|
|
12
12
|
end
|
|
@@ -16,6 +16,14 @@ module Gemmy::Patches::ArrayPatch
|
|
|
16
16
|
|
|
17
17
|
module InstanceMethods
|
|
18
18
|
|
|
19
|
+
module Exclude
|
|
20
|
+
# facets
|
|
21
|
+
# the opposite of include
|
|
22
|
+
def exclude?(x)
|
|
23
|
+
! include? x
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
19
27
|
module KeyBy
|
|
20
28
|
# facets
|
|
21
29
|
def key_by
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Gemmy::Patches::ClassPatch
|
|
2
|
+
module InstanceMethods
|
|
3
|
+
module ToProc
|
|
4
|
+
# facets
|
|
5
|
+
# I.e if an initializer takes one arg, then you can do
|
|
6
|
+
# %w{ arg1 arg2 }.map &ClassToInitialize
|
|
7
|
+
def to_proc
|
|
8
|
+
proc{|*args| new(*args)}
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
module ClassMethods
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Gemmy::Patches::ExceptionPatch
|
|
2
|
+
|
|
3
|
+
module ClassMethods
|
|
4
|
+
|
|
5
|
+
module Raised
|
|
6
|
+
# facets
|
|
7
|
+
# does an exception raise an error?
|
|
8
|
+
def self.raised? #:yeild:
|
|
9
|
+
begin
|
|
10
|
+
yield
|
|
11
|
+
false
|
|
12
|
+
rescue self
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module Suppress
|
|
19
|
+
# facets
|
|
20
|
+
def suppress(*err_classes)
|
|
21
|
+
err_classes.each do |e|
|
|
22
|
+
unless e < self
|
|
23
|
+
raise ArgumentError, "exception #{e} not a subclass of #{self}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
err_classes = err_classes.empty? ? [self] : err_classes
|
|
27
|
+
begin
|
|
28
|
+
yield
|
|
29
|
+
rescue Exception => e
|
|
30
|
+
raise unless err_classes.any? { |cls| e.kind_of?(cls) }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module InstanceMethods
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Gemmy::Patches::FloatPatch
|
|
2
|
+
module ClassMethods
|
|
3
|
+
end
|
|
4
|
+
module InstanceMethods
|
|
5
|
+
|
|
6
|
+
module RoundTo
|
|
7
|
+
# facets
|
|
8
|
+
# i.e. 2.046.round_to(0.01) == 2.05
|
|
9
|
+
def round_to( n ) #n=1
|
|
10
|
+
return self if n == 0
|
|
11
|
+
(self * (1.0 / n)).round.to_f / (1.0 / n)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -3,10 +3,194 @@
|
|
|
3
3
|
module Gemmy::Patches::HashPatch
|
|
4
4
|
|
|
5
5
|
module ClassMethods
|
|
6
|
+
# facets
|
|
7
|
+
# Hash.zip(["a","b","c"], [1,2,3])
|
|
8
|
+
# => { "a"=>1, "b"=>2, "c"=>3 }
|
|
9
|
+
module Zip
|
|
10
|
+
def zip(keys,values) # or some better name
|
|
11
|
+
h = {}
|
|
12
|
+
keys.size.times{ |i| h[ keys[i] ] = values[i] }
|
|
13
|
+
h
|
|
14
|
+
end
|
|
15
|
+
end
|
|
6
16
|
end
|
|
7
17
|
|
|
8
18
|
module InstanceMethods
|
|
9
19
|
|
|
20
|
+
module UpdateKeys
|
|
21
|
+
# facets
|
|
22
|
+
# in place
|
|
23
|
+
def update_keys #:yield:
|
|
24
|
+
if block_given?
|
|
25
|
+
keys.each { |old_key| store(yield(old_key), delete(old_key)) }
|
|
26
|
+
else
|
|
27
|
+
to_enum(:update_keys)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module UpdateValues
|
|
33
|
+
# facets
|
|
34
|
+
# in place
|
|
35
|
+
def update_values #:yield:
|
|
36
|
+
if block_given?
|
|
37
|
+
each{ |k,v| store(k, yield(v)) }
|
|
38
|
+
else
|
|
39
|
+
to_enum(:update_values)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
module ToOpenStruct
|
|
45
|
+
# facets
|
|
46
|
+
def to_ostruct
|
|
47
|
+
OpenStruct.new(self)
|
|
48
|
+
end
|
|
49
|
+
def recursive_to_ostruct(exclude={})
|
|
50
|
+
return exclude[self] if exclude.key?( self )
|
|
51
|
+
o = exclude[self] = OpenStruct.new
|
|
52
|
+
h = self.dup
|
|
53
|
+
each_pair do |k,v|
|
|
54
|
+
h[k] = v.to_ostruct_recurse( exclude ) if v.respond_to?(:to_ostruct_recurse)
|
|
55
|
+
end
|
|
56
|
+
o.merge!(h)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module Rekey
|
|
61
|
+
# facets
|
|
62
|
+
# rekey according to a block, i.e. {a: 1}.rekey &:to_s
|
|
63
|
+
def rekey(key_map=nil, &block)
|
|
64
|
+
raise ArgumentError, "argument or block" if key_map && block
|
|
65
|
+
|
|
66
|
+
if !(key_map or block)
|
|
67
|
+
block = lambda{|k| k.to_sym}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if block
|
|
71
|
+
hash = dup.clear
|
|
72
|
+
if block.arity.abs == 1
|
|
73
|
+
each_pair do |k, v|
|
|
74
|
+
hash[block[k]] = v #hash[block[k] || k] = v
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
each_pair do |k, v|
|
|
78
|
+
hash[block[k,v]] = v #hash[block[k,v] || k] = v
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
#hash = dup.clear # to keep default_proc
|
|
83
|
+
#(keys - key_map.keys).each do |key|
|
|
84
|
+
# hash[key] = self[key]
|
|
85
|
+
#end
|
|
86
|
+
#key_map.each do |from, to|
|
|
87
|
+
# hash[to] = self[from] if key?(from)
|
|
88
|
+
#end
|
|
89
|
+
hash = dup # to keep default_proc
|
|
90
|
+
key_map.each_pair do |from, to|
|
|
91
|
+
hash[to] = hash.delete(from) if hash.key?(from)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
hash
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
module Recurse
|
|
100
|
+
# facets
|
|
101
|
+
# h = {:a=>1, :b=>{:b1=>1, :b2=>2}}
|
|
102
|
+
# g = h.recurse{|h| h.inject({}){|h,(k,v)| h[k.to_s] = v; h} }
|
|
103
|
+
# g #=> {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}}
|
|
104
|
+
def recurse(*types, &block)
|
|
105
|
+
types = [self.class] if types.empty?
|
|
106
|
+
h = inject({}) do |hash, (key, value)|
|
|
107
|
+
case value
|
|
108
|
+
when *types
|
|
109
|
+
hash[key] = value.recurse(*types, &block)
|
|
110
|
+
else
|
|
111
|
+
hash[key] = value
|
|
112
|
+
end
|
|
113
|
+
hash
|
|
114
|
+
end
|
|
115
|
+
yield h
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
module HasKeys
|
|
120
|
+
# facets
|
|
121
|
+
# checks if a list of keys are all present
|
|
122
|
+
def keys?(*check_keys)
|
|
123
|
+
unknown_keys = check_keys - self.keys
|
|
124
|
+
return unknown_keys.empty?
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
module OnlyKeys
|
|
129
|
+
# facets
|
|
130
|
+
# checks if these are the only keys
|
|
131
|
+
def only_keys?(*check_keys)
|
|
132
|
+
unknown_keys = self.keys - check_keys
|
|
133
|
+
return unknown_keys.empty?
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
module Join
|
|
138
|
+
# facets
|
|
139
|
+
# returns a string
|
|
140
|
+
def join(pair_divider='', elem_divider=nil)
|
|
141
|
+
elem_divider ||= pair_divider
|
|
142
|
+
s = []
|
|
143
|
+
each{ |k,v| s << "#{k}#{pair_divider}#{v}" }
|
|
144
|
+
s.join(elem_divider)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
module Inverse
|
|
149
|
+
# facets
|
|
150
|
+
# h = {"a"=>3, "b"=>3, "c"=>3, "d"=>2, "e"=>9, "f"=>3, "g"=>9}
|
|
151
|
+
# h.invert #=> {2=>"d", 3=>"f", 9=>"g"}
|
|
152
|
+
# h.inverse #=> {2=>"d", 3=>["f", "c", "b", "a"], 9=>["g", "e"]}
|
|
153
|
+
# h.inverse.inverse #=> {"a"=>3, "b"=>3, "c"=>3, "d"=>2, "e"=>9, "f"=>3, "g"=>9}
|
|
154
|
+
def inverse
|
|
155
|
+
i = Hash.new
|
|
156
|
+
self.each_pair{ |k,v|
|
|
157
|
+
if (Array === v)
|
|
158
|
+
v.each{ |x| i[x] = ( i.has_key?(x) ? [k,i[x]].flatten : k ) }
|
|
159
|
+
else
|
|
160
|
+
i[v] = ( i.has_key?(v) ? [k,i[v]].flatten : k )
|
|
161
|
+
end
|
|
162
|
+
}
|
|
163
|
+
return i
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
module Diff
|
|
168
|
+
# facets
|
|
169
|
+
# returns the key-vals from <self> that are not the same in <hash>
|
|
170
|
+
def diff(hash)
|
|
171
|
+
h1 = self.dup.delete_if{ |k,v| hash[k] == v }
|
|
172
|
+
h2 = hash.dup.delete_if{ |k,v| has_key?(k) }
|
|
173
|
+
h1.merge(h2)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
module Except
|
|
178
|
+
# facets
|
|
179
|
+
# excludes vertain keys
|
|
180
|
+
def except(*less_keys)
|
|
181
|
+
hash = dup
|
|
182
|
+
less_keys.each{ |k| hash.delete(k) }
|
|
183
|
+
hash
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
module DeleteUnless
|
|
188
|
+
# facets
|
|
189
|
+
def delete_unless #:yield:
|
|
190
|
+
delete_if{ |key, value| ! yield(key, value) }
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
10
194
|
# The opposite of Hash#dig
|
|
11
195
|
# Takes a list of keys followed by a value to set
|
|
12
196
|
#
|
|
@@ -2,6 +2,27 @@ module Gemmy::Patches::IntegerPatch
|
|
|
2
2
|
|
|
3
3
|
module ClassMethods
|
|
4
4
|
|
|
5
|
+
module RomanValues
|
|
6
|
+
# facets
|
|
7
|
+
def roman_values
|
|
8
|
+
[
|
|
9
|
+
["M", 1000],
|
|
10
|
+
["CM", 900],
|
|
11
|
+
["D", 500],
|
|
12
|
+
["CD", 400],
|
|
13
|
+
["C", 100],
|
|
14
|
+
["XC", 90],
|
|
15
|
+
["L", 50],
|
|
16
|
+
["XL", 40],
|
|
17
|
+
["X", 10],
|
|
18
|
+
["IX", 9],
|
|
19
|
+
["V", 5],
|
|
20
|
+
["IV", 4],
|
|
21
|
+
["I", 1]
|
|
22
|
+
].to_h
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
5
26
|
end
|
|
6
27
|
|
|
7
28
|
module InstanceMethods
|
|
@@ -1,12 +1,203 @@
|
|
|
1
1
|
# Object patches. Can be called with implicit receiver
|
|
2
2
|
#
|
|
3
|
+
# Patches which are originally specified as being for Kernel (by facets,
|
|
4
|
+
# for examples), are implemented here as patches on Object because Kernel is
|
|
5
|
+
# a module and Ruby doesn't support refinements on Modules. Object includes
|
|
6
|
+
# and extends Kernel so it's the same effect.
|
|
7
|
+
#
|
|
3
8
|
module Gemmy::Patches::ObjectPatch
|
|
4
9
|
|
|
10
|
+
# This class is redundant here, since Object's instance methods
|
|
11
|
+
# are available at the class scope anyway.
|
|
5
12
|
module ClassMethods
|
|
6
13
|
end
|
|
7
14
|
|
|
8
15
|
module InstanceMethods
|
|
9
16
|
|
|
17
|
+
module Iteself
|
|
18
|
+
# facets
|
|
19
|
+
def itself
|
|
20
|
+
def itself
|
|
21
|
+
self
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module Try
|
|
27
|
+
# facets
|
|
28
|
+
# nicer than the builtin
|
|
29
|
+
# @example.try.name #=> "bob"
|
|
30
|
+
# @people.try(:collect){ |p| p.name }
|
|
31
|
+
def try(method=nil, *args, &block)
|
|
32
|
+
if method
|
|
33
|
+
__send__(method, *args, &block)
|
|
34
|
+
else
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
module Not
|
|
41
|
+
# facets
|
|
42
|
+
# true.nil?.not? == !true.nil?
|
|
43
|
+
def not?
|
|
44
|
+
!self
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module Truthy
|
|
49
|
+
def truthy
|
|
50
|
+
!! self
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
module Falsy
|
|
55
|
+
def Falsy
|
|
56
|
+
! self
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module NotNil
|
|
61
|
+
# facets
|
|
62
|
+
def not_nil?
|
|
63
|
+
! nil?
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module Maybe
|
|
68
|
+
# Random generator that returns true or false. Can also take a block that has a 50/50 chance to being executed…
|
|
69
|
+
# facets
|
|
70
|
+
def maybe(chance = 0.5, &block)
|
|
71
|
+
if block
|
|
72
|
+
yield if rand < chance
|
|
73
|
+
else
|
|
74
|
+
rand < chance
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
module InstanceAssign
|
|
80
|
+
# facets
|
|
81
|
+
# assign instance variables with a hash
|
|
82
|
+
def instance_assign(hash)
|
|
83
|
+
hash.each do |k,v|
|
|
84
|
+
k = "@#{k}" if k !~ /^@/
|
|
85
|
+
instance_variable_set(k, v)
|
|
86
|
+
end
|
|
87
|
+
self
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
module HierarchicalSend
|
|
92
|
+
# facets
|
|
93
|
+
# Send a message to each ancestor in an object's class hierarchy. The method will only be called if the method is defined for the ancestor.
|
|
94
|
+
# This can be very useful for setting up a `preinitialize` system.
|
|
95
|
+
#
|
|
96
|
+
# Example:
|
|
97
|
+
# m = Module.new do
|
|
98
|
+
# attr :a
|
|
99
|
+
# def preinitialize
|
|
100
|
+
# @a = 1
|
|
101
|
+
# end
|
|
102
|
+
# end
|
|
103
|
+
#
|
|
104
|
+
# c = Class.new do
|
|
105
|
+
# include m
|
|
106
|
+
# def initialize
|
|
107
|
+
# hierarchical_send(:preinitialize)
|
|
108
|
+
# end
|
|
109
|
+
# end
|
|
110
|
+
|
|
111
|
+
# c.new.a #=> 1
|
|
112
|
+
def hierarchical_send(method_name, *args, &block)
|
|
113
|
+
method_name = method_name.to_s if RUBY_VERSION < '1.9'
|
|
114
|
+
this = self
|
|
115
|
+
self.class.hierarchically do |anc|
|
|
116
|
+
## is there really no better way to check for the method?
|
|
117
|
+
if anc.instance_methods(false).include?(method_name) or
|
|
118
|
+
anc.public_instance_methods(false).include?(method_name) or
|
|
119
|
+
anc.private_instance_methods(false).include?(method_name) or
|
|
120
|
+
anc.protected_instance_methods(false).include?(method_name)
|
|
121
|
+
im = anc.instance_method(method_name)
|
|
122
|
+
##im.arity == 0 ? im.bind(this).call(&block) : im.bind(this).call(*args, &block)
|
|
123
|
+
im.bind(this).call(*args, &block)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
module Ergo
|
|
130
|
+
# facets
|
|
131
|
+
# This is like #tap, but #tap yields self and returns self,
|
|
132
|
+
# where as #ergo yields self but returns the result.
|
|
133
|
+
def ergo(&b)
|
|
134
|
+
if block_given?
|
|
135
|
+
b.arity > 0 ? yield(self) : instance_eval(&b)
|
|
136
|
+
else
|
|
137
|
+
self
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
module DeepCopy
|
|
143
|
+
# facets
|
|
144
|
+
def deep_copy
|
|
145
|
+
Marshal::load(Marshal::dump(self))
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
module Constant
|
|
150
|
+
# facets
|
|
151
|
+
# like Module#const_get accessible at all levels
|
|
152
|
+
# and handles module hierarchy.
|
|
153
|
+
# constant("Process::Sys")
|
|
154
|
+
def constant(const)
|
|
155
|
+
const = const.to_s.dup
|
|
156
|
+
base = const.sub!(/^::/, '') ? Object : ( self.kind_of?(Module) ? self : self.class )
|
|
157
|
+
const.split(/::/).inject(base){ |mod, name| mod.const_get(name) }
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
module Bool
|
|
162
|
+
# facets
|
|
163
|
+
def bool?
|
|
164
|
+
(true == self or false == self)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
module AttrSingletonAccessor
|
|
169
|
+
# facets
|
|
170
|
+
# obj = Object.new
|
|
171
|
+
# obj.attr_singleton_accessor :x, :y
|
|
172
|
+
def attr_singleton_accessor(*args)
|
|
173
|
+
#h, a = *args.partition{|a| Hash===a}
|
|
174
|
+
(class << self ; self ; end).send( :attr_accessor, *args )
|
|
175
|
+
#(class << self ; self ; end).send( :attr_accessor, *h.keys )
|
|
176
|
+
#h.each { |k,v| instance_variable_set("@#{k}", v) }
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
module AttrSingletonReader
|
|
181
|
+
# facets
|
|
182
|
+
def attr_singleton_reader(*args)
|
|
183
|
+
#h, a = *args.partition{|a| Hash===a}
|
|
184
|
+
(class << self ; self ; end).send( :attr_reader, *args )
|
|
185
|
+
#(class << self ; self ; end).send( :attr_reader, *h.keys )
|
|
186
|
+
#h.each { |k,v| instance_variable_set("@#{k}", v) }
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
module AttrSingletonWriter
|
|
191
|
+
# facets
|
|
192
|
+
def attr_singleton_writer(*args)
|
|
193
|
+
#h, a = *args.partition{|a| Hash===a}
|
|
194
|
+
(class << self ; self ; end).send( :attr_writer, *args )
|
|
195
|
+
#(class << self ; self ; end).send( :attr_writer, *h.keys )
|
|
196
|
+
#h.each { |k,v| instance_variable_set("@#{k}", v) }
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
|
|
10
201
|
# Turns on verbose mode, showing warnings
|
|
11
202
|
#
|
|
12
203
|
module VerboseMode
|
|
@@ -24,6 +215,15 @@ module Gemmy::Patches::ObjectPatch
|
|
|
24
215
|
end
|
|
25
216
|
end
|
|
26
217
|
|
|
218
|
+
module Ask
|
|
219
|
+
# facets
|
|
220
|
+
def ask(prompt=nil)
|
|
221
|
+
$stdout << "#{prompt}"
|
|
222
|
+
$stdout.flush
|
|
223
|
+
$stdin.gets.chomp!
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
27
227
|
# Prints a string then gets input
|
|
28
228
|
# @param txt [String]
|
|
29
229
|
#
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Gemmy::Patches::ProcPatch
|
|
2
|
+
module ClassMethods
|
|
3
|
+
end
|
|
4
|
+
module InstanceMethods
|
|
5
|
+
|
|
6
|
+
module ToMethod
|
|
7
|
+
# facets
|
|
8
|
+
# converts a proc to a method on an object
|
|
9
|
+
# object = Object.__new__
|
|
10
|
+
# function = lambda { |x| x + 1 }
|
|
11
|
+
# function.to_method(object, 'foo')
|
|
12
|
+
# object.foo(1) #=> 2
|
|
13
|
+
def to_method(object, name=nil)
|
|
14
|
+
##object = object || eval("self", self)
|
|
15
|
+
block, time = self, Time.now
|
|
16
|
+
method_name = name || "__bind_#{time.to_i}_#{time.usec}"
|
|
17
|
+
begin
|
|
18
|
+
object.singleton_class.class_eval do
|
|
19
|
+
define_method(method_name, &block)
|
|
20
|
+
method = instance_method(method_name)
|
|
21
|
+
remove_method(method_name) unless name
|
|
22
|
+
method
|
|
23
|
+
end.bind(object)
|
|
24
|
+
rescue TypeError
|
|
25
|
+
object.class.class_eval do
|
|
26
|
+
define_method(method_name, &block)
|
|
27
|
+
method = instance_method(method_name)
|
|
28
|
+
remove_method(method_name) unless name
|
|
29
|
+
method
|
|
30
|
+
end.bind(object)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# facets
|
|
36
|
+
# can be used for higher-order methods
|
|
37
|
+
# a = lambda { |x| x + 4 }
|
|
38
|
+
# b = lambda { |y| y / 2 }
|
|
39
|
+
|
|
40
|
+
# (a * b).call(4) #=> 6
|
|
41
|
+
# (b * a).call(4) #=> 4
|
|
42
|
+
module Multiply
|
|
43
|
+
def *(x)
|
|
44
|
+
if Integer===x
|
|
45
|
+
# collect times
|
|
46
|
+
c = []
|
|
47
|
+
x.times{|i| c << call(i)}
|
|
48
|
+
c
|
|
49
|
+
else
|
|
50
|
+
# compose procs
|
|
51
|
+
lambda{|*a| self[x[*a]]}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
module Compose
|
|
57
|
+
# facets
|
|
58
|
+
# similar to multiply
|
|
59
|
+
#
|
|
60
|
+
# a = lambda { |x| x + 4 }
|
|
61
|
+
# b = lambda { |y| y / 2 }
|
|
62
|
+
|
|
63
|
+
# a.compose(b).call(4) #=> 6
|
|
64
|
+
# b.compose(a).call(4) #=> 4
|
|
65
|
+
def compose(g)
|
|
66
|
+
raise ArgumentError, "arity count mismatch" unless arity == g.arity
|
|
67
|
+
lambda{ |*a| self[ *g[*a] ] }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
module BindTo
|
|
72
|
+
# facets
|
|
73
|
+
# a = [1,2,3]
|
|
74
|
+
# p1 = Proc.new{ join(' ') }
|
|
75
|
+
# p2 = p1.bind_to(a)
|
|
76
|
+
# p2.call #=> '1 2 3'
|
|
77
|
+
def bind_to(object)
|
|
78
|
+
Proc.new{object.instance_eval(&self)}
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -7,6 +7,223 @@ module Gemmy::Patches::StringPatch
|
|
|
7
7
|
|
|
8
8
|
module InstanceMethods
|
|
9
9
|
|
|
10
|
+
module Words
|
|
11
|
+
# facets
|
|
12
|
+
def words
|
|
13
|
+
self.split(/\s+/)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module Rotate
|
|
18
|
+
# facets
|
|
19
|
+
# 'abcdefgh'.rotate(2) #=> 'cdefghab'
|
|
20
|
+
# 'abcdefgh'.rotate(-2) #=> 'ghabcdef'
|
|
21
|
+
def rotate(count=1)
|
|
22
|
+
count+=self.length if count<0
|
|
23
|
+
self.slice(count,self.length-count)+self.slice(0,count)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module Range
|
|
28
|
+
# facets
|
|
29
|
+
# Gets the start/end indexes of a match to <pattern>
|
|
30
|
+
# only considers first match
|
|
31
|
+
def range(pattern, offset=0)
|
|
32
|
+
unless Regexp === pattern
|
|
33
|
+
pattern = Regexp.new(Regexp.escape(pattern.to_s))
|
|
34
|
+
end
|
|
35
|
+
string = self[offset..-1]
|
|
36
|
+
if md = pattern.match(string)
|
|
37
|
+
return (md.begin(0)+offset)..(md.end(0)+offset-1)
|
|
38
|
+
end
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
module RangeAll
|
|
44
|
+
# facets
|
|
45
|
+
# like #range patch but returns start/end indexes of all matches
|
|
46
|
+
def range_all(pattern, reuse=false)
|
|
47
|
+
r = []; i = 0
|
|
48
|
+
while i < self.length
|
|
49
|
+
rng = range(pattern, i)
|
|
50
|
+
if rng
|
|
51
|
+
r << rng
|
|
52
|
+
i += reuse ? 1 : rng.end + 1
|
|
53
|
+
else
|
|
54
|
+
break
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
r.uniq
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module IsNumber
|
|
62
|
+
# facets
|
|
63
|
+
def is_number?
|
|
64
|
+
!!self.match(/\A[+-]?\d+?(_?\d+?)*?(\.\d+(_?\d+?)*?)?\Z/)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
module EachMatch
|
|
69
|
+
# facets
|
|
70
|
+
# iterator over matches from regex
|
|
71
|
+
def each_match(re) #:yield:
|
|
72
|
+
if block_given?
|
|
73
|
+
scan(re) { yield($~) }
|
|
74
|
+
else
|
|
75
|
+
m = []
|
|
76
|
+
scan(re) { m << $~ }
|
|
77
|
+
m
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
module LineWrap
|
|
83
|
+
# facets
|
|
84
|
+
# wrap lines at width
|
|
85
|
+
def line_wrap(width, tabs=4)
|
|
86
|
+
s = gsub(/\t/,' ' * tabs) # tabs default to 4 spaces
|
|
87
|
+
s = s.gsub(/\n/,' ')
|
|
88
|
+
r = s.scan( /.{1,#{width}}/ )
|
|
89
|
+
r.join("\n") << "\n"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
module Lchomp
|
|
94
|
+
# facets
|
|
95
|
+
def lchomp(match)
|
|
96
|
+
if index(match) == 0
|
|
97
|
+
self[match.size..-1]
|
|
98
|
+
else
|
|
99
|
+
self.dup
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
module IndexAll
|
|
105
|
+
# facets
|
|
106
|
+
# standard String#index only shows the first match
|
|
107
|
+
def index_all(s, reuse=false)
|
|
108
|
+
s = Regexp.new(Regexp.escape(s)) unless Regexp===s
|
|
109
|
+
ia = []; i = 0
|
|
110
|
+
while (i = index(s,i))
|
|
111
|
+
ia << i
|
|
112
|
+
i += (reuse ? 1 : $~[0].size)
|
|
113
|
+
end
|
|
114
|
+
ia
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
module Indent
|
|
119
|
+
# facets
|
|
120
|
+
def indent(n, c=' ')
|
|
121
|
+
if n >= 0
|
|
122
|
+
gsub(/^/, c * n)
|
|
123
|
+
else
|
|
124
|
+
gsub(/^#{Regexp.escape(c)}{0,#{-n}}/, "")
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
module ExpandTabs
|
|
130
|
+
# turns tabs to spaces
|
|
131
|
+
def expand_tabs(n=8)
|
|
132
|
+
n = n.to_int
|
|
133
|
+
raise ArgumentError, "n must be >= 0" if n < 0
|
|
134
|
+
return gsub(/\t/, "") if n == 0
|
|
135
|
+
return gsub(/\t/, " ") if n == 1
|
|
136
|
+
str = self.dup
|
|
137
|
+
while
|
|
138
|
+
str.gsub!(/^([^\t\n]*)(\t+)/) { |f|
|
|
139
|
+
val = ( n * $2.size - ($1.size % n) )
|
|
140
|
+
$1 << (' ' * val)
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
str
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
module Exclude
|
|
148
|
+
# facets
|
|
149
|
+
def exclude?(str)
|
|
150
|
+
!include?(str)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
module CompressLines
|
|
155
|
+
# facets
|
|
156
|
+
# replace newlines or N spaces with one space
|
|
157
|
+
def compress_lines(spaced = true)
|
|
158
|
+
split($/).map{ |line| line.strip }.join(spaced ? ' ' : '')
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
module AlignCenter
|
|
163
|
+
# facets
|
|
164
|
+
def align_center(n, sep="\n", c=' ')
|
|
165
|
+
return center(n.to_i,c.to_s) if sep==nil
|
|
166
|
+
q = split(sep.to_s).collect { |line|
|
|
167
|
+
line.center(n.to_i,c.to_s)
|
|
168
|
+
}
|
|
169
|
+
q.join(sep.to_s)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
module AlignLeft
|
|
174
|
+
# facets
|
|
175
|
+
def align_left(n, sep="\n", c=' ')
|
|
176
|
+
return ljust(n.to_i,c.to_s) if sep==nil
|
|
177
|
+
q = split(sep.to_s).map do |line|
|
|
178
|
+
line.strip.ljust(n.to_i,c.to_s)
|
|
179
|
+
end
|
|
180
|
+
q.join(sep.to_s)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
module AsciiOnly
|
|
185
|
+
# facets
|
|
186
|
+
# remove non ascii characters
|
|
187
|
+
def ascii_only(alt='')
|
|
188
|
+
encoding_options = {
|
|
189
|
+
:invalid => :replace, # Replace invalid byte sequences
|
|
190
|
+
:undef => :replace, # Replace anything not defined in ASCII
|
|
191
|
+
:replace => alt, # Use a blank for those replacements
|
|
192
|
+
:UNIVERSAL_NEWLINE_DECORATOR => true # Always break lines with \n
|
|
193
|
+
}
|
|
194
|
+
self.encode(Encoding.find('ASCII'), encoding_options)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
module AlignRight
|
|
199
|
+
# facets
|
|
200
|
+
def align_right(n, sep="\n", c=' ')
|
|
201
|
+
return rjust(n.to_i,c.to_s) if sep==nil
|
|
202
|
+
q = split(sep.to_s).map do |line|
|
|
203
|
+
line.rjust(n.to_i,c.to_s)
|
|
204
|
+
end
|
|
205
|
+
q.join(sep.to_s)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
module Subtract
|
|
210
|
+
# facets
|
|
211
|
+
# removes all instances of a pattern from a string
|
|
212
|
+
def -(pattern)
|
|
213
|
+
gsub(pattern, '')
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
module Random
|
|
218
|
+
# facets
|
|
219
|
+
# a random string of length n with a given character set
|
|
220
|
+
def self.random(len=32, character_set = ["A".."Z", "a".."z", "0".."9"])
|
|
221
|
+
characters = character_set.map { |i| i.to_a }.flatten
|
|
222
|
+
characters_len = characters.length
|
|
223
|
+
(0...len).map{ characters[rand(characters_len)] }.join
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
10
227
|
# reference 'strip_heredoc' (provided by active support) by 'unindent'
|
|
11
228
|
#
|
|
12
229
|
# this takes an indented heredoc and treats it as if the first line is not
|
|
@@ -5,7 +5,16 @@ module Gemmy::Patches::SymbolPatch
|
|
|
5
5
|
module ClassMethods
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
module InstanceMethods
|
|
9
|
+
|
|
10
|
+
module Variablize
|
|
11
|
+
# facets
|
|
12
|
+
# take a symbol and make it fine for an instance variable name
|
|
13
|
+
def variablize
|
|
14
|
+
name = to_s.gsub(/\W/, '_')
|
|
15
|
+
"@#{name}".to_sym
|
|
16
|
+
end
|
|
17
|
+
end
|
|
9
18
|
|
|
10
19
|
# Patch symbol so the proc shorthand can take extra arguments
|
|
11
20
|
# http://stackoverflow.com/a/23711606/2981429
|
data/lib/gemmy/patches.rb
CHANGED
|
@@ -95,7 +95,11 @@ module Gemmy::Patches
|
|
|
95
95
|
Method: Gemmy::Patches::MethodPatch,
|
|
96
96
|
Hash: Gemmy::Patches::HashPatch,
|
|
97
97
|
Thread: Gemmy::Patches::ThreadPatch,
|
|
98
|
-
Integer: Gemmy::Patches::IntegerPatch
|
|
98
|
+
Integer: Gemmy::Patches::IntegerPatch,
|
|
99
|
+
Class: Gemmy::Patches::ClassPatch,
|
|
100
|
+
Exception: Gemmy::Patches::ExceptionPatch,
|
|
101
|
+
Float: Gemmy::Patches::FloatPatch,
|
|
102
|
+
Proc: Gemmy::Patches::ProcPatch
|
|
99
103
|
}.with_indifferent_access
|
|
100
104
|
end
|
|
101
105
|
|
data/lib/gemmy/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gemmyrb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- max pleaner
|
|
@@ -101,10 +101,14 @@ files:
|
|
|
101
101
|
- lib/gemmy/components/dynamic_steps.rb
|
|
102
102
|
- lib/gemmy/patches.rb
|
|
103
103
|
- lib/gemmy/patches/array_patch.rb
|
|
104
|
+
- lib/gemmy/patches/class_patch.rb
|
|
105
|
+
- lib/gemmy/patches/exception_patch.rb
|
|
106
|
+
- lib/gemmy/patches/float_patch.rb
|
|
104
107
|
- lib/gemmy/patches/hash_patch.rb
|
|
105
108
|
- lib/gemmy/patches/integer_patch.rb
|
|
106
109
|
- lib/gemmy/patches/method_patch.rb
|
|
107
110
|
- lib/gemmy/patches/object_patch.rb
|
|
111
|
+
- lib/gemmy/patches/proc_patch.rb
|
|
108
112
|
- lib/gemmy/patches/string_patch.rb
|
|
109
113
|
- lib/gemmy/patches/symbol_patch.rb
|
|
110
114
|
- lib/gemmy/patches/thread_patch.rb
|