sixarm_ruby_ramp 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,238 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'yaml'
4
+
5
+ # Hash extensions
6
+
7
+ class Hash
8
+
9
+
10
+ # @return [Boolean] true if size > 0
11
+
12
+ def size?
13
+ size>0
14
+ end
15
+
16
+ # @return [Hash] a new hash sorted by the keys
17
+ #
18
+ # @example
19
+ # h = {"c" => "cherry", "b" => "banana", "a" =>"apple" }
20
+ # h.sort_keys => {"a" => "apple", "b" => "banana", "c" => "cherry"}
21
+
22
+ def sort_by_keys
23
+ Hash[sort]
24
+ end
25
+
26
+
27
+ # Calls block once for each key in hsh, passing the key and value to the block as a two-element array.
28
+ #
29
+ # The keys are sorted.
30
+ #
31
+ # @example
32
+ # h = { "xyz" => "123", "abc" => "789" }
33
+ # h.each_sort {|key, val| ... }
34
+ # => calls the block with "abc" => "789", then with "xyz" => "123"
35
+
36
+ def each_sort
37
+ keys.sort.each{|key| yield key,self[key] }
38
+ end
39
+
40
+
41
+ # Calls block once for each key in hsh,
42
+ # passing the key as a parameter,
43
+ # and updating it in place.
44
+ #
45
+ # @example
46
+ # h = { "a" => "b", "c" => "d" }
47
+ # h.each_key! {|key| key.upcase }
48
+ # h => { "A" => "b", "C" => "d" }
49
+ #
50
+ # @return self
51
+
52
+ def each_key!
53
+ replacements=[]
54
+ keys.each{|key|
55
+ value=self[key]
56
+ key2=yield(key)
57
+ if key===key2
58
+ #nop
59
+ else
60
+ replacements << [key,key2,value]
61
+ end
62
+ }
63
+ replacements.each{|key,key2,value|
64
+ self.delete(key)
65
+ self[key2]=value
66
+ }
67
+ return self
68
+ end
69
+
70
+
71
+ # Calls block once for each key in hsh,
72
+ # passing the key and value as parameters,
73
+ # and updated them in place.
74
+ #
75
+ # @example
76
+ # h = { "a" => "b", "c" => "d" }
77
+ # h.each_pair! {|key,value| key.upcase, value.upcase }
78
+ # h => { "A" => "B", "C" => "D" }
79
+ #
80
+ # @return self.
81
+
82
+ def each_pair!
83
+ replacements=[]
84
+ keys.each{|key|
85
+ value=self[key]
86
+ key2,value2=yield(key,value)
87
+ if key===key2
88
+ if value===value2
89
+ #nop
90
+ else
91
+ self[key]=value2
92
+ end
93
+ else
94
+ replacements << [key,key2,value2]
95
+ end
96
+ }
97
+ replacements.each{|key,key2,value2|
98
+ self.delete(key)
99
+ self[key2]=value2
100
+ }
101
+ return self
102
+ end
103
+
104
+
105
+ # Calls block once for each key in hsh,
106
+ # passing the value as a parameter,
107
+ # and updating it in place.
108
+ #
109
+ # @example
110
+ # h = { "a" => "b", "c" => "d" }
111
+ # h.each_value! {|value| value.upcase }
112
+ # h => { "a" => "B", "c" => "d" }
113
+ #
114
+ # @return self.
115
+
116
+ def each_value!
117
+ keys.each{|key|
118
+ value=self[key]
119
+ value2=yield(value)
120
+ if value===value2
121
+ #nop
122
+ else
123
+ self[key]=yield(value)
124
+ end
125
+ }
126
+ return self
127
+ end
128
+
129
+
130
+ # Calls block once for each key-value pair in hsh,
131
+ # passing the key and value as paramters to the block.
132
+ #
133
+ # @example
134
+ # h = {"a"=>"b", "c"=>"d", "e"=>"f" }
135
+ # h.map_pair{|key,value| key+value }
136
+ # => ["ab","cd","ef"]
137
+
138
+ def map_pair
139
+ keys.map{|key| yield key, self[key] }
140
+ end
141
+
142
+
143
+ # Hash#pivot aggregates values for a hash of hashes,
144
+ # for example to calculate subtotals and groups.
145
+ #
146
+ # Suppose you have data arranged by companies, roles, and headcounts.
147
+ #
148
+ # data = {
149
+ # "Apple" => {"Accountants" => 11, "Designers" => 22, "Developers" => 33},
150
+ # "Goggle" => {"Accountants" => 44, "Designers" => 55, "Developers" => 66},
151
+ # "Microsoft" => {"Accountants" => 77, "Designers" => 88, "Developers" => 99},
152
+ # }
153
+ #
154
+ # To calculate each company's total headcount, you pivot up, then sum:
155
+ #
156
+ # data.pivot(:up,&:sum)
157
+ # => {
158
+ # "Apple"=>66,
159
+ # "Goggle"=>165,
160
+ # "Microsoft"=>264
161
+ # }
162
+ #
163
+ # To calculate each role's total headcount, you pivot down, then sum:
164
+ #
165
+ # data.pivot(:down,&:sum)
166
+ # => {
167
+ # "Accountants"=>132,
168
+ # "Designers"=>165,
169
+ # "Developers"=>198
170
+ # }
171
+ #
172
+ # Generic xxample:
173
+ # h={
174
+ # "a"=>{"x"=>1,"y"=>2,"z"=>3},
175
+ # "b"=>{"x"=>4,"y"=>5,"z"=>6},
176
+ # "c"=>{"x"=>7,"y"=>8,"z"=>9},
177
+ # }
178
+ # h.pivot(:keys) => {"a"=>[1,2,3],"b"=>[4,5,6],"c"=>[7,8,9]}
179
+ # h.pivot(:vals) => {"x"=>[1,4,7],"y"=>[2,5,8],"z"=>[3,6,9]}
180
+ #
181
+ # = Calculating subtotals
182
+ #
183
+ # The pivot method is especially useful for calculating subtotals.
184
+ #
185
+ # @example
186
+ # r = h.pivot(:keys)
187
+ # r['a'].sum => 6
188
+ # r['b'].sum => 15
189
+ # r['c'].sum => 24
190
+ #
191
+ # @example
192
+ # r=h.pivot(:vals)
193
+ # r['x'].sum => 12
194
+ # r['y'].sum => 15
195
+ # r['z'].sum => 18
196
+ #
197
+ # = Block customization
198
+ #
199
+ # You can provide a block that will be called for the pivot items.
200
+ #
201
+ # @example
202
+ # h.pivot(:keys){|items| items.max } => {"a"=>3,"b"=>6,"c"=>9}
203
+ # h.pivot(:keys){|items| items.join("/") } => {"a"=>"1/2/3","b"=>"4/5/6","c"=>"7/8/9"}
204
+ # h.pivot(:keys){|items| items.inject{|sum,x| sum+=x } } => {"a"=>6,"b"=>15,"c"=>24}
205
+ #
206
+ # @example
207
+ # h.pivot(:vals){|items| items.max } => {"a"=>7,"b"=>8,"c"=>9}
208
+ # h.pivot(:vals){|items| items.join("-") } => {"a"=>"1-4-7","b"=>"2-5-8","c"=>"3-6-9"}
209
+ # h.pivot(:vals){|items| items.inject{|sum,x| sum+=x } } => {"a"=>12,"b"=>15,"c"=>18}
210
+
211
+ def pivot(direction='keys',&block)
212
+ a=self.class.new
213
+ direction=direction.to_s
214
+ up=pivot_direction_up?(direction)
215
+ each_pair{|k1,v1|
216
+ v1.each_pair{|k2,v2|
217
+ k = up ? k1 : k2
218
+ a[k]=[] if (a[k]==nil or a[k]=={})
219
+ a[k]<<(v2)
220
+ }
221
+ }
222
+ if block
223
+ a.each_pair{|key,val| a[key]=block.call(val)}
224
+ end
225
+ a
226
+ end
227
+
228
+ protected
229
+
230
+ def pivot_direction_up?(direction_name)
231
+ case direction_name.to_s
232
+ when 'key','keys','up','left','out' then return true
233
+ when 'val','vals','down','right','in' then return false
234
+ else raise ArgumentError.new('Pivot direction must be either: key/keys/up/left/out or val/vals/down/right/in')
235
+ end
236
+ end
237
+
238
+ end
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Integer extensions
4
+
5
+ class Integer
6
+
7
+ # Syntactic sugar to yield n times to a block.
8
+ #
9
+ # Comparison to Integer#times:
10
+ # Integer#maps is similar to Integer#times except that the output from each
11
+ # call to the block is captured in an array element and that array is
12
+ # returned to the calling code.
13
+ #
14
+ # @return an array of any results
15
+ #
16
+ # @example Generate an array of three random numbers
17
+ # 3.maps{rand}
18
+ # => [0.0248131784304143, 0.814666170190905, 0.15812816258206]
19
+ #
20
+
21
+ def maps
22
+ return (0...self).map{|item| yield item}
23
+ end
24
+
25
+
26
+ end
@@ -0,0 +1,71 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # IO extensions
4
+
5
+ class IO
6
+
7
+
8
+ # Reads the entire file specified by name as individual lines as with IO#readlines,
9
+ # and returns those lines in an array of rows, where each row is an array of fields.
10
+ #
11
+ # @return [Array<Array<String>>] an array of rows, where each row is an array of fields.
12
+ #
13
+ # @example
14
+ # IO.readrows("my.tsv")
15
+ # => [["A1","B1","C1"],["A2","B2","C2"],["A3","B3","C3"]]
16
+ #
17
+ # @param [String] filename
18
+ # @param [Hash] options
19
+ # - Rows are separated by _row_ option, which defaults to Ruby's record separator $/ or "\n"
20
+ # - Cols are separated by _col_ option, which defaults to Ruby's string split separator $; or "\t"
21
+ #
22
+ # @example with options suitable for a file using TSV (Tab Separated Values)
23
+ # IO.readrows("my.tsv", :row=>"\n", :col=>"\t")
24
+ #
25
+ # Note: the col option is sent along to String#split, so can be a string or a regexp.
26
+ #
27
+ # @see
28
+ # - File#readline
29
+ # - File#readlines
30
+ # - File#readrow
31
+
32
+ def IO.readrows(filename, options={})
33
+ row_sep||=options[:row]||$/||"\n"
34
+ col_sep||=options[:col]||$;||"\t"
35
+ return IO.readlines(filename, row_sep).map{|line| line.chomp(row_sep).split(col_sep)}
36
+ end
37
+
38
+
39
+ # Read a line as with IO#readline and return the line as a row of fields.
40
+ #
41
+ # Note: the col option is sent along to String#split, so can be a string or a regexp.
42
+ #
43
+ # @return [Array<String>] fields
44
+ #
45
+ # @param [Hash] options
46
+ # - Rows are separated by _row_ option, which defaults to Ruby's record separator $/ or "\n"
47
+ # - Cols are separated by _col_ option, which defaults to Ruby's string split separator $; or "\t"
48
+ #
49
+ # @example
50
+ # file = File.new("my.tsv")
51
+ # file.readrow() => ["A1","B1","C1"]
52
+ # file.readrow() => ["A2","B2","C2"]
53
+ # file.readrow() => ["A3","B3","C3"]]
54
+ #
55
+ # @example with options suitable for a file using TSV (Tab Separated Values)
56
+ # file = File.new("my.tsv")
57
+ # file.readrow(:row=>"\n", :col=>"\t") => ["A1","B1","C1"]
58
+ # file.readrow(:row=>"\n", :col=>"\t") => ["A2","B2","C2"]
59
+ # file.readrow(:row=>"\n", :col=>"\t") => ["A3","B3","C3"]
60
+ #
61
+ # @see File#readline
62
+ # @see File#readlines
63
+ # @see File#readrows
64
+
65
+ def readrow(options={})
66
+ row_sep||=options[:row]||$/||"\n"
67
+ col_sep||=options[:col]||$;||"\t"
68
+ return readline(row_sep).chomp(row_sep).split(col_sep)
69
+ end
70
+
71
+ end
@@ -0,0 +1,84 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'pp'
3
+ require 'stringio'
4
+
5
+ # Kernel extensions
6
+
7
+ module Kernel
8
+
9
+ # See:
10
+ # - http://www.ruby-forum.com/topic/75258
11
+ # - In 1.9 (Ruby CVS HEAD) there is #__method__ and #__callee__
12
+ # - http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l90
13
+ #-
14
+ # Make this fast because its often doing logging & reporting.
15
+ # Inline this and use $1 because it's empirically faster than /1
16
+ #
17
+ # These two methods are always equal:
18
+ # caller_method_name(0) === my_method_name
19
+ #
20
+ # @example
21
+ # def foo
22
+ # puts my_method_name
23
+ # end
24
+ # foo
25
+ # => "foo"
26
+ #
27
+ # @return [String] my method name
28
+
29
+ def my_method_name
30
+ caller[0] =~ /`([^']*)'/ and $1
31
+ end
32
+
33
+
34
+ # See:
35
+ # - http://www.ruby-forum.com/topic/75258
36
+ # - In 1.9 (Ruby CVS HEAD) there is #__method__ and #__callee__
37
+ # - http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l90
38
+ #-
39
+ # Make this fast because its often doing logging & reporting.
40
+ # Inline this and use $1 because it's empirically faster than /1
41
+ #
42
+ # These two methods are always equal:
43
+ # caller_method_name(0) === my_method_name
44
+ #
45
+ # @example
46
+ # def foo
47
+ # puts caller_method_name(0)
48
+ # puts caller_method_name(1)
49
+ # end
50
+ # =>
51
+ # "foo"
52
+ # "irb_binding"
53
+ #
54
+ # @return [String] the method name of the caller at the index
55
+
56
+ def caller_method_name(caller_index=0)
57
+ caller[caller_index] =~ /`([^']*)'/ and $1
58
+ end
59
+
60
+
61
+ # Pretty print to a string.
62
+ #
63
+ # Created by Graeme Mathieson.
64
+ #
65
+ # See http://rha7dotcom.blogspot.com/2008/07/ruby-and-rails-how-to-get-pp-pretty.html
66
+ #
67
+ # @example
68
+ # pp_s(["foo","goo"])
69
+ # => "[\"foo\", \"goo\"]\n"
70
+ #
71
+ # @return [String] a pretty print string of the params
72
+
73
+ def pp_s(*objs)
74
+ str = StringIO.new
75
+ objs.each {|obj|
76
+ PP.pp(obj, str)
77
+ }
78
+ str.rewind
79
+ str.read
80
+ end
81
+ module_function :pp_s
82
+
83
+ end
84
+
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Math extensions
4
+
5
+ module Math
6
+
7
+
8
+ # @return [Float] the natural log of _num_
9
+ #
10
+ # @example
11
+ # Math.ln(2.719)
12
+ # => 1.00
13
+
14
+ def Math.ln(num)
15
+ Math.log(num)
16
+ end
17
+
18
+
19
+ # @return [Float] the log of _num_ in base _base_
20
+ #
21
+ # @example
22
+ # Math.logn(10000,10)
23
+ # => 4.00
24
+
25
+ def Math.logn(num,base)
26
+ Math.ln(num)/Math.ln(base)
27
+ end
28
+
29
+
30
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # NilClass provides an instantiatable object
4
+ # suitable for more careful thorough programming.
5
+
6
+ class NilClass
7
+
8
+ # @return [true]
9
+
10
+ def blank?
11
+ return true
12
+ end
13
+
14
+
15
+ # @return [false]
16
+
17
+ def size?
18
+ return false
19
+ end
20
+
21
+ end
22
+
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Numeric extensions
4
+
5
+ class Numeric
6
+
7
+
8
+ # @return 0 if the given flag is any of: nil, false, 0, [], {}
9
+ #
10
+ # @example
11
+ # 3.if(true) => 3
12
+ # 3.if(false) => 0
13
+ #
14
+
15
+ def if(flag)
16
+ if [nil,false,0,[],{}].include?(flag) then 0 else self end
17
+ end
18
+
19
+
20
+ # @return self if flag is nil, false, 0, [], {}; otherwise return 0.
21
+ #
22
+ # @example
23
+ # 3.unless(true) => 0
24
+ # 3.unless(false) => 3
25
+
26
+ def unless(flag)
27
+ if [nil,false,0,[],{}].include?(flag) then self else 0 end
28
+ end
29
+
30
+
31
+ # @return self as a percent, i.e. * 100 then call round.
32
+ #
33
+ # @example
34
+ # x = 0.12345
35
+ # x.percent => 12
36
+ # x.percent(1) => 12.3
37
+ # x.percent(2) => 12.34
38
+ # x.percent(-1) => 10
39
+
40
+ def percent(ndigits=0)
41
+ (self * 100).round(ndigits)
42
+ end
43
+
44
+ end
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Object extensions
4
+
5
+ class Object
6
+
7
+ # Syntactic sugar for arrays.
8
+ #
9
+ # Definition:
10
+ # object.in? array === array.include? object
11
+ #
12
+ # @example
13
+ # array=['a','b','c']
14
+ # object='b'
15
+ # object.in? array
16
+ # => true
17
+ #
18
+ # @return [Boolean] true iff this object is included in the array.
19
+ def in?(array)
20
+ array.include?(self)
21
+ end
22
+
23
+ end