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 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) 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
+
@@ -0,0 +1,3 @@
1
+ require 'thread'
2
+ require 'floormanager/queue'
3
+ require 'floormanager/workers'
@@ -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
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Floormanager" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'floormanager'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
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