epitools 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,306 @@
1
+
2
+
3
+ module Enumerable
4
+
5
+ #
6
+ # 'true' if the Enumerable has no elements
7
+ #
8
+ def blank?
9
+ not any?
10
+ end
11
+
12
+ #
13
+ # `.all` is more fun to type than `.to_a`
14
+ #
15
+ alias_method :all, :to_a
16
+
17
+ #
18
+ # `includes?` is gramatically correct.
19
+ #
20
+ alias_method :includes?, :include?
21
+
22
+
23
+ #
24
+ # Skip the first n elements and return an Enumerator for the rest, or pass them
25
+ # in succession to the block, if given. This is like "drop", but returns an enumerator
26
+ # instead of converting the whole thing to an array.
27
+ #
28
+ def skip(n)
29
+ if block_given?
30
+ each do |x|
31
+ if n > 0
32
+ n -= 1
33
+ else
34
+ yield x
35
+ end
36
+ end
37
+ else
38
+ enum_for :skip, n
39
+ end
40
+ end
41
+
42
+ #
43
+ # Split this enumerable into chunks, given some boundary condition. (Returns an array of arrays.)
44
+ #
45
+ # Options:
46
+ # :include_boundary => true #=> include the element that you're splitting at in the results
47
+ # (default: false)
48
+ # :after => true #=> split after the matched element (only has an effect when used with :include_boundary)
49
+ # (default: false)
50
+ # :once => flase #=> only perform one split (default: false)
51
+ #
52
+ # Examples:
53
+ # [1,2,3,4,5].split{ |e| e == 3 }
54
+ # #=> [ [1,2], [4,5] ]
55
+ #
56
+ # [1,2,3,4,5].split(:include_boundary=>true) { |e| e == 3 }
57
+ # #=> [ [1,2], [3,4,5] ]
58
+ #
59
+ # chapters = File.read("ebook.txt").split(/Chapter \d+/, :include_boundary=>true)
60
+ # #=> [ ["Chapter 1", ...], ["Chapter 2", ...], etc. ]
61
+ #
62
+ def split_at(matcher=nil, options={}, &block)
63
+ # TODO: Ruby 1.9 returns Enumerators for everything now. Maybe use that?
64
+
65
+ return self unless self.any?
66
+
67
+ include_boundary = options[:include_boundary] || false
68
+
69
+ if matcher.nil?
70
+ boundary_test_proc = block
71
+ else
72
+ if matcher.is_a? String or matcher.is_a? Regexp
73
+ boundary_test_proc = proc { |element| element[matcher] rescue nil }
74
+ else
75
+ boundary_test_proc = proc { |element| element == matcher }
76
+ #raise "I don't know how to split with #{matcher}"
77
+ end
78
+ end
79
+
80
+ chunks = []
81
+ current_chunk = []
82
+
83
+ splits = 0
84
+ max_splits = options[:once] == true ? 1 : options[:max_splits]
85
+
86
+ each do |e|
87
+
88
+ if boundary_test_proc.call(e) and (max_splits == nil or splits < max_splits)
89
+
90
+ if current_chunk.empty? and not include_boundary
91
+ next # hit 2 boundaries in a row... just keep moving, people!
92
+ end
93
+
94
+ if options[:after]
95
+ # split after boundary
96
+ current_chunk << e if include_boundary # include the boundary, if necessary
97
+ chunks << current_chunk # shift everything after the boundary into the resultset
98
+ current_chunk = [] # start a new result
99
+ else
100
+ # split before boundary
101
+ chunks << current_chunk # shift before the boundary into the resultset
102
+ current_chunk = [] # start a new result
103
+ current_chunk << e if include_boundary # include the boundary, if necessary
104
+ end
105
+
106
+ splits += 1
107
+
108
+ else
109
+ current_chunk << e
110
+ end
111
+
112
+ end
113
+
114
+ chunks << current_chunk if current_chunk.any?
115
+
116
+ chunks # resultset
117
+ end
118
+
119
+ #
120
+ # Split the array into chunks, cutting between the matched element and the next element.
121
+ #
122
+ # Example:
123
+ # [1,2,3,4].split_after{|e| e == 3 } #=> [ [1,2,3], [4] ]
124
+ #
125
+ def split_after(matcher=nil, options={}, &block)
126
+ options[:after] ||= true
127
+ options[:include_boundary] ||= true
128
+ split_at(matcher, options, &block)
129
+ end
130
+
131
+ #
132
+ # Split the array into chunks, cutting between the matched element and the previous element.
133
+ #
134
+ # Example:
135
+ # [1,2,3,4].split_before{|e| e == 3 } #=> [ [1,2], [3,4] ]
136
+ #
137
+ def split_before(matcher=nil, options={}, &block)
138
+ options[:include_boundary] ||= true
139
+ split_at(matcher, options, &block)
140
+ end
141
+
142
+ #
143
+ # Sum the elements
144
+ #
145
+ def sum
146
+ if block_given?
147
+ inject(0) { |total,elem| total + yield(elem) }
148
+ else
149
+ inject(0) { |total,elem| total + elem }
150
+ end
151
+ end
152
+
153
+ #
154
+ # Average the elements
155
+ #
156
+ def average
157
+ count = 0
158
+ sum = inject(0) { |total,n| count += 1; total + n }
159
+ sum / count.to_f
160
+ end
161
+
162
+ #
163
+ # The same as "map", except that if an element is an Array or Enumerable, map is called
164
+ # recursively on that element.
165
+ #
166
+ # Example:
167
+ # [ [1,2], [3,4] ].deep_map{|e| e ** 2 } #=> [ [1,4], [9,16] ]
168
+ #
169
+ def deep_map(depth=nil, &block)
170
+ map do |obj|
171
+
172
+ case obj
173
+ when Enumerable
174
+ obj.deep_map(&block)
175
+ else
176
+ block.call(obj)
177
+ end
178
+
179
+ end
180
+ end
181
+
182
+ alias_method :recursive_map, :deep_map
183
+ alias_method :map_recursively, :deep_map
184
+ alias_method :map_recursive, :deep_map
185
+
186
+ #
187
+ # The same as "select", except that if an element is an Array or Enumerable, select is called
188
+ # recursively on that element.
189
+ #
190
+ # Example:
191
+ # [ [1,2], [3,4] ].deep_map{|e| e ** 2 } #=> [ [1,4], [9,16] ]
192
+ #
193
+ def deep_select(depth=nil, &block)
194
+ select do |e|
195
+ if (e.is_a? Array or e.is_a? Enumerable) and (depth && depth > 0)
196
+ e.select(depth-1, &block)
197
+ else
198
+ block.call(e)
199
+ end
200
+ end
201
+ end
202
+
203
+ alias_method :recursive_select, :deep_select
204
+
205
+
206
+ #
207
+ # Identical to "reduce" in ruby1.9 (or foldl in haskell.)
208
+ #
209
+ # Example:
210
+ # array.foldl{|a,b| a + b } == array[1..-1].inject(array[0]){|a,b| a + b }
211
+ #
212
+ def foldl(methodname=nil, &block)
213
+ result = nil
214
+
215
+ raise "Error: pass a parameter OR a block, not both!" unless !!methodname ^ block_given?
216
+
217
+ if methodname
218
+
219
+ each_with_index do |e,i|
220
+ if i == 0
221
+ result = e
222
+ next
223
+ end
224
+
225
+ result = result.send(methodname, e)
226
+ end
227
+
228
+ else
229
+
230
+ each_with_index do |e,i|
231
+ if i == 0
232
+ result = e
233
+ next
234
+ end
235
+
236
+ result = block.call(result, e)
237
+ end
238
+
239
+ end
240
+
241
+ result
242
+ end
243
+
244
+ #
245
+ # Returns the powerset of the Enumerable
246
+ #
247
+ # Example:
248
+ # [1,2].powerset #=> [[], [1], [2], [1, 2]]
249
+ #
250
+ def powerset
251
+ # the bit pattern of the numbers from 0..2^(elements)-1 can be used to select the elements of the set...
252
+ a = to_a
253
+ (0...2**a.size).map do |bitmask|
254
+ a.select.with_index{ |e, i| bitmask[i] == 1 }
255
+ end
256
+ end
257
+
258
+ #
259
+ # Does the opposite of #zip -- converts [ [:a, 1], [:b, 2] ] to [ [:a, :b], [1, 2] ]
260
+ #
261
+ def unzip
262
+ # TODO: make it work for arrays containing uneven-length contents
263
+ to_a.transpose
264
+ end
265
+
266
+ #
267
+ # Associative grouping; groups all elements who share something in common with each other.
268
+ # You supply a block which takes two elements, and have it return true if they are "neighbours"
269
+ # (eg: belong in the same group).
270
+ #
271
+ # Example:
272
+ # [1,2,5,6].group_neighbours_by { |a,b| b-a <= 1 } #=> [ [1,2], [5,6] ]
273
+ #
274
+ # (Note: This is a very fast one-pass algorithm -- therefore, the groups must be pre-sorted.)
275
+ #
276
+ def group_neighbours_by(&block)
277
+ result = []
278
+ cluster = [first]
279
+ each_cons(2) do |a,b|
280
+ if yield(a,b)
281
+ cluster << b
282
+ else
283
+ result << cluster
284
+ cluster = [b]
285
+ end
286
+ end
287
+
288
+ result << cluster if cluster.any?
289
+
290
+ result
291
+ end
292
+ alias_method :group_neighbors_by, :group_neighbours_by
293
+
294
+
295
+ #
296
+ # Convert the array into a stable iterator (Iter) object.
297
+ #
298
+ def to_iter
299
+ Iter.new(to_a)
300
+ end
301
+ alias_method :iter, :to_iter
302
+
303
+
304
+ end
305
+
306
+
@@ -0,0 +1,201 @@
1
+
2
+ class Hash
3
+
4
+ #
5
+ # 'true' if the Hash has no entries
6
+ #
7
+ def blank?
8
+ not any?
9
+ end
10
+
11
+ #
12
+ # Runs "remove_blank_values" on self.
13
+ #
14
+ def remove_blank_values!
15
+ delete_if{|k,v| v.blank?}
16
+ self
17
+ end
18
+
19
+ #
20
+ # Returns a new Hash where blank values have been removed.
21
+ # (It checks if the value is blank by calling #blank? on it)
22
+ #
23
+ def remove_blank_values
24
+ dup.remove_blank_values!
25
+ end
26
+
27
+ #
28
+ # Runs map_values on self.
29
+ #
30
+ def map_values!(&block)
31
+ keys.each do |key|
32
+ value = self[key]
33
+ self[key] = yield(value)
34
+ end
35
+ self
36
+ end
37
+
38
+ #
39
+ # Transforms the values of the hash by passing them into the supplied
40
+ # block, and then using the block's result as the new value.
41
+ #
42
+ def map_values(&block)
43
+ dup.map_values!(&block)
44
+ end
45
+
46
+ #
47
+ # Runs map_keys on self.
48
+ #
49
+ def map_keys!(&block)
50
+ keys.each do |key|
51
+ value = delete(key)
52
+ self[yield(key)] = value
53
+ end
54
+ self
55
+ end
56
+
57
+ #
58
+ # Transforms the keys of the hash by passing them into the supplied block,
59
+ # and then using the blocks result as the new key.
60
+ #
61
+ def map_keys(&block)
62
+ dup.map_keys!(&block)
63
+ end
64
+
65
+ #
66
+ # Returns a new Hash whose values default to empty arrays. (Good for collecting things!)
67
+ #
68
+ # eg:
69
+ # Hash.of_arrays[:yays] << "YAY!"
70
+ #
71
+ def self.of_arrays
72
+ new {|h,k| h[k] = [] }
73
+ end
74
+
75
+ #
76
+ # Returns a new Hash whose values default to 0. (Good for counting things!)
77
+ #
78
+ # eg:
79
+ # Hash.of_integers[:yays] += 1
80
+ #
81
+ def self.of_integers
82
+ new(0)
83
+ end
84
+
85
+ #
86
+ # Hash keys become methods, kinda like OpenStruct. These methods have the lowest priority,
87
+ # so be careful. They will be overridden by any methods on Hash.
88
+ #
89
+ def self.lazy!
90
+ Hash.class_eval do
91
+ def method_missing(name, *args)
92
+ if args.any?
93
+ super
94
+ else
95
+ self[name] || self[name.to_s]
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ #
102
+ # `key?` and `includes?` is an alias for `include?`
103
+ #
104
+ alias_method :key?, :include?
105
+ alias_method :includes?, :include?
106
+
107
+ #
108
+ # Makes each element in the `path` array point to a hash containing the next element in the `path`.
109
+ # Useful for turning a bunch of strings (paths, module names, etc.) into a tree.
110
+ #
111
+ # Example:
112
+ # h = {}
113
+ # h.mkdir_p(["a", "b", "c"]) #=> {"a"=>{"b"=>{"c"=>{}}}}
114
+ # h.mkdir_p(["a", "b", "whoa"]) #=> {"a"=>{"b"=>{"c"=>{}, "whoa"=>{}}}}
115
+ #
116
+ def mkdir_p(path)
117
+ return if path.empty?
118
+ dir = path.first
119
+ self[dir] ||= {}
120
+ self[dir].mkdir_p(path[1..-1])
121
+ self
122
+ end
123
+
124
+ #
125
+ # Turn some nested hashes into a tree (returns an array of strings, padded on the left with indents.)
126
+ #
127
+ def tree(level=0, indent=" ")
128
+ result = []
129
+ dent = indent * level
130
+ each do |key, val|
131
+ result << dent+key
132
+ result += val.tree(level+1) if val.any?
133
+ end
134
+ result
135
+ end
136
+
137
+ #
138
+ # Print the result of `tree`
139
+ #
140
+ def print_tree
141
+ tree.each { |row| puts row }
142
+ nil
143
+ end
144
+
145
+ #
146
+ # Convert the hash into a GET query.
147
+ #
148
+ def to_query
149
+ params = ''
150
+ stack = []
151
+
152
+ each do |k, v|
153
+ if v.is_a?(Hash)
154
+ stack << [k,v]
155
+ else
156
+ params << "#{k}=#{v}&"
157
+ end
158
+ end
159
+
160
+ stack.each do |parent, hash|
161
+ hash.each do |k, v|
162
+ if v.is_a?(Hash)
163
+ stack << ["#{parent}[#{k}]", v]
164
+ else
165
+ params << "#{parent}[#{k}]=#{v}&"
166
+ end
167
+ end
168
+ end
169
+
170
+ params.chop! # trailing &
171
+ params
172
+ end
173
+
174
+ #
175
+ # Query a hash using MQL (see: http://wiki.freebase.com/wiki/MQL_operators for reference)
176
+ #
177
+ # Examples:
178
+ # > query(name: /steve/)
179
+ # > query(/title/ => ??)
180
+ # > query(articles: [{title: ??}])
181
+ # > query(responses: [])
182
+ # > query("date_of_birth<" => "2000")
183
+ #
184
+ def query(template)
185
+ results = []
186
+ template.each do |key,val|
187
+ case key
188
+ when Regexp, String
189
+ when Array
190
+ when Hash
191
+ results += hash.query(template)
192
+ end
193
+ end
194
+
195
+ map do |key,val|
196
+ end
197
+ end
198
+ alias_method :mql, :query
199
+
200
+ end
201
+