duct_tape 0.0.4

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.
Files changed (55) hide show
  1. data/Gemfile +10 -0
  2. data/Gemfile.lock +35 -0
  3. data/LICENSE +25 -0
  4. data/README.md +223 -0
  5. data/Rakefile +38 -0
  6. data/VERSION +1 -0
  7. data/duct_tape.gemspec +106 -0
  8. data/ext/mkrf_conf.rb +36 -0
  9. data/git_hooks/env_vars.sh +287 -0
  10. data/git_hooks/post-commit +43 -0
  11. data/git_hooks/post-merge +8 -0
  12. data/git_hooks/pre-commit +273 -0
  13. data/install_git_hooks +17 -0
  14. data/lib/algorithms/containers/heap.rb +15 -0
  15. data/lib/algorithms/containers/priority_queue.rb +11 -0
  16. data/lib/algorithms/containers.rb +1 -0
  17. data/lib/duct_tape/autoassociative_array.rb +110 -0
  18. data/lib/duct_tape.rb +10 -0
  19. data/lib/ext/array.rb +327 -0
  20. data/lib/ext/boolean.rb +3 -0
  21. data/lib/ext/datetime.rb +7 -0
  22. data/lib/ext/dir.rb +59 -0
  23. data/lib/ext/file.rb +40 -0
  24. data/lib/ext/hash.rb +83 -0
  25. data/lib/ext/kernel.rb +593 -0
  26. data/lib/ext/numeric.rb +74 -0
  27. data/lib/ext/object.rb +17 -0
  28. data/lib/ext/pathname.rb +114 -0
  29. data/lib/ext/range.rb +7 -0
  30. data/lib/ext/regexp.rb +12 -0
  31. data/lib/ext/string.rb +54 -0
  32. data/lib/ext/symbol.rb +8 -0
  33. data/lib/ext/time.rb +32 -0
  34. data/lib/ext/uri.rb +16 -0
  35. data/spec/algorithms/containers/heap_spec.rb +19 -0
  36. data/spec/algorithms/containers/priority_queue_spec.rb +19 -0
  37. data/spec/duct_tape/autoassociative_array_spec.rb +139 -0
  38. data/spec/ext/array_spec.rb +407 -0
  39. data/spec/ext/boolean_spec.rb +19 -0
  40. data/spec/ext/datetime_spec.rb +10 -0
  41. data/spec/ext/dir_spec.rb +46 -0
  42. data/spec/ext/file_spec.rb +10 -0
  43. data/spec/ext/hash_spec.rb +73 -0
  44. data/spec/ext/kernel_spec.rb +64 -0
  45. data/spec/ext/numeric_spec.rb +61 -0
  46. data/spec/ext/object_spec.rb +19 -0
  47. data/spec/ext/pathname_spec.rb +13 -0
  48. data/spec/ext/range_spec.rb +10 -0
  49. data/spec/ext/regexp_spec.rb +10 -0
  50. data/spec/ext/string_spec.rb +73 -0
  51. data/spec/ext/symbol_spec.rb +10 -0
  52. data/spec/ext/time_spec.rb +19 -0
  53. data/spec/ext/uri_spec.rb +28 -0
  54. data/spec/spec_helper.rb +7 -0
  55. metadata +183 -0
