duct_tape 0.0.4

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