gemmyrb 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|