hash_queue 0.1.1 → 0.1.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.md CHANGED
@@ -22,7 +22,7 @@ For those living on the edge:
22
22
 
23
23
  ..with Bundler 1.1 or newer:
24
24
 
25
- gem 'mimi', github: 'mikekreeki/hash_queue'
25
+ gem 'hash_queue', github: 'mikekreeki/hash_queue'
26
26
 
27
27
  ## Usage
28
28
 
@@ -187,7 +187,30 @@ hash_queue[:foo].pop # => #<Object:0x000001008d4658>
187
187
  hash_queue[:foo].pop(size: 2) # => [#<Object:0x000001008ae228>, #<Object:0x000001008ae200>]
188
188
  ```
189
189
 
190
- You can use same options as mentioned above.
190
+ You can use same options as mentioned above plus you can pass in a block into play. Block passed to `HashQueue::Queue#pop` yields items that otherwise would be directly returned, e.g. popped from the queue, and method actually pops values only if return value of a block evaluates to true.
191
+
192
+ ```ruby
193
+ food = HashQueue::Queue.new
194
+ food.push :carrot
195
+
196
+ food.pop do |snack|
197
+ current_user.favors? snack
198
+ end
199
+ ```
200
+
201
+ ##### peek
202
+
203
+ Use `#peek` to look what is in the head of the queue but without removing it from there.
204
+
205
+ ```ruby
206
+ queue = HashQueue::Queue.new
207
+ queue.push :foo
208
+
209
+ queue.peek # => :foo
210
+ queue.size # => 1
211
+ ```
212
+
213
+ You can peek on more items in the head of the queue specifying `:size` option. Be aware, using `#peek` your code might be subject to race condition. If you want to pop only when some condition is met, use `#pop` with a block mentioned above.
191
214
 
192
215
  ### Locking capabilities
193
216
 
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ require 'rake/testtask'
8
8
  Rake::TestTask.new do |t|
9
9
  t.libs << 'spec'
10
10
  t.pattern = 'spec/**/*_spec.rb'
11
- t.verbose = true
11
+ t.verbose = false
12
12
  end
13
13
 
14
14
  desc "Run tests"
data/hash_queue.gemspec CHANGED
@@ -9,8 +9,7 @@ Gem::Specification.new do |gem|
9
9
  gem.homepage = "http://github.com/mikekreeki/hash_queue"
10
10
 
11
11
  gem.add_development_dependency('minitest')
12
- gem.add_development_dependency('turn')
13
- gem.add_development_dependency('term-ansicolor')
12
+ gem.add_development_dependency('minitest-reporters')
14
13
 
15
14
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
15
  gem.files = `git ls-files`.split("\n")
@@ -90,7 +90,7 @@ module HashQueue
90
90
  class QueueProxy
91
91
 
92
92
  [ :queue, :enqueue, :push, :<<, :queue_many, :enqueue_many, :push_many,
93
- :pop, :shift, :size, :count, :length, :empty?, :clear, :lock, :unlock,
93
+ :pop, :peek, :shift, :size, :count, :length, :empty?, :clear, :lock, :unlock,
94
94
  :locked?, :unlock_all, :count_locks, :locks_count].each do |m|
95
95
  define_method m do |*args|
96
96
  subject.send m, *args
@@ -1,4 +1,5 @@
1
1
  require 'hash_queue/queue/lockable'
2
+ require 'ostruct'
2
3
 
3
4
  module HashQueue
4
5
  class Queue
@@ -15,7 +16,7 @@ module HashQueue
15
16
  @mutex.synchronize do
16
17
  @queue.concat objs
17
18
 
18
- wake_waiting unless @waiting.empty?
19
+ wake_waiting
19
20
  end
20
21
  end
21
22
  alias_method :enqueue, :queue
@@ -28,17 +29,33 @@ module HashQueue
28
29
  def pop(options = {}, results = [])
29
30
  @mutex.synchronize do
30
31
  loop do
31
- if options[:blocking] and _empty?
32
- @waiting.push Thread.current
32
+ if options[:blocking] and not can_pop?(options[:size] || 1)
33
+ @waiting.push OpenStruct.new(thread: Thread.current, pop_size: options[:size] || 1)
33
34
  @mutex.sleep
34
35
  else
35
- return _pop(options,results)
36
+ if block_given?
37
+ should_pop = yield _peek(options)
38
+
39
+ if should_pop
40
+ return _pop(options,results)
41
+ else
42
+ return
43
+ end
44
+ else
45
+ return _pop(options,results)
46
+ end
36
47
  end
37
48
  end
38
49
  end
39
50
  end
40
51
  alias_method :shift, :pop
41
52
 
53
+ def peek(options = {})
54
+ @mutex.synchronize do
55
+ _peek(options)
56
+ end
57
+ end
58
+
42
59
  def size
43
60
  @mutex.synchronize do
44
61
  @queue.size
@@ -64,7 +81,7 @@ module HashQueue
64
81
  def _pop(options,results)
65
82
  size = options.fetch(:size, 1)
66
83
 
67
- if _locked? and _count_locks >= size
84
+ unless can_pop?(size)
68
85
  if options.key? :size
69
86
  return []
70
87
  else
@@ -85,14 +102,34 @@ module HashQueue
85
102
  end
86
103
  end
