hash_queue 0.1.0 → 0.1.1
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/CHANGELOG.md +6 -1
- data/README.md +15 -3
- data/lib/hash_queue/hash.rb +3 -2
- data/lib/hash_queue/queue.rb +41 -31
- data/lib/hash_queue/version.rb +1 -1
- data/spec/hash_queue/hash_queue_spec.rb +9 -1
- data/spec/hash_queue/queue_spec.rb +30 -0
- data/spec/spec_helper.rb +1 -0
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## 0.1
|
3
|
+
## 0.1.1
|
4
|
+
|
5
|
+
+ [FEATURE] Added queueing in batches (queueing more items in a single method call)
|
6
|
+
+ [BUGFIX] Fixed bug when popping from HashQueue::Queue with blocking option didn't take nil or an empty array as a valid value [ISSUE#1]
|
7
|
+
|
8
|
+
## 0.1.0
|
4
9
|
|
5
10
|
+ Initial release
|
data/README.md
CHANGED
@@ -46,9 +46,19 @@ hash_queue[:my_queue].queue Stuff.new
|
|
46
46
|
hash_queue.queue :my_queue, Stuff.new
|
47
47
|
```
|
48
48
|
|
49
|
-
|
49
|
+
You can also queue multiple items in a single method call:
|
50
50
|
|
51
|
-
|
51
|
+
```ruby
|
52
|
+
hash_queue[:my_queue].queue_many :foo, :bar, :xyz
|
53
|
+
|
54
|
+
# Ruby itself provides some handy magic syntax for expanding arrays into arguments. The result is identical.
|
55
|
+
stuff = [:foo, :bar, :xyz]
|
56
|
+
hash_queue[:my_queue].queue_many *stuff
|
57
|
+
```
|
58
|
+
|
59
|
+
Keys (or namespaces if you prefer) can be anything you want. Usually those will be symbols or strings but don't need to be. Objects, classes, numbers or even `true` or `nil` will work. Same applies for queued items (but beware if you don't pop with `:size` option, you logically won't be able to distinguish if `nil` you get back is `nil` you queued there or just null return value of popping from an empty queue)
|
60
|
+
|
61
|
+
`#queue` is aliased as `#enqueue`, `#push` and `#<<` for convenience. `#queue_many` is aliased as `#enqueue_many` and `#push_many` accordingly.
|
52
62
|
|
53
63
|
### Working with hash_queue as a whole
|
54
64
|
|
@@ -65,9 +75,11 @@ hash_queue.queue :favourite_rubies, 'rubinius'
|
|
65
75
|
hash_queue.size # => 2
|
66
76
|
```
|
67
77
|
|
78
|
+
Also aliased as `#count` and `#length`.
|
79
|
+
|
68
80
|
##### empty?
|
69
81
|
|
70
|
-
Returns `true` or `false` whether
|
82
|
+
Returns `true` or `false` whether HashQueue instance is empty or not.
|
71
83
|
|
72
84
|
```ruby
|
73
85
|
hash_queue = HashQueue.new
|
data/lib/hash_queue/hash.rb
CHANGED
@@ -89,8 +89,9 @@ module HashQueue
|
|
89
89
|
|
90
90
|
class QueueProxy
|
91
91
|
|
92
|
-
[ :queue, :enqueue, :push, :<<, :
|
93
|
-
|
92
|
+
[ :queue, :enqueue, :push, :<<, :queue_many, :enqueue_many, :push_many,
|
93
|
+
:pop, :shift, :size, :count, :length, :empty?, :clear, :lock, :unlock,
|
94
|
+
:locked?, :unlock_all, :count_locks, :locks_count].each do |m|
|
94
95
|
define_method m do |*args|
|
95
96
|
subject.send m, *args
|
96
97
|
end
|
data/lib/hash_queue/queue.rb
CHANGED
@@ -8,27 +8,33 @@ module HashQueue
|
|
8
8
|
@mutex = Mutex.new
|
9
9
|
@queue = []
|
10
10
|
@locks = []
|
11
|
+
@waiting = []
|
11
12
|
end
|
12
13
|
|
13
|
-
def queue(
|
14
|
+
def queue(*objs)
|
14
15
|
@mutex.synchronize do
|
15
|
-
@queue.
|
16
|
+
@queue.concat objs
|
17
|
+
|
18
|
+
wake_waiting unless @waiting.empty?
|
16
19
|
end
|
17
20
|
end
|
18
21
|
alias_method :enqueue, :queue
|
19
22
|
alias_method :push, :queue
|
20
23
|
alias_method :<<, :queue
|
24
|
+
alias_method :queue_many, :queue
|
25
|
+
alias_method :enqueue_many, :queue
|
26
|
+
alias_method :push_many, :queue
|
21
27
|
|
22
28
|
def pop(options = {}, results = [])
|
23
|
-
|
24
|
-
loop do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
@mutex.synchronize do
|
30
|
+
loop do
|
31
|
+
if options[:blocking] and _empty?
|
32
|
+
@waiting.push Thread.current
|
33
|
+
@mutex.sleep
|
34
|
+
else
|
35
|
+
return _pop(options,results)
|
36
|
+
end
|
29
37
|
end
|
30
|
-
else
|
31
|
-
_pop(options,results)
|
32
38
|
end
|
33
39
|
end
|
34
40
|
alias_method :shift, :pop
|
@@ -56,34 +62,38 @@ module HashQueue
|
|
56
62
|
private
|
57
63
|
|
58
64
|
def _pop(options,results)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
if
|
63
|
-
|
64
|
-
return []
|
65
|
-
else
|
66
|
-
return nil
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
(size - _count_locks).times do
|
71
|
-
break if _empty?
|
72
|
-
results.push @queue.shift
|
73
|
-
_lock if options[:lock]
|
74
|
-
end
|
75
|
-
|
76
|
-
if options.key? :size
|
77
|
-
results
|
65
|
+
size = options.fetch(:size, 1)
|
66
|
+
|
67
|
+
if _locked? and _count_locks >= size
|
68
|
+
if options.key? :size
|
69
|
+
return []
|
78
70
|
else
|
79
|
-
|
71
|
+
return nil
|
80
72
|
end
|
81
|
-
end
|
73
|
+
end
|
74
|
+
|
75
|
+
(size - _count_locks).times do
|
76
|
+
break if _empty?
|
77
|
+
results.push @queue.shift
|
78
|
+
_lock if options[:lock]
|
79
|
+
end
|
80
|
+
|
81
|
+
if options.key? :size
|
82
|
+
results
|
83
|
+
else
|
84
|
+
results[0]
|
85
|
+
end
|
82
86
|
end
|
83
87
|
|
84
88
|
def _empty?
|
85
89
|
@queue.empty?
|
86
90
|
end
|
91
|
+
|
92
|
+
def wake_waiting
|
93
|
+
@waiting.shift.wakeup
|
94
|
+
rescue ThreadError
|
95
|
+
retry
|
96
|
+
end
|
87
97
|
|
88
98
|
end
|
89
99
|
end
|
data/lib/hash_queue/version.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
#require 'timeout'
|
3
2
|
|
4
3
|
describe HashQueue do
|
5
4
|
it 'should be able to create new HashQueue instance' do
|
@@ -159,6 +158,15 @@ describe HashQueue::Hash do
|
|
159
158
|
@hash_queue.pop(blocking: true).wont_be_empty
|
160
159
|
end
|
161
160
|
|
161
|
+
it 'should work as expected when an empty array is queued' do
|
162
|
+
Thread.new {
|
163
|
+
sleep 0.5
|
164
|
+
@hash_queue[:foo].queue []
|
165
|
+
}
|
166
|
+
|
167
|
+
Timeout::timeout(0.7) { @hash_queue.pop(blocking: true).must_equal [[]] }
|
168
|
+
end
|
169
|
+
|
162
170
|
end
|
163
171
|
|
164
172
|
end
|
@@ -12,6 +12,16 @@ describe HashQueue::Queue do
|
|
12
12
|
@queue.size.must_equal 0
|
13
13
|
end
|
14
14
|
|
15
|
+
it 'should be able to queue stuff' do
|
16
|
+
@queue.queue :foo
|
17
|
+
@queue.size.must_equal 1
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should be to queue stuff in batches' do
|
21
|
+
@queue.queue_many :foo, :bar, :xyz
|
22
|
+
@queue.size.must_equal 3
|
23
|
+
end
|
24
|
+
|
15
25
|
end
|
16
26
|
|
17
27
|
describe 'when queued stuff' do
|
@@ -89,6 +99,26 @@ describe HashQueue::Queue do
|
|
89
99
|
@queue.pop(blocking: true, size: 1).wont_be_empty
|
90
100
|
end
|
91
101
|
|
102
|
+
it 'should handle nil in queue' do
|
103
|
+
Thread.new {
|
104
|
+
sleep 0.5
|
105
|
+
@queue.queue_many nil, nil
|
106
|
+
}
|
107
|
+
|
108
|
+
Timeout::timeout(0.7) { @queue.pop(blocking: true).must_equal nil }
|
109
|
+
Timeout::timeout(0.7) { @queue.pop(blocking: true, size: 1).must_equal [nil] }
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should handle empty array in queue' do
|
113
|
+
Thread.new {
|
114
|
+
sleep 0.5
|
115
|
+
@queue.queue_many [], []
|
116
|
+
}
|
117
|
+
|
118
|
+
Timeout::timeout(0.7) { @queue.pop(blocking: true).must_equal [] }
|
119
|
+
Timeout::timeout(0.7) { @queue.pop(blocking: true, size: 1).must_equal [[]] }
|
120
|
+
end
|
121
|
+
|
92
122
|
end
|
93
123
|
|
94
124
|
describe 'locking' do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|