sixarm_ruby_ramp 2.1.0
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/.gemtest +0 -0
- data/CHANGELOG.txt +51 -0
- data/INSTALL.txt +32 -0
- data/LICENSE.txt +12 -0
- data/README.rdoc +240 -0
- data/Rakefile +8 -0
- data/VERSION +1 -0
- data/lib/sixarm_ruby_ramp/array.rb +397 -0
- data/lib/sixarm_ruby_ramp/class.rb +38 -0
- data/lib/sixarm_ruby_ramp/csv.rb +58 -0
- data/lib/sixarm_ruby_ramp/date.rb +55 -0
- data/lib/sixarm_ruby_ramp/enumerable.rb +483 -0
- data/lib/sixarm_ruby_ramp/file.rb +17 -0
- data/lib/sixarm_ruby_ramp/fixnum.rb +34 -0
- data/lib/sixarm_ruby_ramp/hash.rb +238 -0
- data/lib/sixarm_ruby_ramp/integer.rb +26 -0
- data/lib/sixarm_ruby_ramp/io.rb +71 -0
- data/lib/sixarm_ruby_ramp/kernel.rb +84 -0
- data/lib/sixarm_ruby_ramp/math.rb +30 -0
- data/lib/sixarm_ruby_ramp/nil.rb +22 -0
- data/lib/sixarm_ruby_ramp/numeric.rb +44 -0
- data/lib/sixarm_ruby_ramp/object.rb +23 -0
- data/lib/sixarm_ruby_ramp/process.rb +221 -0
- data/lib/sixarm_ruby_ramp/string.rb +230 -0
- data/lib/sixarm_ruby_ramp/symbol.rb +29 -0
- data/lib/sixarm_ruby_ramp/time.rb +61 -0
- data/lib/sixarm_ruby_ramp/xml.rb +204 -0
- data/lib/sixarm_ruby_ramp/yaml.rb +10 -0
- data/lib/sixarm_ruby_ramp.rb +8 -0
- data/test/sixarm_ruby_ramp/io_test.txt +1 -0
- data/test/sixarm_ruby_ramp/xml_test_1.xml +5 -0
- data/test/sixarm_ruby_ramp/xml_test_2.xml +5 -0
- data/test/sixarm_ruby_ramp/xml_test_msword_clean.html +1 -0
- data/test/sixarm_ruby_ramp/xml_test_msword_dirty.html +148 -0
- data/test/sixarm_ruby_ramp_test.rb +9 -0
- data.tar.gz.sig +1 -0
- metadata +113 -0
- metadata.gz.sig +0 -0
@@ -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
|