floormanager 0.1.0
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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +22 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/floormanager.gemspec +57 -0
- data/lib/floormanager.rb +3 -0
- data/lib/floormanager/queue.rb +176 -0
- data/lib/floormanager/workers.rb +42 -0
- data/spec/floormanager_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +89 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Inge Jørgensen
|
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,22 @@
|
|
1
|
+
= floormanager: Handle threaded workers like a champ
|
2
|
+
|
3
|
+
== Usage
|
4
|
+
|
5
|
+
require 'floormanager'
|
6
|
+
|
7
|
+
queue = FloorManager::Queue.new('one', 'two', 'three', 'four', 'five')
|
8
|
+
workers = FloorManager::Workers.new(queue)
|
9
|
+
|
10
|
+
workers.perform(:threads => 3) do |item|
|
11
|
+
item.upcase
|
12
|
+
end
|
13
|
+
|
14
|
+
queue.each do |key, results|
|
15
|
+
puts "Key: #{key}, results: #{results}"
|
16
|
+
end
|
17
|
+
|
18
|
+
See the examples for more advanced usage.
|
19
|
+
|
20
|
+
== Copyright
|
21
|
+
|
22
|
+
Copyright (c) 2010 Inge Jørgensen. 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 = "floormanager"
|
8
|
+
gem.summary = %Q{Handle threaded workers like a champ}
|
9
|
+
gem.description = %Q{Simple ruby library for handling threaded workers operating on a queue}
|
10
|
+
gem.email = "inge@elektronaut.no"
|
11
|
+
gem.homepage = "http://github.com/elektronaut/floormanager"
|
12
|
+
gem.authors = ["Inge Jørgensen"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.3.0"
|
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 = "floormanager #{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.0
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{floormanager}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Inge J\303\270rgensen"]
|
12
|
+
s.date = %q{2010-05-14}
|
13
|
+
s.description = %q{Simple ruby library for handling threaded workers operating on a queue}
|
14
|
+
s.email = %q{inge@elektronaut.no}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"floormanager.gemspec",
|
27
|
+
"lib/floormanager.rb",
|
28
|
+
"lib/floormanager/queue.rb",
|
29
|
+
"lib/floormanager/workers.rb",
|
30
|
+
"spec/floormanager_spec.rb",
|
31
|
+
"spec/spec.opts",
|
32
|
+
"spec/spec_helper.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/elektronaut/floormanager}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.6}
|
38
|
+
s.summary = %q{Handle threaded workers like a champ}
|
39
|
+
s.test_files = [
|
40
|
+
"spec/floormanager_spec.rb",
|
41
|
+
"spec/spec_helper.rb"
|
42
|
+
]
|
43
|
+
|
44
|
+
if s.respond_to? :specification_version then
|
45
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
46
|
+
s.specification_version = 3
|
47
|
+
|
48
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
52
|
+
end
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
data/lib/floormanager.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
module FloorManager
|
2
|
+
class Queue
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
# States
|
6
|
+
PENDING = 0
|
7
|
+
CHECKED_OUT = 1
|
8
|
+
FAILED = 2
|
9
|
+
SUCCESS = 3
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
@queue = []
|
13
|
+
args.each{|a| self << a} if (args = *args)
|
14
|
+
end
|
15
|
+
|
16
|
+
public
|
17
|
+
|
18
|
+
# Add an item to the queue
|
19
|
+
def add(item)
|
20
|
+
@queue << {
|
21
|
+
:item => item,
|
22
|
+
:value => nil,
|
23
|
+
:state => PENDING
|
24
|
+
}
|
25
|
+
end
|
26
|
+
alias :<< :add
|
27
|
+
|
28
|
+
# Get the value of an item in the queue
|
29
|
+
def get_value(key)
|
30
|
+
(item = get_item(key)) ? item[:value] : nil
|
31
|
+
end
|
32
|
+
alias :[] :get_value
|
33
|
+
|
34
|
+
# Returns all the items in the queue
|
35
|
+
def keys
|
36
|
+
@queue.map{|i| i[:item]}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns each item with value, hash style
|
40
|
+
def each
|
41
|
+
@queue.each{|item| yield item[:item], item[:value]}
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check out an item from the queue
|
45
|
+
def checkout
|
46
|
+
if pending?
|
47
|
+
item = pending_items.first
|
48
|
+
item[:state] = CHECKED_OUT
|
49
|
+
item[:item]
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Check in an item with a new value, optionally with a state
|
56
|
+
# (which defaults to SUCCESS)
|
57
|
+
def checkin(item, value, state=SUCCESS)
|
58
|
+
if keys.include?(item)
|
59
|
+
item = get_item(item)
|
60
|
+
item[:value] = value
|
61
|
+
item[:state] = state
|
62
|
+
else
|
63
|
+
invalid_key!
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Total queue length
|
68
|
+
def length
|
69
|
+
@queue.length
|
70
|
+
end
|
71
|
+
|
72
|
+
# Is the queue done?
|
73
|
+
def done?
|
74
|
+
(pending.length == 0 && checked_out.length == 0) ? true : false
|
75
|
+
end
|
76
|
+
|
77
|
+
# Does this queue have pending items?
|
78
|
+
def pending?
|
79
|
+
(pending.length > 0) ? true : false
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get pending items
|
83
|
+
def pending
|
84
|
+
pending_items.map{|i| i[:item]}
|
85
|
+
end
|
86
|
+
|
87
|
+
# Get checked out items
|
88
|
+
def checked_out
|
89
|
+
checked_out_items.map{|i| i[:item]}
|
90
|
+
end
|
91
|
+
|
92
|
+
# Get completed items
|
93
|
+
def completed
|
94
|
+
completed_items.map{|i| i[:item]}
|
95
|
+
end
|
96
|
+
|
97
|
+
# Get successed items
|
98
|
+
def successed
|
99
|
+
successed_items.map{|i| i[:item]}
|
100
|
+
end
|
101
|
+
|
102
|
+
# Get failed items
|
103
|
+
def failed
|
104
|
+
failed_items.map{|i| i[:item]}
|
105
|
+
end
|
106
|
+
|
107
|
+
# Get the state of an item
|
108
|
+
def state(key)
|
109
|
+
(item = get_item(key)) ? item[:state] : invalid_key!
|
110
|
+
end
|
111
|
+
|
112
|
+
# Is this item processed?
|
113
|
+
def processed?(key)
|
114
|
+
state(key) > PENDING
|
115
|
+
end
|
116
|
+
|
117
|
+
# Is this item checked out?
|
118
|
+
def checked_out?(key)
|
119
|
+
state(key) == CHECKED_OUT
|
120
|
+
end
|
121
|
+
|
122
|
+
# Did this item fail?
|
123
|
+
def failed?(key)
|
124
|
+
state(key) == FAILED
|
125
|
+
end
|
126
|
+
|
127
|
+
# Did this item succeed?
|
128
|
+
def success?(key)
|
129
|
+
state(key) == SUCCESS
|
130
|
+
end
|
131
|
+
|
132
|
+
# Is this item completed?
|
133
|
+
def completed?(key)
|
134
|
+
state(key) >= FAILED
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
# Handle invalid keys
|
140
|
+
def invalid_key!
|
141
|
+
raise ArgumentError, "Invalid key: #{item.inspect}"
|
142
|
+
end
|
143
|
+
|
144
|
+
# Get an item by key
|
145
|
+
def get_item(key)
|
146
|
+
matches = @queue.select{|i| i[:item] == key}
|
147
|
+
(matches.length > 0) ? matches.first : nil
|
148
|
+
end
|
149
|
+
|
150
|
+
# Get all pending items
|
151
|
+
def pending_items
|
152
|
+
@queue.select{|i| i[:state] == PENDING}
|
153
|
+
end
|
154
|
+
|
155
|
+
# Get all items which are checked out
|
156
|
+
def checked_out_items
|
157
|
+
@queue.select{|i| i[:state] == CHECKED_OUT}
|
158
|
+
end
|
159
|
+
|
160
|
+
# Get all completed items (both failed and successed)
|
161
|
+
def completed_items
|
162
|
+
@queue.select{|i| i[:state] >= FAILED}
|
163
|
+
end
|
164
|
+
|
165
|
+
# Get all failed items
|
166
|
+
def failed_items
|
167
|
+
@queue.select{|i| i[:state] == FAILED}
|
168
|
+
end
|
169
|
+
|
170
|
+
# Get all successed items
|
171
|
+
def successed_items
|
172
|
+
@queue.select{|i| i[:state] == SUCCESS}
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module FloorManager
|
2
|
+
class Workers
|
3
|
+
|
4
|
+
def initialize(*queue)
|
5
|
+
queue = *queue
|
6
|
+
@queue = queue.kind_of?(FloorManager::Queue) ? queue : FloorManager::Queue.new(queue)
|
7
|
+
@mutex = Mutex.new
|
8
|
+
end
|
9
|
+
attr_reader :queue
|
10
|
+
|
11
|
+
def perform(options={})
|
12
|
+
options = {:threads => 1}.merge(options)
|
13
|
+
threads = (0...options[:threads]).to_a.map do |thread_id|
|
14
|
+
Thread.new do
|
15
|
+
until queue.done?
|
16
|
+
if item = checkout
|
17
|
+
value = yield(item)
|
18
|
+
checkin(item, value)
|
19
|
+
else
|
20
|
+
Thread.pass
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
threads.each{|t| t.join}
|
26
|
+
@queue
|
27
|
+
end
|
28
|
+
|
29
|
+
def checkout
|
30
|
+
@mutex.synchronize{@queue.checkout}
|
31
|
+
end
|
32
|
+
|
33
|
+
def checkin(*args)
|
34
|
+
@mutex.synchronize{@queue.checkin(*args)}
|
35
|
+
end
|
36
|
+
|
37
|
+
def synchronize
|
38
|
+
@mutex.synchronize{yield}
|
39
|
+
end
|
40
|
+
alias :exclusively :synchronize
|
41
|
+
end
|
42
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: floormanager
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- "Inge J\xC3\xB8rgensen"
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-14 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 3
|
30
|
+
- 0
|
31
|
+
version: 1.3.0
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
description: Simple ruby library for handling threaded workers operating on a queue
|
35
|
+
email: inge@elektronaut.no
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- LICENSE
|
42
|
+
- README.rdoc
|
43
|
+
files:
|
44
|
+
- .document
|
45
|
+
- .gitignore
|
46
|
+
- LICENSE
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- VERSION
|
50
|
+
- floormanager.gemspec
|
51
|
+
- lib/floormanager.rb
|
52
|
+
- lib/floormanager/queue.rb
|
53
|
+
- lib/floormanager/workers.rb
|
54
|
+
- spec/floormanager_spec.rb
|
55
|
+
- spec/spec.opts
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/elektronaut/floormanager
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.3.6
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: Handle threaded workers like a champ
|
87
|
+
test_files:
|
88
|
+
- spec/floormanager_spec.rb
|
89
|
+
- spec/spec_helper.rb
|