jashmenn-basket 0.0.2
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.
- data/README.rdoc +37 -0
- data/Rakefile +72 -0
- data/examples/01_simple.rb +8 -0
- data/examples/02_conditional.rb +13 -0
- data/examples/03_other_baskets.rb +17 -0
- data/examples/04_parallel.rb +10 -0
- data/lib/basket.rb +133 -0
- data/lib/ext/core.rb +11 -0
- data/lib/ext/metaid.rb +15 -0
- data/lib/has_logger.rb +34 -0
- data/spec/basket_spec.rb +122 -0
- data/spec/spec_helper.rb +29 -0
- metadata +74 -0
data/README.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
= Basket
|
2
|
+
|
3
|
+
Easily process and sort a directory of files.
|
4
|
+
|
5
|
+
= Example:
|
6
|
+
|
7
|
+
Basket.process("orders") do |file|
|
8
|
+
puts "we are processing #{file}"
|
9
|
+
end
|
10
|
+
|
11
|
+
Assuming there are number of files in <tt>orders/inbox</tt>
|
12
|
+
* each file is +mv+'d to <tt>orders/pending</tt>
|
13
|
+
* the block is called on each file
|
14
|
+
* the file is +mv+'d to <tt>orders/archive</tt>
|
15
|
+
|
16
|
+
See Basket#process for a list of all the options.
|
17
|
+
|
18
|
+
= Install:
|
19
|
+
|
20
|
+
gem install jashmenn-basket --source http://gems.github.com
|
21
|
+
|
22
|
+
= More examples:
|
23
|
+
|
24
|
+
The output folder can be conditional based on the output of the block, as in
|
25
|
+
the following example. In this case the default names of the folders are
|
26
|
+
+success+ and +fail+ based on the return value of the block being +true+ or
|
27
|
+
+false+.
|
28
|
+
|
29
|
+
:include:examples/02_conditional.rb
|
30
|
+
|
31
|
+
You can create arbitrary baskets for the output. If you specify <tt>:other</tt> then the files are *not* +mv+'d automatically. You must call the appropriate bang method on the file. For example:
|
32
|
+
|
33
|
+
:include:examples/03_other_baskets.rb
|
34
|
+
|
35
|
+
Baskets has (experimental) built-in support for doing parallel processing using <tt>forkoff</tt>. Example:
|
36
|
+
|
37
|
+
:include:examples/04_parallel.rb
|
data/Rakefile
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rubygems/specification'
|
4
|
+
require 'date'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
require 'lib/ext/core'
|
8
|
+
|
9
|
+
GEM = "basket"
|
10
|
+
GEM_VERSION = "0.0.2"
|
11
|
+
AUTHOR = "Nate Murray"
|
12
|
+
EMAIL = "nate@natemurray.com"
|
13
|
+
HOMEPAGE = "http://www.xcombinator.com"
|
14
|
+
SUMMARY = "Easily process and sort a directory of files."
|
15
|
+
|
16
|
+
spec = Gem::Specification.new do |s|
|
17
|
+
s.name = GEM
|
18
|
+
s.version = GEM_VERSION
|
19
|
+
s.platform = Gem::Platform::RUBY
|
20
|
+
s.has_rdoc = true
|
21
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
22
|
+
s.summary = SUMMARY
|
23
|
+
s.description = s.summary
|
24
|
+
s.author = AUTHOR
|
25
|
+
s.email = EMAIL
|
26
|
+
s.homepage = HOMEPAGE
|
27
|
+
s.add_dependency('forkoff', '>= 0.0.1')
|
28
|
+
|
29
|
+
s.require_path = 'lib'
|
30
|
+
s.autorequire = GEM
|
31
|
+
s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,spec,examples}/**/*").reject{|f| f =~ /(spec\/fixtures)/}
|
32
|
+
end
|
33
|
+
|
34
|
+
task :default => :spec
|
35
|
+
|
36
|
+
desc "Run specs"
|
37
|
+
Spec::Rake::SpecTask.new do |t|
|
38
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
39
|
+
t.spec_opts = %w(-fs --color)
|
40
|
+
end
|
41
|
+
|
42
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
43
|
+
pkg.gem_spec = spec
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "install the gem locally"
|
47
|
+
task :install => [:package] do
|
48
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "create a gemspec file"
|
52
|
+
task :make_spec do
|
53
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
54
|
+
file.puts spec.to_ruby
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
namespace :rdoc do
|
59
|
+
Rake::RDocTask.new :html do |rd|
|
60
|
+
rd.main = "README.rdoc"
|
61
|
+
rd.rdoc_dir = 'rdoc'
|
62
|
+
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
63
|
+
end
|
64
|
+
task :open do
|
65
|
+
system 'open ' + (:rdoc / 'index.html') if PLATFORM['darwin']
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "run rstakeout"
|
70
|
+
task :rstakeout do
|
71
|
+
exec "AUTOTEST=true rstakeout -t 1 -v \"spec spec --format=specdoc --color\" '*/**/*.rb'"
|
72
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + "/../lib"
|
2
|
+
require 'basket'
|
3
|
+
def log(*args); p args; end
|
4
|
+
|
5
|
+
Basket.process("orders", :conditional => true, :logdev => "/dev/null") do |file, i|
|
6
|
+
if i % 2 == 0
|
7
|
+
log :success, file
|
8
|
+
true # returning true mv's file to +success+
|
9
|
+
else
|
10
|
+
log :fail, file
|
11
|
+
false # returning false mv's file to +faile+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + "/../lib"
|
2
|
+
require 'basket'
|
3
|
+
def log(*args); p args; end
|
4
|
+
|
5
|
+
Basket.process("orders", :inbox => "new", :pending => "work", :other => %w{good bad unknown}) do |file, i|
|
6
|
+
case i % 3
|
7
|
+
when 0
|
8
|
+
log :good, file
|
9
|
+
file.good! # mv's file to "orders/good"
|
10
|
+
when 1
|
11
|
+
log :bad, file
|
12
|
+
file.bad!
|
13
|
+
when 2
|
14
|
+
log :unknown, file
|
15
|
+
file.unknown!
|
16
|
+
end
|
17
|
+
end
|
data/lib/basket.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
module Basket
|
2
|
+
VERSION = '0.0.1'
|
3
|
+
|
4
|
+
DIR = File.expand_path(File.dirname(File.expand_path(__FILE__)))
|
5
|
+
$:.unshift DIR
|
6
|
+
|
7
|
+
require 'fileutils'
|
8
|
+
require 'pp'
|
9
|
+
require 'ext/core'
|
10
|
+
require 'ext/metaid'
|
11
|
+
require 'has_logger'
|
12
|
+
require 'forkoff'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
@logging = false
|
16
|
+
attr_accessor :logging
|
17
|
+
end
|
18
|
+
|
19
|
+
# == Basket
|
20
|
+
# Process a directory of files, one at a time.
|
21
|
+
#
|
22
|
+
# == Overview
|
23
|
+
# Take +root+ folder and look for the directory +inbox+. Each file in
|
24
|
+
# +inbox+ is first +mv+'d to +pending+ and then yielded to +block+. Upon
|
25
|
+
# completion of the block the file is +mv+'d to a directory, as specifed in
|
26
|
+
# the options.
|
27
|
+
#
|
28
|
+
# == Options
|
29
|
+
# * <tt>:inbox</tt>: the name of the inbox folder (default +inbox+)
|
30
|
+
# * <tt>:pending</tt>: the name of the pending folder (default +pending+)
|
31
|
+
# * <tt>:archive</tt>: the name of the archive folder (default +archive+)
|
32
|
+
# * <tt>:other</tt>: if +other+ is specified then the files are *not* moved to the archive or any other directory automatically. You *must* specify where the file will go or it will remain in +inbox+. incompatable with +conditional+.
|
33
|
+
# * <tt>:logdev</tt>: device to log to. For example: <tt>STDOUT</tt> or <tt>"/path/to/log.log"</tt> (default: <tt>/dev/null</tt>)
|
34
|
+
# * <tt>:conditional</tt>: if +conditional+ is specified then then the result of the #process block is interpreted as boolean. if the result is +true+ then the file is mv'd to +success+ otherwise it is mv'd to +fail+
|
35
|
+
#
|
36
|
+
# == Block Arity
|
37
|
+
# If the block takes a single argument, then a string containing the path to
|
38
|
+
# the +pending+ file is yielded. If the block accepts two arugments then the
|
39
|
+
# file index is also yielded. Does not work for parallel processing with forkoff.
|
40
|
+
def self.process(input, opts={}, &block)
|
41
|
+
b = Base.new(input, opts)
|
42
|
+
b.process(&block)
|
43
|
+
end
|
44
|
+
|
45
|
+
class Base
|
46
|
+
|
47
|
+
INBOX = "inbox"
|
48
|
+
PENDING = "pending"
|
49
|
+
ARCHIVE = "archive"
|
50
|
+
|
51
|
+
attr_accessor :root
|
52
|
+
attr_accessor :inbox
|
53
|
+
attr_accessor :pending
|
54
|
+
attr_accessor :other
|
55
|
+
|
56
|
+
include HasLogger
|
57
|
+
include FileUtils
|
58
|
+
|
59
|
+
def initialize(root, opts={})
|
60
|
+
@root = root
|
61
|
+
@inbox = opts.delete(:inbox) || INBOX
|
62
|
+
@pending = opts.delete(:pending) || PENDING
|
63
|
+
@archive = opts.delete(:archive) || ARCHIVE
|
64
|
+
@other = opts.delete(:other) || []
|
65
|
+
@logdev = opts.delete(:logdev) || "/dev/null"
|
66
|
+
@opts = opts
|
67
|
+
end
|
68
|
+
|
69
|
+
def process(&block)
|
70
|
+
create_directories
|
71
|
+
files = Dir[@root/@inbox/"*"]
|
72
|
+
logger.debug(["#{files.size} files in", @root/@inbox/"*"])
|
73
|
+
send_args = @opts[:workers] ? [:forkoff!, {:processes => @opts[:workers]}] : [:each]
|
74
|
+
i = 0
|
75
|
+
files.send(*send_args) do |file|
|
76
|
+
pending_file = @root/@pending/File.basename(file)
|
77
|
+
logger.info [:mv, file, pending_file]
|
78
|
+
mv file, pending_file
|
79
|
+
|
80
|
+
to_mix = mixin
|
81
|
+
pending_file.meta_eval { include to_mix }
|
82
|
+
result = block.arity > 1 ? block.call(pending_file, i) : block.call(pending_file)
|
83
|
+
|
84
|
+
if @opts[:conditional]
|
85
|
+
destination = result ? @root/"success" : @root/"fail"
|
86
|
+
logger.info [:mv, pending_file, destination]
|
87
|
+
mv pending_file, destination
|
88
|
+
elsif @other.size > 0
|
89
|
+
# don't mv anything
|
90
|
+
else
|
91
|
+
logger.info [:mv, pending_file, @root/@archive]
|
92
|
+
mv pending_file, @root/@archive
|
93
|
+
end
|
94
|
+
i += 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
def create_directories
|
100
|
+
baskets.each do |dir|
|
101
|
+
logger.debug([:creating, @root/dir])
|
102
|
+
mkdir_p(@root/dir)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# create the Module that will be mixed in to the String representing the
|
107
|
+
# files this allows us to define exclamation methods that will move the
|
108
|
+
# files to a particular directory
|
109
|
+
def mixin # :nodoc:
|
110
|
+
our_baskets, our_root, our_logger = baskets, @root, logger # create local definitions for closures
|
111
|
+
@mixin ||= begin
|
112
|
+
movingMethods = Module.new
|
113
|
+
movingMethods.module_eval do
|
114
|
+
our_baskets.each do |basket|
|
115
|
+
define_method "#{basket}!" do
|
116
|
+
our_logger.info [:mv, self, our_root/basket]
|
117
|
+
FileUtils.mv self, our_root/basket
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
movingMethods
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def baskets
|
126
|
+
baskets = [@inbox, @pending, @archive, @other]
|
127
|
+
baskets << ["success", "fail"] if @opts[:conditional]
|
128
|
+
baskets.flatten.compact
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
data/lib/ext/core.rb
ADDED
data/lib/ext/metaid.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class Object
|
2
|
+
# The hidden singleton lurks behind everyone
|
3
|
+
def metaclass; class << self; self; end; end
|
4
|
+
def meta_eval &blk; metaclass.instance_eval &blk; end
|
5
|
+
|
6
|
+
# Adds methods to a metaclass
|
7
|
+
def meta_def name, &blk
|
8
|
+
meta_eval { define_method name, &blk }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Defines an instance method within a class
|
12
|
+
def class_def name, &blk
|
13
|
+
class_eval { define_method name, &blk }
|
14
|
+
end
|
15
|
+
end
|
data/lib/has_logger.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Module for easy logging
|
2
|
+
#
|
3
|
+
# Example:
|
4
|
+
#
|
5
|
+
# class MyClass
|
6
|
+
# include HasLogger
|
7
|
+
#
|
8
|
+
# # ...
|
9
|
+
# def do_something
|
10
|
+
# logger.info("I just did something!")
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
require 'logger'
|
14
|
+
|
15
|
+
module HasLogger
|
16
|
+
def self.included(mod)
|
17
|
+
mod.extend(ClassMethods)
|
18
|
+
mod.send :include, InstanceMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
def logger
|
26
|
+
@logger ||= begin
|
27
|
+
logger = Logger.new(@logdev || STDOUT)
|
28
|
+
logger.formatter = Logger::Formatter.new
|
29
|
+
logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
30
|
+
logger
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/spec/basket_spec.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
def log *args
|
4
|
+
return false # comment to log these tests to stdout
|
5
|
+
p args
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "Basket" do
|
9
|
+
include BasketFixtures
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
create_fixture_files
|
13
|
+
@root = FIXTURES_DIR/"orders"
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Basket::Base" do
|
17
|
+
describe "using default options" do
|
18
|
+
before(:each) do
|
19
|
+
@b = Basket::Base.new(FIXTURES_DIR/"orders", :logdev => "/dev/null")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have root" do
|
23
|
+
@b.root.should eql(FIXTURES_DIR/"orders")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should create the needed directories" do
|
27
|
+
%w{pending archive}.each { |basket| File.exists?(@b.root/basket).should be_false }
|
28
|
+
@b.send(:create_directories)
|
29
|
+
%w{pending archive}.each { |basket| File.exists?(@b.root/basket).should be_true }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "making custom directories" do
|
34
|
+
before(:each) do
|
35
|
+
@all = %w{new work done foo bar baz}
|
36
|
+
@b = Basket::Base.new(FIXTURES_DIR/"orders", :inbox => "new",
|
37
|
+
:pending => "work",
|
38
|
+
:archive => "done",
|
39
|
+
:other => @all,
|
40
|
+
:logdev => "/dev/null")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should create them" do
|
44
|
+
@all.each { |basket| File.exists?(@b.root/basket).should be_false }
|
45
|
+
@b.send(:create_directories)
|
46
|
+
@all.each { |basket| File.exists?(@b.root/basket).should be_true }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "basic usage" do
|
52
|
+
it "should process files" do
|
53
|
+
Dir["#{@root}/inbox/*"].size.should == 25 # check and make sure files are in the inbox
|
54
|
+
|
55
|
+
Basket.process(@root, :logdev => "/dev/null") do |file|
|
56
|
+
log :processing, file
|
57
|
+
end
|
58
|
+
|
59
|
+
Dir["#{@root}/inbox/*" ].size.should == 0
|
60
|
+
Dir["#{@root}/archive/*"].size.should == 25
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "conditional usage" do
|
65
|
+
it "should process files" do
|
66
|
+
Dir["#{@root}/inbox/*"].size.should == 25 # check and make sure files are in the inbox
|
67
|
+
|
68
|
+
Basket.process(@root, :conditional => true, :logdev => "/dev/null") do |file, i|
|
69
|
+
if i % 2 == 0
|
70
|
+
log :success, file
|
71
|
+
true
|
72
|
+
else
|
73
|
+
log :fail, file
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Dir["#{@root}/inbox/*" ].size.should == 0
|
79
|
+
Dir["#{@root}/success/*" ].size.should == 13
|
80
|
+
Dir["#{@root}/fail/*" ].size.should == 12
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "custom baskets" do
|
85
|
+
it "should process files" do
|
86
|
+
create_fixture_files("new")
|
87
|
+
Dir["#{@root}/new/*"].size.should == 25 # check and make sure files are in the inbox
|
88
|
+
|
89
|
+
Basket.process(@root, :inbox => "new", :pending => "work", :other => %w{good bad unknown}) do |file, i|
|
90
|
+
case i % 3
|
91
|
+
when 0
|
92
|
+
log :good, file
|
93
|
+
file.good!
|
94
|
+
when 1
|
95
|
+
log :bad, file
|
96
|
+
file.bad!
|
97
|
+
when 2
|
98
|
+
log :unknown, file
|
99
|
+
file.unknown!
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
Dir["#{@root}/new/*" ].size.should == 0
|
104
|
+
Dir["#{@root}/good/*" ].size.should == 9
|
105
|
+
Dir["#{@root}/bad/*" ].size.should == 8
|
106
|
+
Dir["#{@root}/unknown/*" ].size.should == 8
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "parallel processing with forkoff" do
|
111
|
+
it "should process the files" do
|
112
|
+
create_fixture_files("inbox", 10)
|
113
|
+
Basket.process(@root, :workers => 2) do |file, i|
|
114
|
+
log $$, :processing, file, i
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
after(:each) do
|
120
|
+
cleanup_fixtures_dir
|
121
|
+
end
|
122
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
$TESTING=true
|
2
|
+
$:.push File.join(File.dirname(__FILE__), '..', 'lib')
|
3
|
+
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
|
4
|
+
require 'basket'
|
5
|
+
|
6
|
+
module BasketFixtures
|
7
|
+
def fixtures_name
|
8
|
+
"order"
|
9
|
+
end
|
10
|
+
|
11
|
+
def fixtures_dir
|
12
|
+
FIXTURES_DIR/fixtures_name + "s"
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_fixture_files inbox="inbox", howmany=25
|
16
|
+
cleanup_fixtures_dir
|
17
|
+
inbox_dir = fixtures_dir/inbox
|
18
|
+
FileUtils.mkdir_p(inbox_dir)
|
19
|
+
0.upto(howmany - 1) do |i|
|
20
|
+
filename = inbox_dir/"#{fixtures_name}_%05d" % i
|
21
|
+
FileUtils.touch(filename) unless File.exists?(filename)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def cleanup_fixtures_dir
|
26
|
+
FileUtils.rm_rf(fixtures_dir) if File.exists?(fixtures_dir)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jashmenn-basket
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nate Murray
|
8
|
+
autorequire: basket
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-10 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: forkoff
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.1
|
24
|
+
version:
|
25
|
+
description: Easily process and sort a directory of files.
|
26
|
+
email: nate@natemurray.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.rdoc
|
33
|
+
files:
|
34
|
+
- README.rdoc
|
35
|
+
- Rakefile
|
36
|
+
- lib/basket.rb
|
37
|
+
- lib/ext
|
38
|
+
- lib/ext/core.rb
|
39
|
+
- lib/ext/metaid.rb
|
40
|
+
- lib/has_logger.rb
|
41
|
+
- spec/basket_spec.rb
|
42
|
+
- spec/spec_helper.rb
|
43
|
+
- examples/01_simple.rb
|
44
|
+
- examples/02_conditional.rb
|
45
|
+
- examples/03_other_baskets.rb
|
46
|
+
- examples/04_parallel.rb
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://www.xcombinator.com
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.2.0
|
70
|
+
signing_key:
|
71
|
+
specification_version: 2
|
72
|
+
summary: Easily process and sort a directory of files.
|
73
|
+
test_files: []
|
74
|
+
|