@@ -0,0 +1,110 @@
1
+ module Containers
2
+ class AutoassociativeArray
3
+ def initialize
4
+ @values = []
5
+ @columns = Hash.new { |hsh,key| hsh[key] = {} }
6
+ @hash = Hash.new { |hsh,key| hsh[key] = [] }
7
+ self
8
+ end
9
+
10
+ def insert(*args)
11
+ @values |= [args]
12
+ args.size.times do |i|
13
+ @columns[i][@values[-1][i]] = @values[-1]
14
+ @hash[@values[-1][i]].push(@values[-1])
15
+ end
16
+ self
17
+ end
18
+
19
+ def partial_match(*args)
20
+ matches = {}
21
+ ret = []
22
+ (1..args.size).reverse_each do |i|
23
+ args.combination(i) do |subset|
24
+ check = match_impl(*subset)
25
+ matches[subset] = check unless check.empty?
26
+ end
27
+ most_matches = matches.map { |k,v| v.size }.max
28
+ matches.reject! { |k,v| v.size < most_matches }
29
+ unless matches.empty?
30
+ matches.each { |k,v| ret |= v }
31
+ break
32
+ end
33
+ end
34
+ (ret && ret.one? ? ret[0] : ret)
35
+ end
36
+
37
+ def [](*args)
38
+ ret = match_impl(*args)
39
+ (ret && ret.one? ? ret[0] : ret)
40
+ end
41
+
42
+ def by_column(col, key)
43
+ (@columns.has_key?(col) && @columns[col].has_key?(key)) ? @columns[col][key] : nil
44
+ end
45
+
46
+ def empty?
47
+ @values.empty?
48
+ end
49
+
50
+ def length
51
+ @values.size
52
+ end
53
+ alias_method :size, :length
54
+
55
+ def method_missing(*args, &block)
56
+ ret = @values.__send__(*args, &block)
57
+ rebuild_hash
58
+ ret
59
+ end
60
+
61
+ def clear
62
+ @hash.clear
63
+ @values.clear
64
+ @columns.clear
65
+ self
66
+ end
67
+
68
+ def inspect
69
+ @values.inspect
70
+ end
71
+
72
+ def to_s
73
+ @values.to_s
74
+ end
75
+
76
+ def dup
77
+ ret = self.class.new
78
+ @values.each { |set| ret.insert(*set) }
79
+ ret
80
+ end
81
+
82
+ def <<(ary)
83
+ insert(*ary)
84
+ end
85
+
86
+ private
87
+
88
+ def rebuild_hash
89
+ @hash.clear
90
+ @columns.clear
91
+ @values.each_with_index do |ary,idx|
92
+ type_assert(ary, Array)
93
+ ary.size.times do |i|
94
+ @columns[i][@values[idx][i]] = @values[idx]
95
+ @hash[@values[idx][i]].push(@values[idx])
96
+ end
97
+ end
98
+ self
99
+ end
100
+
101
+ def match_impl(*args)
102
+ ret = @hash[args.first]
103
+ args[1..-1].each do |k|
104
+ ret &= @hash[k]
105
+ break if ret.empty?
106
+ end
107
+ ret
108
+ end
109
+ end
110
+ end
data/lib/duct_tape.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'facets'
3
+ Dir[__DIR__("ext", "*.rb")].each { |f| require f }
4
+
5
+ if gem_installed?('algorithms')
6
+ require 'algorithms'
7
+ automatic_require "algorithms"
8
+ end
9
+
10
+ automatic_require
data/lib/ext/array.rb ADDED
@@ -0,0 +1,327 @@
1
+ class Array
2
+ # Returns a copy of self deep_merged with another array
3
+ def deep_merge(second)
4
+ target = deep_dup
5
+ target.deep_merge!(second.deep_dup)
6
+ target
7
+ end
8
+
9
+ # Deep_merge self with another array
10
+ def deep_merge!(second)
11
+ return nil unless second
12
+ type_assert(second, Array)
13
+ changed = nil
14
+ second.each_index do |k|
15
+ if self[k].is_a?(Array) and second[k].is_a?(Array)
16
+ changed |= true if self[k].deep_merge!(second[k])
17
+ elsif self[k].is_a?(Hash) and second[k].is_a?(Hash)
18
+ changed |= true if self[k].deep_merge!(second[k])
19
+ elsif exclude?(second[k])
20
+ self << second[k]
21
+ changed |= true
22
+ end
23
+ end
24
+ return nil unless changed
25
+ self
26
+ end
27
+
28
+ # 3 Forms:
29
+ # Multiplied by an Integer, returns a single array with the repeated contents of self
30
+ # Multiplied by a String, returns self.join
31
+ # Multiplied by an Array, returns the set-wise cross-product of the two Arrays
32
+ def *(second)
33
+ ret = []
34
+ case second
35
+ when Integer
36
+ second.times { |i| ret += dup }
37
+ when String
38
+ return join(second)
39
+ when Array
40
+ each { |x| second.each { |y| ret << [x,y].flatten } }
41
+ else
42
+ raise TypeError.new("can't convert #{second.class} into Integer")
43
+ end
44
+ return ret
45
+ end
46
+
47
+ # Returns the set-wise n-th power of self. (The length of the return value
48
+ # is equal to: self.length ** n)
49
+ # e.g [0,1] ** 0 #=> []
50
+ # e.g [0,1] ** 1 #=> [[0], [1]]
51
+ # e.g [0,1] ** 2 #=> [[0, 0], [0, 1], [1, 0], [1, 1]]
52
+ # e.g [0,1] ** 3 #=> [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1],
53
+ # # [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
54
+ def **(n)
55
+ type_assert(n, Integer)
56
+ ret = []
57
+ if n > 1
58
+ ret = dup
59
+ (n - 1).times {
60
+ temp = []
61
+ ret.each { |x| each { |y| temp << [x,y].flatten } }
62
+ ret = temp
63
+ }
64
+ elsif n == 1
65
+ ret = map { |item| [item] }
66
+ end
67
+ return ret
68
+ end
69
+
70
+ # Returns a new Array rejecting objects based on if the block-mapped
71
+ # values are unique
72
+ def uniq_by(&block)
73
+ ret = dup
74
+ ret.uniq_by!(&block)
75
+ ret
76
+ end
77
+
78
+ # 1st Form:
79
+ # [1,1,1].unanimous? #=> true
80
+ # [1,1,2].unanimous? #=> false
81
+ #
82
+ # 2nd Form:
83
+ # [1,1,1].unanimous?(1) #=> true
84
+ # [1,1,1].unanimous?(2) #=> false
85
+ #
86
+ # 3rd Form:
87
+ # [1,1,1].unanimous? { |i| i == 2 } #=> true
88
+ #
89
+ # 4th Form:
90
+ # [1,3,5].unanimous?(true) { |i| i % 2 == 1 } #=> true
91
+ def unanimous?(arg=nil, &block)
92
+ ret = true
93
+ cmp = (arg.nil? ? (block_given? ? block[first] : first) : arg)
94
+ each_with_index do |elem,index|
95
+ next if index == 0 && arg.nil?
96
+ ret &&= (block_given? ? (cmp == block[elem]) : (cmp == elem))
97
+ break unless ret
98
+ end
99
+ ret
100
+ end
101
+
102
+ # Converts certain Arrays to Hashes:
103
+ # ["a","b","c"].to_h #=> {0=>"a", 1=>"b", 2=>"c"}
104
+ # [[1,2], [3,4]].to_h #=> {1=>2, 3=>4}
105
+ # [{1 => 2}, {3 => 4}].to_h #=> {1=>2, 3=>4}
106
+ # [{"name" => 1, "value" => 2},
107
+ # {"name" => 3, "value" => 4}].to_h #=> {1=>2, 3=>4}
108
+ # [{:x => 1, :y => 2},
109
+ # {:x => 3, :y => 4}].to_h(:x, :y) #=> {1=>2, 3=>4}
110
+ # [{1 => 2, 3 => 4}, {1 => 4}].to_h #=> {1=>[2, 4], 3=>4}
111
+ def to_h(name_key="name", value_key="value")
112
+ #raise "Elements are not unique!" unless self == uniq
113
+ ret = {}
114
+ collisions = Hash.new { |hsh,key| hsh[key] = 0 }
115
+ each_with_index do |elem,index|
116
+ temp = {}
117
+ if elem.is_a?(Hash)
118
+ temp = elem
119
+ if elem[name_key] and elem[value_key] and elem.length == 2
120
+ temp = {elem[name_key] => elem[value_key]}
121
+ elsif elem[name_key.to_s] and elem[value_key.to_s] and elem.length == 2
122
+ temp = {elem[name_key.to_s] => elem[value_key.to_s]}
123
+ elsif elem[name_key.to_sym] and elem[value_key.to_sym] and elem.length == 2
124
+ temp = {elem[name_key.to_sym] => elem[value_key.to_sym]}
125
+ end
126
+ elsif elem.is_a?(Array)
127
+ if elem.length == 2
128
+ temp[elem.first] = elem.last
129
+ elsif elem.length > 2
130
+ temp[elem.first] = elem[1..-1]
131
+ else
132
+ temp[index] = elem.first
133
+ end
134
+ else
135
+ temp[index] = elem
136
+ end
137
+ temp.each do |k,v|
138
+ if ret.has_key?(k)
139
+ if collisions[k] == 0
140
+ if ret[k] != v
141
+ collisions[k] += 1
142
+ ret[k] = [ret[k], v]
143
+ end
144
+ elsif ret[k].exclude?(v)
145
+ collisions[k] += 1
146
+ ret[k] << v
147
+ end
148
+ else
149
+ ret[k] = v
150
+ end
151
+ end
152
+ end
153
+ ret
154
+ end
155
+ alias_method :to_hash, :to_h
156
+
157
+ # Creates a hash with keys equal to the contents of self and values equal to the
158
+ # mapped array's values
159
+ def map_to_h(&block)
160
+ [self, map(&block)].transpose.to_h
161
+ end
162
+ alias_method :map_to_hash, :map_to_h
163
+
164
+ # Chunks an array into segments of maximum length
165
+ # [1,2,3,4,5,6,7,8,9,10].chunk(3) #=> [[1,2,3], [4,5,6], [7,8,9], [10]]
166
+ def chunk(max_length=nil, &block)
167
+ if ::RUBY_VERSION >= "1.9" && block_given?
168
+ super(&block)
169
+ else
170
+ each_slice(max_length).to_a
171
+ end
172
+ end
173
+
174
+ def not_empty?
175
+ !empty?
176
+ end
177
+
178
+ #
179
+ # Statistics from:
180
+ # http://github.com/christianblais/utilities.git
181
+ #
182
+
183
+ # Add each object of the array to each other in order to get the sum, as long as all objects respond to + operator
184
+ def sum
185
+ flatten.compact.inject(:+)
186
+ end
187
+
188
+ def product
189
+ flatten.compact.inject(:*)
190
+ end
191
+
192
+ # Calculate squares of each item
193
+ def squares
194
+ map { |i| i ** 2 }
195
+ end
196
+
197
+ # Return a new array containing the rank of each value
198
+ # Ex: [1, 2, 2, 8, 9] #=> [0.0, 1.5, 1.5, 3.0, 4.0]
199
+ def ranks(already_sorted=false)
200
+ a = already_sorted ? self : sort
201
+ map { |i| (a.index(i) + a.rindex(i)) / 2.0 }
202
+ end
203
+
204
+ # Calculate square roots of each item
205
+ def sqrts
206
+ map { |i| Math.sqrt(i) }
207
+ end
208
+
209
+ # Calculate the arithmetic mean of the array, as long as all objects respond to / operator
210
+ def mean
211
+ a = flatten.compact
212
+ (a.size > 0) ? a.sum.to_f / a.size : 0.0
213
+ end
214
+ alias_method :average, :mean
215
+
216
+ # TODO - Geometric mean
217
+
218
+ # Calculate the number of occurences for each element of the array
219
+ def frequencies
220
+ inject(Hash.new(0)) { |h,v| h[v] += 1; h }
221
+ end
222
+
223
+ # Return the variance of self
224
+ def variance(population=false)
225
+ m = mean.to_f
226
+ map { |v| (v - m) ** 2 }.sum / (size - (population ? 0 : 1))
227
+ end
228
+
229
+ # Return the (sample|population) standard deviation of self
230
+ # If population is set to true, then we consider the dataset as the complete population
231
+ # Else, we consider the dataset as a sample, so we use the sample standard deviation (size - 1)
232
+ def standard_deviation(population=false)
233
+ size > 1 ? Math.sqrt(variance(population)) : 0.0
234
+ end
235
+ alias_method :std_dev, :standard_deviation
236
+
237
+ # Return the median of sorted self
238
+ def median(already_sorted=false)
239
+ return nil if empty?
240
+ a = already_sorted ? self : sort
241
+ m_pos = size / 2
242
+ size % 2 == 1 ? a[m_pos] : (a[m_pos-1] + a[m_pos]).to_f / 2
243
+ end
244
+ alias_method :second_quartile, :median
245
+
246
+ # Return the first quartile of self
247
+ def first_quartile(already_sorted=false)
248
+ return nil if size < 4
249
+ a = already_sorted ? self : sort
250
+ a[0..((size / 2) - 1)].median(true)
251
+ end
252
+ alias_method :lower_quartile, :first_quartile
253
+
254
+ # Return the last quartile of self
255
+ def last_quartile(already_sorted=false)
256
+ return nil if size < 4
257
+ a = already_sorted ? self : sort
258
+ a[((size / 2) + 1)..-1].median(true)
259
+ end
260
+ alias_method :upper_quartile, :last_quartile
261
+
262
+ # Return an array containing the first, the second and the last quartile of self
263
+ def quartiles(already_sorted=false)
264
+ a = already_sorted ? self : sort
265
+ [a.first_quartile(true), a.median(true), a.last_quartile(true)]
266
+ end
267
+
268
+ # Calculate the interquartile range of self
269
+ def interquartile_range(already_sorted=false)
270
+ return nil if size < 4
271
+ a = already_sorted ? self : sort
272
+ a.last_quartile - a.first_quartile
273
+ end
274
+
275
+ # Return a hash of modes with their corresponding occurences
276
+ def modes
277
+ fre = frequencies
278
+ max = fre.values.max
279
+ fre.select { |k, f| f == max }
280
+ end
281
+
282
+ # Return the midrange of sorted self
283
+ def midrange(already_sorted=false)
284
+ return nil if empty?
285
+ a = already_sorted ? self : sort
286
+ (a.first + a.last) / 2.0
287
+ end
288
+
289
+ # Return the statistical range of sorted self
290
+ def statistical_range(already_sorted=false)
291
+ return nil if empty?
292
+ a = already_sorted ? self : sort
293
+ (a.last - a.first)
294
+ end
295
+
296
+ # Return all statistics from self in a simple hash
297
+ def statistics(already_sorted=false)
298
+ sorted = sort
299
+
300
+ {
301
+ :first => self.first,
302
+ :last => self.last,
303
+ :size => self.size,
304
+ :sum => self.sum,
305
+ :squares => self.squares,
306
+ :sqrts => self.sqrts,
307
+ :min => self.min,
308
+ :max => self.max,
309
+ :mean => self.mean,
310
+ :frequencies => self.frequencies,
311
+ :variance => self.variance,
312
+ :standard_deviation => self.standard_deviation,
313
+ :population_variance => self.variance(true),
314
+ :population_standard_deviation => self.standard_deviation(true),
315
+ :modes => self.modes,
316
+
317
+ # Need to be sorted...
318
+ :ranks => sorted.ranks(true),
319
+ :median => sorted.median(true),
320
+ :midrange => sorted.midrange(true),
321
+ :statistical_range => sorted.statistical_range(true),
322
+ :quartiles => sorted.quartiles(true),
323
+ :interquartile_range => sorted.interquartile_range(true)
324
+ }
325
+ end
326
+ alias_method :stats, :statistics
327
+ end
@@ -0,0 +1,3 @@
1
+ module Boolean; end
2
+ class FalseClass; include Boolean; end
3
+ class TrueClass; include Boolean; end
@@ -0,0 +1,7 @@
1
+ require 'date'
2
+
3
+ class DateTime < Date
4
+ def to_time
5
+ Time.parse(self.to_s)
6
+ end
7
+ end
data/lib/ext/dir.rb ADDED
@@ -0,0 +1,59 @@
1
+ require 'pathname'
2
+
3
+ class Dir
4
+ # Determine the relative path based on pwd
5
+ def self.relative_path(abs_path, from=Dir.pwd)
6
+ Pathname.new(abs_path).expand_path.relative_path_from(Pathname.new(from)).to_s
7
+ end
8
+
9
+ def self.absolute_path(path)
10
+ Pathname.new(path).expand_path.to_s
11
+ end
12
+
13
+ def self.empty?(dir)
14
+ entries(dir).join == "..."
15
+ end
16
+
17
+ def relative_path
18
+ Dir.relative_path(self.path)
19
+ end
20
+
21
+ def empty?
22
+ Dir.empty?(self)
23
+ end
24
+
25
+ def absolute_path
26
+ Dir.absolute_path(self.path)
27
+ end
28
+
29
+ def children
30
+ entries.map_to_h { |name| Pathname.join(absolute_path, name) }
31
+ end
32
+ alias_method :to_h, :children
33
+
34
+ def [](*path)
35
+ pathname = Pathname.new(File.join(path.flatten))
36
+ return nil unless pathname.exist?
37
+ pathname
38
+ end
39
+
40
+ def /(path)
41
+ self[path]
42
+ end
43
+
44
+ def files
45
+ children.values.reject { |v| !(File.file?(v)) }
46
+ end
47
+
48
+ def directories
49
+ children.values.reject { |v| !(File.directory?(v)) }
50
+ end
51
+
52
+ def writable?
53
+ File.writable?(self.path)
54
+ end
55
+
56
+ def readable?
57
+ File.readable?(self.path)
58
+ end
59
+ end
data/lib/ext/file.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'pathname'
2
+
3
+ class File
4
+
5
+ def self.relative_path(abs_path, pwd=Dir.pwd)
6
+ Dir.relative_path(abs_path, pwd)
7
+ end
8
+
9
+ def self.absolute_path(path)
10
+ Dir.absolute_path(path)
11
+ end
12
+
13
+ def relative_path
14
+ Dir.relative_path(self.path)
15
+ end
16
+
17
+ def absolute_path
18
+ Dir.absolute_path(self.path)
19
+ end
20
+
21
+ def dirname
22
+ File.dirname(self.path)
23
+ end
24
+
25
+ def basename(*args)
26
+ File.basename(self.path, *args)
27
+ end
28
+
29
+ def writable?
30
+ File.writable?(self.path)
31
+ end
32
+
33
+ def readable?
34
+ File.readable?(self.path)
35
+ end
36
+
37
+ def executable?
38
+ File.executable?(self.path)
39
+ end
40
+ end
data/lib/ext/hash.rb ADDED
@@ -0,0 +1,83 @@
1
+ class Hash
2
+ # Merges self with another second, recursively.
3
+ #
4
+ # This code was lovingly stolen from some random gem:
5
+ # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
6
+ #
7
+ # Thanks to whoever made it.
8
+ #
9
+ # Modified to provide same functionality with Arrays
10
+
11
+ def deep_merge(second)
12
+ target = deep_dup
13
+ target.deep_merge!(second.deep_dup)
14
+ target
15
+ end
16
+
17
+ # From: http://www.gemtacular.com/gemdocs/cerberus-0.2.2/doc/classes/Hash.html
18
+ # File lib/cerberus/utils.rb, line 42
19
+ # Modified to provide same functionality with Arrays
20
+
21
+ def deep_merge!(second)
22
+ return nil unless second
23
+ type_assert(second, Hash)
24
+ second.each_pair do |k,v|
25
+ if self[k].is_a?(Array) and second[k].is_a?(Array)
26
+ self[k].deep_merge!(second[k])
27
+ elsif self[k].is_a?(Hash) and second[k].is_a?(Hash)
28
+ self[k].deep_merge!(second[k])
29
+ else
30
+ self[k] = second[k]
31
+ end
32
+ end
33
+ end
34
+
35
+ def to_h
36
+ self
37
+ end
38
+ alias_method :to_hash, :to_h
39
+
40
+ def select_keys(other, &block)
41
+ target = dup
42
+ target.select_keys!(other, &block)
43
+ target
44
+ end
45
+ alias_method :&, :select_keys
46
+
47
+ def select_keys!(other, &block)
48
+ type_assert(other, Array, Hash)
49
+ unless block_given?
50
+ other = other.keys if Hash === other
51
+ block = proc { |k| other.include?(k) }
52
+ end
53
+ self.reject! { |key,val| !block[key] }
54
+ end
55
+
56
+ def reject_keys(other, &block)
57
+ target = dup
58
+ target.reject_keys!(other, &block)
59
+ target
60
+ end
61
+ alias_method :-, :reject_keys
62
+
63
+ def reject_keys!(other, &block)
64
+ type_assert(other, Array, Hash)
65
+ unless block_given?
66
+ other = other.keys if Hash === other
67
+ block = proc { |k| other.include?(k) }
68
+ end
69
+ self.reject! { |key,val| block[key] }
70
+ end
71
+
72
+ def chunk(max_length=nil, &block)
73
+ if ::RUBY_VERSION >= "1.9" && block_given?
74
+ super(&block)
75
+ else
76
+ each_slice(max_length).to_a.map! { |ary| ary.to_h }
77
+ end
78
+ end
79
+
80
+ def not_empty?(arg)
81
+ !empty?
82
+ end
83
+ end