oha_extensions 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oha_extensions.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Bookrenter/Rafter
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # OhaExtensions
2
+
3
+ Gem adds convenience methods listed below to Object, Hash and Array classes.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'oha_extensions'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install oha_extensions
18
+
19
+ ## Usage
20
+
21
+ ***
22
+ ### Object extension methods:
23
+
24
+ * - has_additional_functionality_in(*files)
25
+ * - send_if_respond_to(method, *args)
26
+
27
+ ***
28
+ ### Hash extension methods:
29
+
30
+ * - sum(&block)
31
+ * - increment(key, amount=1, &block)
32
+ * - percent(key, &block)
33
+ * - assert_required_keys(*required_keys)
34
+ * - select_pairs(&block)
35
+ * - Hash.from_xml_string(s, options = {})
36
+
37
+ ***
38
+ ### Array extension methods:
39
+
40
+ * - stats
41
+ * - average
42
+ * - process_in_batches(batch_size)
43
+ * - to_hash_with_keys(options={}, &block)
44
+ * - to_lookup_hash()
45
+ * - to_identity_hash(id_proc = nil)
46
+ * - rand
47
+ * - next
48
+ * - shuffle
49
+ * - delete(first_element)
50
+
51
+ ***
52
+ # Credits
53
+
54
+ [Oha_extensions](https://github.com/bkr/oha_extensions) is maintained by [Bookrenter/Rafter](http://github.com/bkr) and is funded by [BookRenter.com](http://www.bookrenter.com "BookRenter.com").
55
+
56
+ ![BookRenter.com Logo](http://assets0.bookrenter.com/images/header/bookrenter_logo.gif "BookRenter.com")
57
+
58
+ # Copyright
59
+
60
+ Copyright (c) 2012 Bookrenter.com. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,111 @@
1
+ #This class adds the stats methods to array which computes sum, min, max, med, mean, count, std deviation
2
+ module ArrayExtension
3
+ #Given an array of values it returns the mean, median, min, max in a hash
4
+ #*array*:: An array whose values are used to calculate the various statistics
5
+ #returns:: A hash with the following keys
6
+ #* sum
7
+ #* mean
8
+ #* min
9
+ #* max
10
+ #* median
11
+ #* count (number of items in the array)
12
+ #<b> All keys will => 0, if the array is empty</b>
13
+ #<b> The array is automatically sorted when you call stats</b>
14
+ def stats
15
+ return {:sum => 0, :mean => 0, :min => 0, :max => 0, :median => 0, :std_dev => 0, :count => 0} if empty?
16
+ out = Hash.new
17
+ sort!
18
+ out[:sum] = inject(0){|sum, element| sum + element}
19
+ out[:mean] = out[:sum]/size.to_f
20
+ out[:min] = min
21
+ out[:max] = max
22
+ out[:median] = size % 2 == 0 ? (self[size/2] + self[size/2 - 1]) / 2.0 : self[size/2]
23
+ out[:count] = size
24
+ if size > 1
25
+ out[:std_dev] = Math.sqrt((inject(0){|sum_square, element| sum_square += element * element} - out[:sum]*out[:mean]) / (size - 1))
26
+ else
27
+ out[:std_dev] = 0
28
+ end
29
+ return out
30
+ end
31
+
32
+ #returns:: The average value of the elements in the array
33
+ def average
34
+ return stats[:sum] / size.to_f
35
+ end
36
+
37
+ #Divides the calling array into +batch_size+ batches, (the last batch could be less than +batch_size+ if the calling array.size % batch_size != 0) and yields each batch
38
+ #*batch_size*:: The number elements to yield to the given block
39
+ #Example:
40
+ # (1..30).to_a.process_in_batches(10) do |batch|
41
+ # p batch
42
+ # end
43
+ #
44
+ # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
45
+ # [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
46
+ # [21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
47
+ def process_in_batches(batch_size)
48
+ raise ArgumentError if batch_size.nil? or batch_size <= 0
49
+
50
+ index = 0
51
+
52
+ while index < self.size
53
+ yield self[index...index+batch_size]
54
+ index += batch_size
55
+ end
56
+ end
57
+
58
+ def to_hash_with_keys(options={}, &block)
59
+ options = {:value_acts_as_array => false}.merge(options)
60
+ return self.inject(Hash.new) do |injection, var|
61
+ key = block.call(var)
62
+ if options[:value_acts_as_array]
63
+ if injection[key].nil?
64
+ injection[key] = [var]
65
+ else
66
+ injection[key] << var
67
+ end
68
+ else
69
+ injection[key] = var
70
+ end
71
+
72
+ injection
73
+ end
74
+ end
75
+
76
+ def to_lookup_hash()
77
+ h = Hash.new
78
+ self.each do |e|
79
+ h[e] = block_given? ? yield(e) : true
80
+ end
81
+ return h
82
+ end
83
+
84
+ # useful for creating in memory mappings of ActiveRecord models
85
+ def to_identity_hash(id_proc = nil)
86
+ h = Hash.new
87
+ self.each do |e|
88
+ key = id_proc ? id_proc.call(e) : (block_given? ? yield(e) : e.id)
89
+ h[key] = e
90
+ end
91
+ return h
92
+ end
93
+
94
+ def rand
95
+ self[Kernel.rand(self.length)]
96
+ end
97
+
98
+ def next
99
+ @next_index = @next_index.nil? ? 0 : (@next_index + 1) % self.size
100
+ return self[@next_index]
101
+ end
102
+
103
+ def shuffle
104
+ self.sort_by{ Kernel.rand }
105
+ end
106
+
107
+ def delete_first(element)
108
+ index = self.index(element)
109
+ self.delete_at(index) if index
110
+ end
111
+ end
@@ -0,0 +1,159 @@
1
+ require 'nokogiri'
2
+
3
+ module HashExtension
4
+
5
+ #returns:: The sum of each element in the hash
6
+ #An optional block can be given which takes two parameters, key and value for each element in the hash. The return value of the block is summed for each element in the hash.
7
+ #If the result of sum is nil, 0 is returned
8
+ #Examples:
9
+ # {:a => 1, :b => 2, :c => 3}.sum #returns 6
10
+ # {:a => ['foo', 1], :b => ['monkey', 2], :c => ['bunny', 3]}.sum { |k, v| v[1] } #returns 6
11
+ # {:a => ['foo', 1], :b => ['monkey', 2], :c => ['bunny', 3]}.sum { |k, v| v } #returns ['foo', 1, 'monkey', 2, 'bunny', 3] <b>Order of elements is NOT guaranteed</b>
12
+ # {}.sum #returns 0
13
+ def sum(&block)
14
+ block = lambda { |k, v| v } if block.nil?
15
+
16
+ total = nil
17
+
18
+ each do |k, v|
19
+ total.nil? ? total = block.call(k, v) : total += block.call(k, v)
20
+ end
21
+
22
+ return total || 0
23
+ end
24
+
25
+ #Increments the value pointed to from the key
26
+ #If the key is nil then it is initialized to amount
27
+ #An optional block may be given, which is passed +key+, and each key in the hash. The block should return true for the key you wish to increment.
28
+ #Examples:
29
+ # h = Hash.new #h['foo'] = nil
30
+ # h.increment('foo') #1
31
+ # h.increment('foo') #2
32
+ #
33
+ # age = Hash.new
34
+ # age['0 - 18'] = 0
35
+ # age['18 - 24'] = 0
36
+ # age['24 - 99999'] = 0
37
+ #
38
+ # #increment the key where 18 is in range of the min and max
39
+ # age.increment(18) do |v, e|
40
+ # min, max = e.split(' - ')
41
+ # v >= min.to_i && v < max.to_i
42
+ # end
43
+ #
44
+ # assert_equal(0, age['0 - 18'])
45
+ # assert_equal(1, age['18 - 24'])
46
+ # assert_equal(0, age['24 - 99999'])
47
+ def increment(key, amount=1, &block)
48
+ if block.nil?
49
+ key_to_use = key
50
+ else
51
+ key_to_use = self.keys.detect { |k| block.call(key, k) }
52
+ end
53
+
54
+ if self[key_to_use].nil?
55
+ self[key_to_use] = amount
56
+ else
57
+ self[key_to_use] += amount
58
+ end
59
+ end
60
+
61
+ #returns:: What percent of the sum of the hash is the value for +key+
62
+ #Examples:
63
+ # {:a => 1, :b => 2, :c => 3, :d => 4}.percent(:c) #0.30 because 3 is 30% of 10 and 10 is the total of the hash
64
+ # {:a => ['foo', 1], :b => ['monkey', 2], :c => ['bunny', 3], :d => ['kitty', 4]}.percent(:c) { |e| e[1] } #0.30
65
+ # {:a => 0} #0.0, if the sum of the hash is 0, then 0 is returned
66
+ def percent(key, &block)
67
+ block = lambda { |v| v } if block.nil?
68
+ sum_block = lambda { |k, v| block.call(v) }
69
+
70
+ total = self.sum(&sum_block)
71
+ return 0 if total == 0
72
+ return block.call(self[key]) / total.to_f
73
+ end
74
+
75
+ #If keys does not include everything in required_keys, throw an ArgumentError.
76
+ #
77
+ #*required_keys*: list of keys that must be present for the hash (if a required key hashes to nil, but is passed it is still valid.
78
+ #Example::
79
+ # {:happy => nil}.assert_required_keys(:happy) #will not raise error
80
+ #required_keys may be passed as strings, symbols or both. Likewise the keys in the has maybe a strings or symbols or both.
81
+ #Example::
82
+ # {:happy => 'bunny'}.assert_required_keys(:happy) #will not raise error
83
+ # {'happy' => 'bunny'}.assert_required_keys(:happy) #will not raise error
84
+ #====Raises
85
+ #*ArgumentError*:: if a required key is missing
86
+ def assert_required_keys(*required_keys)
87
+ keys_not_passed = [required_keys].flatten.map { |required_key| required_key.to_s } - self.stringify_keys.keys
88
+ raise(ArgumentError, "The following keys were nil when expected not to be: #{keys_not_passed.join(", ")}") unless keys_not_passed.empty?
89
+ end
90
+ alias_method :must_include, :assert_required_keys
91
+
92
+
93
+ def select_pairs(&block)
94
+ return Hash[*self.select(&block).flatten]
95
+ end
96
+
97
+ def self.included(base)
98
+ base.extend ClassMethods
99
+ end
100
+
101
+ module ClassMethods
102
+ # Generates a hash from XML. This is specifically being used generate JSON for the API. It makes the assumption that elements contain arrays
103
+ # must be explicitly specified. Assuming otherwise generates larger JSON.
104
+ # This also utilizes XML attributes which Hash.from_xml ignores.
105
+ def from_xml_string(s, options = {})
106
+ options = {:array_nodes => [], :parent_array_nodes => []}.merge(options)
107
+ return node_to_hash(Nokogiri.parse(s).children.first, options)
108
+ end
109
+
110
+ private
111
+
112
+ def node_to_hash(node, options)
113
+ children = node.children.select {|n| n.element?}
114
+ node_name = node.name
115
+ hash = {}
116
+
117
+ if ! node.attributes.empty?
118
+ hash[node_name] = {}
119
+ node.attributes.each do |attr_name, attr_value|
120
+ hash[node_name][attr_name] = attr_value.to_s
121
+ end
122
+ content_hash = hash[node_name]
123
+ # this is the name of the key for the sub elements, could also use something like 'content'
124
+ node_name = node.name
125
+ else
126
+ content_hash = hash
127
+ end
128
+
129
+ if children.empty?
130
+ nc = node.children.detect{|n| n.text?}
131
+ content_hash[node_name] = nc.nil? ? nil : nc.text
132
+
133
+ if options[:parent_array_nodes].include?(node_name)
134
+ content_hash[node_name] = []
135
+ end
136
+ else
137
+ children_hash = children.inject({}) do |acc, node|
138
+ child_hash = node_to_hash(node, options)
139
+ child_hash.each do |key, value|
140
+ if options[:array_nodes].include?(key)
141
+ acc[key] = [] if acc[key].nil?
142
+ acc[key] << value
143
+ else
144
+ acc[key] = value if acc[key].nil?
145
+ end
146
+ end
147
+ acc
148
+ end
149
+ content_hash[node_name] = children_hash
150
+
151
+ if options[:parent_array_nodes].include?(node_name)
152
+ content_hash[node_name] = children_hash.values.flatten
153
+ end
154
+ end
155
+
156
+ return hash
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,11 @@
1
+ module ObjectExtension
2
+ def has_additional_functionality_in(*files)
3
+ files.each do |file|
4
+ require_dependency "#{name.underscore}_extensions/#{file}"
5
+ end
6
+ end
7
+
8
+ def send_if_respond_to(method, *args)
9
+ self.respond_to?(method) ? self.send(method, *args) : nil
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module OhaExtensions
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,17 @@
1
+ require "oha_extensions/version"
2
+ require "oha_extensions/hash_extension"
3
+ require "oha_extensions/object_extension"
4
+ require "oha_extensions/array_extension"
5
+
6
+ class Array
7
+ include ArrayExtension
8
+ end
9
+
10
+ class Hash
11
+ include HashExtension
12
+ end
13
+
14
+ class Object
15
+ include ObjectExtension
16
+ end
17
+
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/oha_extensions/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Bookrenter/Rafter"]
6
+ gem.email = ["cp@bookrenter.com"]
7
+ gem.description = %q{Extends Object, Hash and Array classes with additional methods.}
8
+ gem.summary = %q{Additional methods for Object, Hash, Array classes.}
9
+ gem.homepage = "https://github.com/bkr/oha_extensions"
10
+
11
+ gem.add_development_dependency('mocha', '> 0')
12
+ gem.add_development_dependency('shoulda', "> 0")
13
+ gem.add_dependency('nokogiri', '> 0')
14
+
15
+ gem.files = `git ls-files`.split($\)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.name = "oha_extensions"
19
+ gem.require_paths = ["lib"]
20
+ gem.version = OhaExtensions::VERSION
21
+ end
@@ -0,0 +1,373 @@
1
+ require "test_helper"
2
+
3
+ class ArrayExtensionTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_array_stats
9
+ #= Test Empty
10
+ stats = [].stats
11
+ stats.values.all? { |e| e == 0 }
12
+
13
+ #== Only 0s
14
+ stats = Array[0].stats
15
+ assert_equal 0, stats[:sum]
16
+ assert_equal 0, stats[:mean]
17
+ assert_equal 0, stats[:min]
18
+ assert_equal 0, stats[:max]
19
+ assert_equal 0, stats[:median]
20
+ assert_equal 1, stats[:count]
21
+ assert_equal 0, stats[:std_dev]
22
+
23
+ stats = Array[0, 0, 0].stats
24
+ assert_equal 0, stats[:sum]
25
+ assert_equal 0, stats[:mean]
26
+ assert_equal 0, stats[:min]
27
+ assert_equal 0, stats[:max]
28
+ assert_equal 0, stats[:median]
29
+ assert_equal 3, stats[:count]
30
+ assert_equal 0, stats[:std_dev]
31
+
32
+ #== Integers
33
+ #==== simple in order (even size)
34
+ stats = Array[0, 1, 2, 3].stats
35
+ assert_equal 6, stats[:sum]
36
+ assert_in_delta(1.5, stats[:mean], 2 ** -20)
37
+ assert_equal 0, stats[:min]
38
+ assert_equal 3, stats[:max]
39
+ assert_in_delta(1.5, stats[:median], 2 ** -20)
40
+ assert_equal 4, stats[:count]
41
+ assert_in_delta(1.29,stats[:std_dev], 0.1)
42
+
43
+ #==== simple out of order (odd size)
44
+ stats = Array[0, 1, 2, 3, 1].stats
45
+ assert_equal 7, stats[:sum]
46
+ assert_in_delta(1.4, stats[:mean], 2 ** -20)
47
+ assert_equal 0, stats[:min]
48
+ assert_equal 3, stats[:max]
49
+ assert_in_delta(1, stats[:median], 2 ** -20)
50
+ assert_equal 5, stats[:count]
51
+ assert_in_delta(1.14,stats[:std_dev], 0.1)
52
+
53
+ #==== 0 sum with negatives
54
+ stats = Array[-99, 99, 0].stats
55
+ assert_equal 0, stats[:sum]
56
+ assert_in_delta(0.0, stats[:mean], 2 ** -20)
57
+ assert_equal -99, stats[:min]
58
+ assert_equal 99, stats[:max]
59
+ assert_in_delta(0.0, stats[:median], 2 ** -20)
60
+ assert_equal 3, stats[:count]
61
+ assert_in_delta(99, stats[:std_dev], 0.1)
62
+
63
+ #==== Random
64
+ a = rand(1000) - rand(1000)
65
+ b = rand(1000) - rand(1000)
66
+ c = rand(1000) - rand(1000)
67
+ input = [a, b, c]
68
+ stats = input.stats
69
+ assert_in_delta((a + b + c), stats[:sum], 2 ** -20)
70
+ assert_in_delta((a + b + c)/3.0, stats[:mean], 2 ** -20)
71
+ assert_equal input.min, stats[:min]
72
+ assert_equal input.max, stats[:max]
73
+ assert_in_delta(input[1], stats[:median], 2 ** -20)
74
+ assert_equal 3, stats[:count]
75
+
76
+ #== Floats
77
+ #==== simple in order (even size)
78
+ stats = Array[0.0, 1.4, 2.567, 3.8].stats
79
+ assert_in_delta(7.767, stats[:sum], 2 ** -20)
80
+ assert_in_delta(1.94175, stats[:mean], 2 ** -20)
81
+ assert_in_delta(0.0, stats[:min], 2 ** -20)
82
+ assert_in_delta(3.8, stats[:max] , 2 ** -20)
83
+ assert_in_delta(1.9835, stats[:median], 2 ** -20)
84
+ assert_equal 4, stats[:count]
85
+ assert_in_delta(1.62, stats[:std_dev], 0.1)
86
+
87
+ #==== simple out of order (odd size)
88
+ stats = Array[0.0, 1.4, 2.567, 3.8, 1.378].stats
89
+ assert_in_delta(9.145, stats[:sum], 2 ** -20)
90
+ assert_in_delta(1.829, stats[:mean], 2 ** -20)
91
+ assert_in_delta(0.0, stats[:min], 2 ** -20)
92
+ assert_in_delta(3.8, stats[:max] , 2 ** -20)
93
+ assert_in_delta(1.4, stats[:median], 2 ** -20)
94
+ assert_equal 5, stats[:count]
95
+ assert_in_delta(1.428, stats[:std_dev], 0.1)
96
+
97
+
98
+ #==== 0 sum with negatives
99
+ stats = Array[-99.88, 99.88, 0].stats
100
+ assert_in_delta(0.0, stats[:sum], 2 ** -20)
101
+ assert_in_delta(0.0, stats[:mean], 2 ** -20)
102
+ assert_in_delta(-99.88, stats[:min], 2 ** -20)
103
+ assert_in_delta(99.88, stats[:max] , 2 ** -20)
104
+ assert_in_delta(0.0, stats[:median], 2 ** -20)
105
+ assert_equal 3, stats[:count]
106
+ assert_in_delta(99.88, stats[:std_dev], 0.1)
107
+
108
+
109
+ #==== Random
110
+ a = rand() * rand(1000) - rand() * rand(1000)
111
+ b = rand() * rand(1000) - rand() * rand(1000)
112
+ c = rand() * rand(1000) - rand() * rand(1000)
113
+ input = [a, b, c]
114
+ stats = input.stats
115
+ assert_in_delta((a + b + c), stats[:sum], 2 ** -20)
116
+ assert_in_delta((a + b + c)/3.0, stats[:mean], 2 ** -20)
117
+ assert_in_delta(input.min, stats[:min], 2 ** -20)
118
+ assert_in_delta(input.max, stats[:max] , 2 ** -20)
119
+ assert_in_delta(input[1], stats[:median], 2 ** -20)
120
+ assert_equal 3, stats[:count]
121
+
122
+ #== Mixed
123
+ a = rand() * rand(1000) - rand() * rand(1000)
124
+ b = rand() * rand(1000) - rand() * rand(1000)
125
+ c = rand() * rand(1000) - rand() * rand(1000)
126
+ d = rand(1000) - rand(1000)
127
+ e = rand(1000) - rand(1000)
128
+ f = rand(1000) - rand(1000)
129
+ input = [a, b, c, d, e, f]
130
+ stats = input.stats
131
+ assert_in_delta((a + b + c + d + e + f), stats[:sum], 2 ** -20)
132
+ assert_in_delta((a + b + c + d + e + f)/6.0, stats[:mean], 2 ** -20)
133
+ assert_in_delta(input.min, stats[:min], 2 ** -20)
134
+ assert_in_delta(input.max, stats[:max] , 2 ** -20)
135
+ assert_in_delta((input[3] + input[2])/2.0, stats[:median], 2 ** -20)
136
+ assert_equal 6, stats[:count]
137
+ end
138
+
139
+ def test_average
140
+ assert_equal 0, [-1, 0, 1].average
141
+ assert_equal 1, [1].average
142
+ assert_equal 46.5, [10, 45, 34, 97].average
143
+ assert_equal 66.065, [34.7, 97.43].average
144
+
145
+ a = rand() * rand(1000) - rand() * rand(1000)
146
+ b = rand() * rand(1000) - rand() * rand(1000)
147
+ c = rand() * rand(1000) - rand() * rand(1000)
148
+ d = rand(1000) - rand(1000)
149
+ e = rand(1000) - rand(1000)
150
+ f = rand(1000) - rand(1000)
151
+ input = [a, b, c, d, e, f]
152
+ assert_in_delta((a + b + c + d + e + f)/6.0, input.average, 2 ** -20)
153
+ end
154
+
155
+ #======================================================================
156
+ #====================== Test process_in_batches =======================
157
+ #======================================================================
158
+ def setup_process_in_batches_tests
159
+ @array = %W[one two three four five six seven eight nine ten]
160
+ @empty = Array.new
161
+ end
162
+
163
+ def test_process_in_batches_missing_batch_size_argument
164
+ setup_process_in_batches_tests
165
+ assert_raise(ArgumentError) { @array.process_in_batches }
166
+ end
167
+
168
+ def test_process_in_batches_empty_array
169
+ setup_process_in_batches_tests
170
+ assert_nil @empty.process_in_batches(3)
171
+ end
172
+
173
+ def test_process_in_batches_batch_size_less_than_or_equal_to_zero
174
+ setup_process_in_batches_tests
175
+ assert_raise(ArgumentError) { @array.process_in_batches(0) }
176
+ assert_raise(ArgumentError) { @array.process_in_batches(-3) }
177
+ end
178
+
179
+ def test_process_in_batches_batch_size_less_than_array_size
180
+ setup_process_in_batches_tests
181
+
182
+ #should get three batchs; two with 4 elements and one with 2 elements
183
+ batch_size = 4
184
+ batch_cnt = 0
185
+
186
+ @array.process_in_batches(batch_size) do |batch|
187
+ case batch_cnt
188
+ when 0, 1
189
+ assert_equal batch_size, batch.size
190
+ when 2
191
+ assert_equal 2, batch.size
192
+ end
193
+ batch_cnt += 1
194
+ end
195
+
196
+ assert_equal 3, batch_cnt
197
+ end
198
+
199
+ def test_process_in_batches_batch_size_greater_than_array_size
200
+ setup_process_in_batches_tests
201
+
202
+ #should get one batch only
203
+ batch_size = @array.size + 1
204
+ batch_cnt = 0
205
+
206
+ @array.process_in_batches(batch_size) do |batch|
207
+ batch_cnt += 1
208
+ assert_equal @array.size, batch.size
209
+ end
210
+ assert_equal 1, batch_cnt
211
+ end
212
+
213
+ def test_process_in_batches_batch_size_equal_to_array_size
214
+ setup_process_in_batches_tests
215
+
216
+ #should get one batch only
217
+ batch_size = @array.size
218
+ batch_cnt = 0
219
+
220
+ @array.process_in_batches(batch_size) do |batch|
221
+ batch_cnt += 1
222
+ assert_equal @array.size, batch.size
223
+ end
224
+ assert_equal 1, batch_cnt
225
+ end
226
+ #======================================================================
227
+ #==================== End test process_in_batches =====================
228
+ #======================================================================
229
+
230
+ def test_to_hash_with_keys
231
+ assert_equal({}, [].to_hash_with_keys { |e| e })
232
+
233
+ actual = [1, 2, 3, 4].to_hash_with_keys { |e| e + 10 }
234
+ expected = {11 => 1, 12 => 2, 13 => 3, 14 => 4}
235
+ assert_equal(expected, actual)
236
+
237
+ actual = [{:msg => 'apples'}, {:msg => 'foos'}, {:msg => 'cows'}].to_hash_with_keys { |e| "i_like_#{e[:msg]}".to_sym }
238
+ expected = { :i_like_apples => {:msg => 'apples'}, :i_like_foos => {:msg => 'foos'}, :i_like_cows => {:msg => 'cows'} }
239
+ assert_equal(expected, actual)
240
+ end
241
+
242
+ def test_to_lookup_hash
243
+ assert_equal({}, [].to_lookup_hash)
244
+ assert_equal({1 => true, 2 => true, 3 => true}, [1, 2, 3].to_lookup_hash)
245
+ assert_equal({1 => 2, 2 => 3, 3 => 4}, [1, 2, 3].to_lookup_hash {|e| e + 1})
246
+ end
247
+
248
+ context "to_identity_hash" do
249
+ should "use id attribute as key with no args" do
250
+ o1 = mock
251
+ o1.stubs(:id).returns(123)
252
+ o2 = mock
253
+ o2.stubs(:id).returns(456)
254
+ o3 = mock
255
+ o3.stubs(:id).returns(789)
256
+ assert_equal({o1.id => o1, o2.id => o2, o3.id => o3}, [o1, o2, o3].to_identity_hash)
257
+ end
258
+
259
+ should "allow symbol proc as the first argument for key creation" do
260
+ o1 = mock
261
+ o1.stubs(:foo).returns(123)
262
+ o2 = mock
263
+ o2.stubs(:foo).returns(456)
264
+ o3 = mock
265
+ o3.stubs(:foo).returns(789)
266
+ assert_equal({o1.foo => o1, o2.foo => o2, o3.foo => o3}, [o1, o2, o3].to_identity_hash(&:foo))
267
+ end
268
+
269
+ should "allow proc to specify key" do
270
+ o1 = mock
271
+ o1.stubs(:foo).returns(123)
272
+ o2 = mock
273
+ o2.stubs(:foo).returns(456)
274
+ o3 = mock
275
+ o3.stubs(:foo).returns(789)
276
+ assert_equal({o1.foo => o1, o2.foo => o2, o3.foo => o3}, [o1, o2, o3].to_identity_hash {|e| e.foo})
277
+ end
278
+ end
279
+
280
+
281
+ context "rand" do
282
+ context "empty array" do
283
+ setup do
284
+ @execute_result = [].rand
285
+ end
286
+
287
+ should "be nil" do
288
+ assert_nil(@execute_result)
289
+ end
290
+ end
291
+
292
+ context "array with 1 item" do
293
+ setup do
294
+ @execute_result = ['foo'].rand
295
+ end
296
+
297
+ should "be just that item" do
298
+ assert_equal 'foo', @execute_result
299
+ end
300
+ end
301
+
302
+ context "array with multiple items" do
303
+ setup do
304
+ @array = ['a', 'b', 'c']
305
+ @execute_result = @array.rand
306
+ end
307
+
308
+ should "return an item from the array" do
309
+ assert_contains(@array, @execute_result)
310
+ end
311
+ end
312
+ end
313
+
314
+ context "next" do
315
+ context "empty array" do
316
+ should "return nil" do
317
+ assert_equal nil, [].next
318
+ end
319
+ end
320
+
321
+ context "single element" do
322
+ setup do
323
+ @element = 1
324
+ @array = [@element]
325
+ end
326
+
327
+ should "always return only element" do
328
+ assert_equal @element, @array.next
329
+ assert_equal @element, @array.next
330
+ assert_equal @element, @array.next
331
+ end
332
+ end
333
+
334
+ context "multiple elements" do
335
+ setup do
336
+ @array = [1, 'a']
337
+ end
338
+
339
+ should "loop" do
340
+ assert_equal 1, @array.next
341
+ assert_equal 'a', @array.next
342
+ assert_equal 1, @array.next
343
+ end
344
+ end
345
+ end
346
+
347
+ context "delete_first" do
348
+ context "empty array" do
349
+ should "return nil" do
350
+ assert_equal nil, [].delete_first("a")
351
+ end
352
+ end
353
+
354
+ context "multiple elements" do
355
+ setup do
356
+ @ary = [1,'a',3,'a']
357
+ end
358
+
359
+ should "delete first element found" do
360
+ deleted = @ary.delete_first('a')
361
+ assert_equal 'a', deleted
362
+ assert_equal [1, 3, 'a'], @ary
363
+ end
364
+
365
+ should "return nil if nothing found" do
366
+ deleted = @ary.delete_first('b')
367
+ assert_equal nil, deleted
368
+ assert_equal [1, 'a', 3, 'a'], @ary
369
+ end
370
+ end
371
+ end
372
+
373
+ end
@@ -0,0 +1,211 @@
1
+ require "test_helper"
2
+
3
+ class HashExtensionTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @simple = {:a => 1, :b => 2, :c => 3}
7
+ @simple_sum = 6
8
+
9
+ @zeros = {:zero => 0, :another_zero => 0, :yet_another_zero => 0}
10
+
11
+ @integers = {:an_integer => 48, :an_negative => -77, :zero => 0}
12
+ @integers_sum = -29
13
+
14
+ @floats = {:a_float => 24.5, :a_negative_float => -74.8, :zero => 0.0}
15
+ @floats_sum = -50.3
16
+
17
+ @mixed = @integers.merge(@floats)
18
+ @mixed_sum = @integers_sum + @floats_sum
19
+ end
20
+
21
+ def test_empty
22
+ assert_equal 0, {}.sum
23
+ assert_equal 0, {}.sum { |k, v| v }
24
+ end
25
+
26
+ def test_zeros
27
+ assert_equal 0, @zeros.sum
28
+ end
29
+
30
+ def test_integers
31
+ assert_equal @integers_sum, @integers.sum
32
+ end
33
+
34
+ def test_floats
35
+ assert_equal @floats_sum, @floats.sum
36
+ end
37
+
38
+ def test_mixed
39
+ assert_equal @mixed_sum, @mixed.sum
40
+ end
41
+
42
+ def test_block
43
+ test = {:a => ['foo', 48], :b => ['monkey', -99], :c => ['bunny', 34]}
44
+
45
+ #sum index 1 of each element
46
+ assert_equal -17, test.sum { |k, v| v[1] }
47
+
48
+ #sum index 0
49
+ assert_match 'foo', test.sum { |k, v| v[0] }
50
+ assert_match 'monkey', test.sum { |k, v| v[0] }
51
+ assert_match 'bunny', test.sum { |k, v| v[0] }
52
+
53
+ #sum key
54
+ assert_match 'a', test.sum { |k, v| k.to_s }
55
+ assert_match 'b', test.sum { |k, v| k.to_s }
56
+ assert_match 'c', test.sum { |k, v| k.to_s }
57
+
58
+ #sum entire array
59
+ assert_equal true, test.sum { |k, v| v }.any? { |e| e == 'foo' }
60
+ assert_equal true, test.sum { |k, v| v }.any? { |e| e == 'monkey' }
61
+ assert_equal true, test.sum { |k, v| v }.any? { |e| e == 'bunny' }
62
+ assert_equal true, test.sum { |k, v| v }.any? { |e| e == 48 }
63
+ assert_equal true, test.sum { |k, v| v }.any? { |e| e == -99 }
64
+ assert_equal true, test.sum { |k, v| v }.any? { |e| e == 34 }
65
+
66
+ #sum manipulating value
67
+ assert_equal 0, test.sum { |k, v| v[1] - v[1] }
68
+ assert_equal -34, test.sum { |k, v| v[1] * 2 }
69
+ assert_equal [], test.sum { |k, v| v - v }
70
+ end
71
+
72
+
73
+ def test_increment
74
+ h = Hash.new
75
+
76
+ assert_equal nil, h['foo']
77
+ assert_equal 1, h.increment('foo')
78
+ assert_equal 2, h.increment('foo')
79
+
80
+ h = Hash.new
81
+ assert_equal 10, h.increment(['foo'], 10)
82
+ assert_equal 20, h.increment(['foo'], 10)
83
+
84
+ age = Hash.new
85
+ age['0 - 18'] = 0
86
+ age['18 - 24'] = 0
87
+ age['24 - 99999'] = 0
88
+
89
+ age.increment(18) do |v, e|
90
+ min, max = e.split(' - ')
91
+ v >= min.to_i && v < max.to_i
92
+ end
93
+
94
+ assert_equal(0, age['0 - 18'])
95
+ assert_equal(1, age['18 - 24'])
96
+ assert_equal(0, age['24 - 99999'])
97
+ end
98
+
99
+ def test_percent
100
+ h = {'a' => 25, 'b' => 50, 'c' => 25}
101
+ assert_in_delta(0.25, h.percent('a'), 2 ** -20)
102
+ assert_in_delta(0.50, h.percent('b'), 2 ** -20)
103
+ assert_in_delta(0.25, h.percent('c'), 2 ** -20)
104
+
105
+ h = {'hot' => ['steamy', 3], 'hotter' => ['smoking', 4], 'hottest' => ['global warming', 7]}
106
+ assert_in_delta(0.21428571428571428571, h.percent('hot') { |v| v[1] }, 2 ** -20)
107
+ assert_in_delta(0.28571428571428571428, h.percent('hotter') { |v| v[1] }, 2 ** -20)
108
+ assert_in_delta(0.5, h.percent('hottest') { |v| v[1] }, 2 ** -20)
109
+
110
+ assert_raise(NoMethodError) { h.percent('cold') }
111
+
112
+ h = {'a' => 0}
113
+ assert_equal 0, h.percent('a')
114
+ end
115
+
116
+ context ".select_pairs" do
117
+ context "empty" do
118
+ setup do
119
+ @hash = {}
120
+ @execute_result = @hash.select_pairs { |k, v| v % 2 == 0 }
121
+ end
122
+
123
+ should "return empty hash" do
124
+ assert_equal({}, @execute_result)
125
+ end
126
+ end
127
+
128
+ context "populated" do
129
+ setup do
130
+ @hash = {'A' => 1, 'B' => 2}
131
+ @execute_result = @hash.select_pairs { |k, v| v % 2 == 0 }
132
+ end
133
+
134
+ should "return hash where values are even" do
135
+ assert_equal({'B' => 2}, @execute_result)
136
+ end
137
+ end
138
+ end
139
+
140
+ context ".from_xml_string" do
141
+ should "handle empty root node" do
142
+ xml = '<a />'
143
+ expected = {'a' => nil}
144
+ assert_equal expected, Hash.from_xml_string(xml)
145
+ end
146
+
147
+ should "handle empty string root node" do
148
+ xml = '<a></a>'
149
+ expected = {'a' => nil}
150
+ assert_equal expected, Hash.from_xml_string(xml)
151
+ end
152
+
153
+ should "handle text string root node" do
154
+ xml = '<a>text</a>'
155
+ expected = {'a' => 'text'}
156
+ assert_equal expected, Hash.from_xml_string(xml)
157
+ end
158
+
159
+ should "handle attributes in root node" do
160
+ xml = '<a a1="aye1" />'
161
+ expected = {'a' => {'a1' => 'aye1', 'a' => nil}}
162
+ assert_equal expected, Hash.from_xml_string(xml)
163
+ end
164
+
165
+ should "handle element nodes" do
166
+ xml = '<a><b>value</b></a>'
167
+ expected = {'a' => {'b' => 'value'}}
168
+ assert_equal expected, Hash.from_xml_string(xml)
169
+ end
170
+
171
+ should "handle empty element nodes" do
172
+ xml = '<a><b/><c/></a>'
173
+ expected = {'a' => {'b' => nil, 'c' => nil}}
174
+ assert_equal expected, Hash.from_xml_string(xml)
175
+ end
176
+
177
+ should "handle attributes in nodes" do
178
+ xml = '<a a1="aye1" a2="aye2"><b b1="bee1"/><c c1="see1">see2</c></a>'
179
+ expected = {'a' => {'a1' => 'aye1', 'a2' => 'aye2', 'a' => {
180
+ 'b' => {'b1' => 'bee1', 'b' => nil},
181
+ 'c' => {'c1' => 'see1', 'c' => 'see2'}}}}
182
+ assert_equal expected, Hash.from_xml_string(xml)
183
+ end
184
+
185
+ should "flatten array nodes by default" do
186
+ xml = '<a><b>bee1</b><b>bee2</b><c /></a>'
187
+ expected = {'a' => {'b' => 'bee1', 'c' => nil}}
188
+ assert_equal expected, Hash.from_xml_string(xml)
189
+ end
190
+
191
+ context "with array nodes" do
192
+ should "not flatten array nodes when array_nodes specified" do
193
+ xml = '<a><b>bee1</b><b>bee2</b><c /></a>'
194
+ expected = {'a' => {'b' => ['bee1', 'bee2'], 'c' => nil}}
195
+ assert_equal expected, Hash.from_xml_string(xml, :array_nodes => ['b'])
196
+ end
197
+
198
+ should "not flatten array nodes and remove inner nodes when array_nodes and parent_array_nodes specified" do
199
+ xml = '<a><b>bee1</b><b>bee2</b><c>see</c></a>'
200
+ expected = {'a' => ['bee1', 'bee2', 'see']}
201
+ assert_equal expected, Hash.from_xml_string(xml, :array_nodes => ['b', 'c'], :parent_array_nodes => ['a'])
202
+ end
203
+
204
+ should "have empty array node when no child nodes present and parent_array_nodes specified" do
205
+ xml = '<a> \n </a>'
206
+ expected = {'a' => []}
207
+ assert_equal expected, Hash.from_xml_string(xml, :parent_array_nodes => ['a'])
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+
11
+ require 'test/unit'
12
+ require 'shoulda'
13
+ require 'mocha'
14
+ require File.dirname(__FILE__) + '/../lib/oha_extensions'
15
+
16
+ require 'oha_extensions'
17
+
18
+ class Test::Unit::TestCase
19
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oha_extensions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bookrenter/Rafter
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mocha
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>'
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>'
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: shoulda
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>'
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>'
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: nokogiri
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>'
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>'
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Extends Object, Hash and Array classes with additional methods.
63
+ email:
64
+ - cp@bookrenter.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - LICENSE
72
+ - README.md
73
+ - Rakefile
74
+ - lib/oha_extensions.rb
75
+ - lib/oha_extensions/array_extension.rb
76
+ - lib/oha_extensions/hash_extension.rb
77
+ - lib/oha_extensions/object_extension.rb
78
+ - lib/oha_extensions/version.rb
79
+ - oha_extensions.gemspec
80
+ - test/oha_extensions/array_extension_test.rb
81
+ - test/oha_extensions/hash_extension_test.rb
82
+ - test/test_helper.rb
83
+ homepage: https://github.com/bkr/oha_extensions
84
+ licenses: []
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 1.8.24
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Additional methods for Object, Hash, Array classes.
107
+ test_files:
108
+ - test/oha_extensions/array_extension_test.rb
109
+ - test/oha_extensions/hash_extension_test.rb
110
+ - test/test_helper.rb