sixarm_ruby_ramp 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|