epitools 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 epitron
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = epitools
2
+
3
+ There's some interesting stuff in here. Unfortunately, it's all gross and
4
+ disorganized. This will change. :D
5
+
6
+ == Note on Patches/Pull Requests
7
+
8
+ * Fork the project.
9
+ * Make your feature addition or bug fix.
10
+ * Add tests for it. This is important so I don't break it in a
11
+ future version unintentionally.
12
+ * Commit, do not mess with rakefile, version, or history.
13
+ (if you want to have your own version, that is fine but
14
+ bump version in a commit by itself I can ignore when I pull)
15
+ * Send me a pull request. Bonus points for topic branches.
16
+
17
+ == Copyright
18
+
19
+ Copyright (c) 2009 epitron. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "epitools"
8
+ gem.summary = %Q{NOT UTILS... METILS!}
9
+ gem.description = %Q{Miscellaneous utility libraries to make my life easier.}
10
+ gem.email = "chris@ill-logic.com"
11
+ gem.homepage = "http://github.com/epitron/epitools"
12
+ gem.authors = ["epitron"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "testtt #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
data/lib/epitools.rb ADDED
@@ -0,0 +1,11 @@
1
+ __DIR__ = File.dirname(__FILE__)
2
+
3
+ %w[
4
+ basetypes
5
+ metaclass
6
+ niceprint
7
+ string_to_proc
8
+ permutations
9
+ ].each do |mod|
10
+ require File.join(__DIR__, "epitools", mod)
11
+ end
@@ -0,0 +1,429 @@
1
+ require 'pp'
2
+
3
+ class Object
4
+ # Default "integer?" behaviour.
5
+ def integer?; false; end
6
+ end
7
+
8
+
9
+ class Float
10
+ def integer?; true; end
11
+ end
12
+
13
+
14
+ class String
15
+
16
+ #
17
+ # Could this string be cast to an integer?
18
+ #
19
+ def integer?
20
+ self.strip.match(/^\d+$/) ? true : false
21
+ end
22
+
23
+ #
24
+ # Like #lines, but skips empty lines and removes \n's.
25
+ #
26
+ def nice_lines
27
+ self.split("\n").map(&:strip).select(&:any?)
28
+ end
29
+
30
+ alias_method :clean_lines, :nice_lines
31
+
32
+ end
33
+
34
+
35
+ class Integer
36
+
37
+ def integer?
38
+ true
39
+ end
40
+
41
+ def to_hex
42
+ "%0.2x" % self
43
+ end
44
+
45
+ #
46
+ # Convert the number to an array of bits (least significant digit first).
47
+ #
48
+ def to_bits
49
+ ("%b" % self).reverse.chars.map(&:to_i)
50
+ end
51
+
52
+ alias_method :bits, :to_bits
53
+
54
+ end
55
+
56
+
57
+ class Array
58
+
59
+ #
60
+ # flatten.compact.uniq
61
+ #
62
+ def squash
63
+ flatten.compact.uniq
64
+ end
65
+
66
+ end
67
+
68
+
69
+ module Enumerable
70
+
71
+ #
72
+ # Split this enumerable into an array of pieces given some
73
+ # boundary condition.
74
+ #
75
+ # Options:
76
+ # :include_boundary => true #=> include the element that you're splitting at in the results
77
+ # (default: false)
78
+ # :after => true #=> split after the matched element (only has an effect when used with :include_boundary)
79
+ # (default: false)
80
+ #
81
+ # Examples:
82
+ # [1,2,3,4,5].split{ |e| e == 3 }
83
+ # #=> [ [1,2], [4,5] ]
84
+ #
85
+ # [1,2,3,4,5].split(:include_boundary=>true) { |e| e == 3 }
86
+ # #=> [ [1,2], [3,4,5] ]
87
+ #
88
+ # chapters = File.read("ebook.txt").split(/Chapter \d+/, :include_boundary=>true)
89
+ # #=> [ ["Chapter 1", ...], ["Chapter 2", ...], etc. ]
90
+ #
91
+ # TODO:
92
+ # - Ruby 1.9 returns Enumerators for everything now. Maybe do that?
93
+ #
94
+ def split_at(matcher=nil, options={}, &block)
95
+ return self unless self.any?
96
+
97
+ include_boundary = options[:include_boundary] || false
98
+
99
+ if matcher.nil?
100
+ boundary_test = block
101
+ else
102
+ if matcher.is_a? String or matcher.is_a? Regexp
103
+ boundary_test = proc { |e| e[matcher] }
104
+ else
105
+ raise "I don't know how to split with #{matcher}"
106
+ end
107
+ end
108
+
109
+ chunks = []
110
+ current_chunk = []
111
+
112
+ each do |e|
113
+
114
+ if boundary_test.call(e)
115
+
116
+ if current_chunk.empty? and not include_boundary
117
+ next # hit 2 boundaries in a row... just keep moving, people!
118
+ end
119
+
120
+ if options[:after]
121
+ # split after boundary
122
+ current_chunk << e if include_boundary # include the boundary, if necessary
123
+ chunks << current_chunk # shift everything after the boundary into the resultset
124
+ current_chunk = [] # start a new result
125
+ else
126
+ # split before boundary
127
+ chunks << current_chunk # shift before the boundary into the resultset
128
+ current_chunk = [] # start a new result
129
+ current_chunk << e if include_boundary # include the boundary, if necessary
130
+ end
131
+
132
+ else
133
+ current_chunk << e
134
+ end
135
+
136
+ end
137
+
138
+ chunks << current_chunk if current_chunk.any?
139
+
140
+ chunks # resultset
141
+ end
142
+
143
+ alias_method :split, :split_at
144
+
145
+ #
146
+ # Split the array into chunks, with the boundaries being after the element to split on.
147
+ #
148
+ # eg: [1,2,3,4].split_after{|e| e == 3 } #=> [ [1,2,3], [4] ]
149
+ #
150
+ def split_after(matcher=nil, options={}, &block)
151
+ options[:after] ||= true
152
+ options[:include_boundary] ||= true
153
+ split(matcher, options, &block)
154
+ end
155
+
156
+ #
157
+ # Split the array into chunks. The boundaries will lie before the element to split on.
158
+ #
159
+ # eg: [1,2,3,4].split_before{|e| e == 3 } #=> [ [1,2], [3,4] ]
160
+ #
161
+ def split_before(matcher=nil, options={}, &block)
162
+ options[:include_boundary] ||= true
163
+ split(matcher, options, &block)
164
+ end
165
+
166
+ #
167
+ # Sum the elements
168
+ #
169
+ def sum
170
+ inject(0) { |total,n| total + n }
171
+ end
172
+
173
+ #
174
+ # Average the elements
175
+ #
176
+ def average
177
+ count = 0
178
+ sum = inject(0) { |total,n| count += 1; total + n }
179
+ sum / count.to_f
180
+ end
181
+
182
+ #
183
+ # The same as "map", except that if an element is an Array or Enumerable, map is called
184
+ # recursively on that element.
185
+ #
186
+ # eg: [ [1,2], [3,4] ].map_recursive{|e| e ** 2 } #=> [ [1,4], [9,16] ]
187
+ #
188
+ def recursive_map(*args, &block)
189
+ map(*args) do |e|
190
+ if e.is_a? Array or e.is_a? Enumerable
191
+ e.map(*args, &block)
192
+ else
193
+ block.call(e)
194
+ end
195
+ end
196
+ end
197
+
198
+ alias_method :map_recursive, :recursive_map
199
+ alias_method :map_recursively, :recursive_map
200
+
201
+
202
+ #
203
+ # Identical to "reduce" in ruby1.9 (or foldl in haskell.)
204
+ #
205
+ # Example:
206
+ # array.foldl{|a,b| a + b } == array[1..-1].inject(array[0]){|a,b| a + b }
207
+ #
208
+ def foldl(methodname=nil, &block)
209
+ result = nil
210
+
211
+ raise "Error: pass a parameter OR a block, not both!" if methodname and block
212
+
213
+ if methodname
214
+
215
+ each_with_index do |e,i|
216
+ if i == 0
217
+ result = e
218
+ next
219
+ end
220
+
221
+ result = result.send(methodname, e)
222
+ end
223
+
224
+ else
225
+
226
+ each_with_index do |e,i|
227
+ if i == 0
228
+ result = e
229
+ next
230
+ end
231
+
232
+ result = block.call(result, e)
233
+ end
234
+
235
+ end
236
+
237
+ result
238
+ end
239
+
240
+
241
+ end
242
+
243
+
244
+
245
+ class Object
246
+
247
+ #
248
+ # Instead of:
249
+ # if cookie_jar.include? cookie
250
+ # Now you can do:
251
+ # if cookie.in? cookie_jar
252
+ #
253
+ def in?(enumerable)
254
+ enumerable.include? self
255
+ end
256
+
257
+ #
258
+ # Instead of:
259
+ # @person ? @person.name : nil
260
+ # Now you can do:
261
+ # @person.try(:name)
262
+ #
263
+ def try(method, *args, &block)
264
+ send(method, *args, &block) if respond_to? method
265
+ end
266
+
267
+ #
268
+ # Benchmark a block!
269
+ #
270
+ def bench(message=nil)
271
+ start = Time.now
272
+ yield
273
+ elapsed = Time.now - start
274
+
275
+ print "[#{message}] " if message
276
+ puts "elapsed time: %0.5fs" % elapsed
277
+ end
278
+ alias time bench
279
+
280
+
281
+ #
282
+ # A decorator that makes any block-accepting method return an
283
+ # Enumerable::Enumerator whenever the method is called without a block.
284
+ #
285
+ def self.enumerable *meths
286
+ meths.each do |meth|
287
+ alias_method "#{meth}_without_enumerator", meth
288
+ class_eval %{
289
+ def #{meth}(*args, &block)
290
+ return Enumerable::Enumerator.new(self, #{meth.inspect}, *args, &block) unless block_given?
291
+ #{meth}_without_enumerator(*args, &block)
292
+ end
293
+ }
294
+ end
295
+ end
296
+
297
+ end
298
+
299
+
300
+ class Hash
301
+ def remove_blank_values!
302
+ delete_if{|k,v| v.blank?}
303
+ self
304
+ end
305
+
306
+ def remove_blank_values
307
+ dup.remove_blank_values!
308
+ end
309
+
310
+ def map_values!(&block)
311
+ keys.each do |key|
312
+ value = self[key]
313
+ self[key] = yield(value)
314
+ end
315
+ self
316
+ end
317
+
318
+ def map_values(&block)
319
+ dup.map_values!(&block)
320
+ end
321
+
322
+ def map_keys!(&block)
323
+ keys.each do |key|
324
+ value = delete(key)
325
+ self[yield(key)] = value
326
+ end
327
+ self
328
+ end
329
+
330
+ def map_keys(&block)
331
+ dup.map_keys!(&block)
332
+ end
333
+
334
+ # TODO: Where did slice come from?
335
+ #alias_method :filter, :slice
336
+ #alias_method :filter!, :slice!
337
+
338
+ end
339
+
340
+
341
+
342
+ #
343
+ # Magic "its" Mapping
344
+ # -------------------
345
+ #
346
+ # The pure-Ruby way:
347
+ # User.find(:all).map{|x| x.contacts.map{|y| y.last_name.capitalize }}
348
+ #
349
+ # With Symbol#to_proc:
350
+ # User.find(:all).map{|x|x.contacts.map(&:last_name).map(&:capitalize)}
351
+ #
352
+ # Magic "its" way:
353
+ # User.find(:all).map &its.contacts.map(&its.last_name.capitalize)
354
+ #
355
+
356
+ module Kernel
357
+
358
+ protected
359
+ def it()
360
+ It.new
361
+ end
362
+
363
+ alias its it
364
+
365
+ end
366
+
367
+ class It
368
+ undef_method( *(instance_methods - ["__id__", "__send__"]) )
369
+
370
+ def initialize
371
+ @methods = []
372
+ end
373
+
374
+ def method_missing(*args, &block)
375
+ @methods << [args, block] unless args == [:respond_to?, :to_proc]
376
+ self
377
+ end
378
+
379
+ def to_proc
380
+ lambda do |obj|
381
+ @methods.inject(obj) do |current,(args,block)|
382
+ current.send(*args, &block)
383
+ end
384
+ end
385
+ end
386
+ end
387
+
388
+
389
+ class BlankSlate
390
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
391
+ end
392
+
393
+ #
394
+ # Funky #not method
395
+ # -----------------
396
+ #
397
+ # >> 10.even?
398
+ # => true
399
+ # >> 10.not.even?
400
+ # => false
401
+ #
402
+
403
+ class NotWrapper < BlankSlate
404
+ def initialize(orig)
405
+ @orig = orig
406
+ end
407
+
408
+ def inspect
409
+ "{NOT #{@orig.inspect}}"
410
+ end
411
+
412
+ def method_missing(meth, *args, &block)
413
+ result = @orig.send(meth, *args, &block)
414
+ if result.is_a? TrueClass or result.is_a? FalseClass
415
+ !result
416
+ else
417
+ raise "Sorry, I don't know how to invert #{result.inspect}"
418
+ end
419
+ end
420
+ end
421
+
422
+
423
+ class Object
424
+ def not
425
+ NotWrapper.new(self)
426
+ end
427
+ end
428
+
429
+