87
104
 
105
+ def _peek(options)
106
+ if options.has_key? :size
107
+ @queue[0..options[:size]]
108
+ else
109
+ @queue[0]
110
+ end
111
+ end
112
+
88
113
  def _empty?
89
114
  @queue.empty?
90
115
  end
91
116
 
92
117
  def wake_waiting
93
- @waiting.shift.wakeup
94
- rescue ThreadError
95
- retry
118
+ unless @waiting.empty?
119
+ while @waiting[0] and can_pop? @waiting[0].pop_size
120
+ begin
121
+ @waiting.shift.thread.wakeup
122
+ rescue ThreadError
123
+ retry
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def can_pop?(size)
130
+ size = @queue.size if size > @queue.size
131
+
132
+ (not _empty?) and (size > _count_locks)
96
133
  end
97
134
 
98
135
  end
@@ -10,6 +10,8 @@ module HashQueue
10
10
  def unlock(n = 1)
11
11
  @mutex.synchronize do
12
12
  @locks.shift(n)
13
+
14
+ wake_waiting
13
15
  end
14
16
  end
15
17
 
@@ -22,6 +24,8 @@ module HashQueue
22
24
  def unlock_all
23
25
  @mutex.synchronize do
24
26
  @locks.clear
27
+
28
+ wake_waiting
25
29
  end
26
30
  end
27
31
 
@@ -1,3 +1,3 @@
1
1
  module HashQueue
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -62,6 +62,35 @@ describe HashQueue::Queue do
62
62
  @queue.clear
63
63
  @queue.pop(size: 1).must_equal []
64
64
  end
65
+
66
+ it 'should yeild items in the block passed to #pop' do
67
+ @queue.pop { |item| item.must_equal 1 }
68
+ @queue.pop(size: 1) { |items| items.must_equal [2] }
69
+ end
70
+
71
+ it 'should pop when block passed to #pop evaluates to truthy value' do
72
+ item = @queue.pop do
73
+ true
74
+ end
75
+
76
+ item.must_equal 1
77
+ end
78
+
79
+ it 'shouldnt pop when block passed to #pop evaluates to falsy value' do
80
+ item = @queue.pop {}
81
+
82
+ item.must_be_nil
83
+ end
84
+
85
+ it 'should be able to peek in the queue' do
86
+ @queue.peek.must_equal 1
87
+ @queue.size.must_equal 2
88
+ end
89
+
90
+ it 'should be able to peek on batch of items' do
91
+ @queue.peek(size: 2).must_equal [1,2]
92
+ @queue.size.must_equal 2
93
+ end
65
94
  end
66
95
 
67
96
  describe 'when we queue weird stuff' do
@@ -99,6 +128,43 @@ describe HashQueue::Queue do
99
128
  @queue.pop(blocking: true, size: 1).wont_be_empty
100
129
  end
101
130
 
131
+ it 'should return appropriate number of items when locked and size is specified' do
132
+ @queue.lock 1
133
+
134
+ Thread.new {
135
+ sleep 0.5
136
+ @queue.queue :foo
137
+ @queue.queue :bar
138
+ }
139
+
140
+ Timeout::timeout(0.7) { @queue.pop(blocking: true, size: 2).must_equal [:foo] }
141
+ end
142
+
143
+ it 'should wait until queue is unlocked' do
144
+ @queue.push :foo, :bar, :xyz
145
+ @queue.lock 3
146
+
147
+ Thread.new {
148
+ sleep 0.5
149
+ @queue.unlock
150
+ sleep 0.5
151
+ @queue.unlock_all
152
+ }
153
+
154
+ Timeout::timeout(0.7) { @queue.pop(blocking: true, size: 3).must_equal [:foo] }
155
+ Timeout::timeout(0.7) { @queue.pop(blocking: true, size: 3).must_equal [:bar, :xyz] }
156
+ end
157
+
158
+ it 'should wake multiple threads if necessary' do
159
+ threads = []
160
+ threads << Thread.new { sleep 0.1; @queue.pop(blocking: true).must_equal :foo }
161
+ threads << Thread.new { sleep 0.2; @queue.pop(blocking: true).must_equal :bar }
162
+
163
+ sleep 0.1
164
+ @queue.push :foo, :bar
165
+ Timeout::timeout(0.7) { threads.map(&:join) }
166
+ end
167
+
102
168
  it 'should handle nil in queue' do
103
169
  Thread.new {
104
170
  sleep 0.5
data/spec/spec_helper.rb CHANGED
@@ -2,7 +2,9 @@ require 'bundler/setup'
2
2
  require 'timeout'
3
3
 
4
4
  require 'minitest/autorun'
5
- require 'turn/autorun'
5
+ require "minitest/reporters"
6
6
 
7
7
  require 'hash_queue'
8
8
 
9
+
10
+ MiniTest::Reporters.use! MiniTest::Reporters::ProgressReporter.new
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.1
4
+ version: 0.1.2
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-10 00:00:00.000000000 Z
12
+ date: 2012-12-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -28,23 +28,7 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
30
  - !ruby/object:Gem::Dependency
31
- name: turn
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :development
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: term-ansicolor
31
+ name: minitest-reporters
48
32
  requirement: !ruby/object:Gem::Requirement
49
33
  none: false
50
34
  requirements: