delayer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in delayer.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Toshiaki Asai
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # Delayer
2
+
3
+ Delay Any task. Similar priority-queue.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'delayer'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install delayer
18
+
19
+ ## Usage
20
+
21
+ Task = Delayer.generate_class # Define basic class
22
+ Task = Delayer.generate_class(priority: [:high, :middle, :low], default: :middle) # or, Priority delayer
23
+ Task = Delayer.generate_class(expire: 0.5) # and/or, Time limited delayer.
24
+
25
+ task = Task.new { delayed code ... } # Register task
26
+ task = Task.new(:high) { delayed code ... } # or, You can specify priority.
27
+
28
+ task.cancel # Task can cancel before Delayer#run.
29
+
30
+ Task.run # Execute all tasks.
31
+ Task.run(1) # or, You can specify expire.
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ task :default => [:test]
6
+
7
+ Rake::TestTask.new do |test|
8
+ # $LOAD_PATH に追加するパス (デフォルトで 'lib' は入っている)
9
+ test.libs << 'test'
10
+ # テスト対象ファイルの指定
11
+ test.test_files = Dir[ 'test/**/test_*.rb' ]
12
+ test.verbose = true
13
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'delayer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "delayer"
8
+ spec.version = Delayer::VERSION
9
+ spec.authors = ["Toshiaki Asai"]
10
+ spec.email = ["toshi.alternative@gmail.com"]
11
+ spec.description = %q{Delay the processing}
12
+ spec.summary = %q{Delay the processing}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.2.3"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,61 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "delayer/version"
3
+ require "delayer/error"
4
+ require "delayer/extend"
5
+ require "delayer/procedure"
6
+ require "delayer/priority"
7
+ require "monitor"
8
+
9
+ module Delayer
10
+ class << self
11
+ attr_accessor :default
12
+
13
+ def included(klass)
14
+ klass.extend Extend
15
+ end
16
+
17
+ # Generate new Delayer class.
18
+ # ==== Args
19
+ # [options]
20
+ # Hash
21
+ # expire :: processing expire (secs, 0=unlimited)
22
+ # priority :: priorities
23
+ # default :: default priotity
24
+ # ==== Return
25
+ # A new class
26
+ def generate_class(options = {})
27
+ if options[:priority]
28
+ Class.new do
29
+ include Priority
30
+ @expire = options[:expire] || 0
31
+ @priorities = options[:priority]
32
+ @default_priority = options[:default]
33
+ end
34
+ else
35
+ Class.new do
36
+ include ::Delayer
37
+ @expire = options[:expire] || 0
38
+ end
39
+ end
40
+ end
41
+
42
+ def method_missing(*args, &proc)
43
+ (@default ||= generate_class).__send__(*args, &proc)
44
+ end
45
+ end
46
+
47
+ def initialize(*args)
48
+ super
49
+ @procedure = Procedure.new(self, &Proc.new)
50
+ end
51
+
52
+ # Cancel this job
53
+ # ==== Exception
54
+ # Delayer::AlreadyExecutedError :: if already called run()
55
+ # ==== Return
56
+ # self
57
+ def cancel
58
+ @procedure.cancel
59
+ self
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Delayer
4
+ class Error < ::StandardError; end
5
+ class TooLate < Error; end
6
+ class AlreadyExecutedError < TooLate; end
7
+ class AlreadyCanceledError < TooLate; end
8
+ class AlreadyRunningError < TooLate; end
9
+ class InvalidPriorityError < Error; end
10
+ def self.StateError(state)
11
+ case state
12
+ when :run
13
+ AlreadyRunningError
14
+ when :done
15
+ AlreadyExecutedError
16
+ when :cancel
17
+ AlreadyCanceledError
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,126 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Delayer
4
+ module Extend
5
+ attr_accessor :expire
6
+
7
+ def self.extended(klass)
8
+ klass.class_eval do
9
+ @first_pointer = @last_pointer = nil
10
+ @busy = false
11
+ @expire = 0
12
+ @remain_hook = nil
13
+ @remain_received = false
14
+ @lock = Mutex.new
15
+ end
16
+ end
17
+
18
+ # Run registered jobs.
19
+ # ==== Args
20
+ # [current_expire] expire for processing (secs, 0=unexpired)
21
+ # ==== Return
22
+ # self
23
+ def run(current_expire = @expire)
24
+ if 0 == current_expire
25
+ run_once while not empty?
26
+ else
27
+ @end_time = Time.new.to_f + @expire
28
+ run_once while not(empty?) and @end_time >= Time.new.to_f
29
+ @end_time = nil
30
+ end
31
+ if @remain_hook
32
+ @remain_received = !empty?
33
+ @remain_hook.call if @remain_received
34
+ end
35
+ end
36
+
37
+ def expire?
38
+ if defined?(@end_time) and @end_time
39
+ @end_time < Time.new.to_f
40
+ else
41
+ false
42
+ end
43
+ end
44
+
45
+ # Run a job and forward pointer.
46
+ # ==== Return
47
+ # self
48
+ def run_once
49
+ if @first_pointer
50
+ @busy = true
51
+ procedure = forward
52
+ procedure = forward while @first_pointer and procedure.canceled?
53
+ procedure.run unless procedure.canceled?
54
+ end
55
+ ensure
56
+ @busy = false
57
+ end
58
+
59
+ # Return if some jobs processing now.
60
+ # ==== Args
61
+ # [args]
62
+ # ==== Return
63
+ # true if Delayer processing job
64
+ def busy?
65
+ @busy
66
+ end
67
+
68
+ # Return true if no jobs has.
69
+ # ==== Return
70
+ # true if no jobs has.
71
+ def empty?
72
+ !@first_pointer
73
+ end
74
+
75
+ # Return remain jobs quantity.
76
+ # ==== Return
77
+ # Count of remain jobs
78
+ def size(node = @first_pointer)
79
+ if node
80
+ 1 + size(node.next)
81
+ else
82
+ 0
83
+ end
84
+ end
85
+
86
+ # register new job.
87
+ # ==== Args
88
+ # [procedure] job(Delayer::Procedure)
89
+ # ==== Return
90
+ # self
91
+ def register(procedure)
92
+ lock.synchronize do
93
+ if @last_pointer
94
+ @last_pointer = @last_pointer.break procedure
95
+ else
96
+ @last_pointer = @first_pointer = procedure
97
+ end
98
+ if @remain_hook and not @remain_received
99
+ @remain_received = true
100
+ @remain_hook.call
101
+ end
102
+ end
103
+ self
104
+ end
105
+
106
+ def register_remain_hook
107
+ @remain_hook = Proc.new
108
+ end
109
+
110
+ private
111
+
112
+ def forward
113
+ lock.synchronize do
114
+ prev = @first_pointer
115
+ @first_pointer = @first_pointer.next
116
+ @last_pointer = nil unless @first_pointer
117
+ prev
118
+ end
119
+ end
120
+
121
+ def lock
122
+ @lock
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,84 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Delayer
4
+ module Priority
5
+ attr_reader :priority
6
+
7
+ def self.included(klass)
8
+ klass.class_eval do
9
+ include ::Delayer
10
+ extend Extend
11
+ end
12
+ end
13
+
14
+ def initialize(priority = self.class.instance_eval{ @default_priority }, *args)
15
+ self.class.validate_priority priority
16
+ @priority = priority
17
+ super(*args)
18
+ end
19
+
20
+ module Extend
21
+ def self.extended(klass)
22
+ klass.class_eval do
23
+ @priority_pointer = {}
24
+ end
25
+ end
26
+
27
+ # register new job.
28
+ # ==== Args
29
+ # [procedure] job(Delayer::Procedure)
30
+ # ==== Return
31
+ # self
32
+ def register(procedure)
33
+ priority = procedure.delayer.priority
34
+ lock.synchronize do
35
+ last_pointer = get_prev_point(priority)
36
+ if last_pointer
37
+ @priority_pointer[priority] = last_pointer.break procedure
38
+ else
39
+ procedure.next = @first_pointer
40
+ @priority_pointer[priority] = @first_pointer = procedure
41
+ end
42
+ if @last_pointer
43
+ @last_pointer = @priority_pointer[priority]
44
+ end
45
+ if @remain_hook and not @remain_received
46
+ @remain_received = true
47
+ @remain_hook.call
48
+ end
49
+ end
50
+ self
51
+ end
52
+
53
+ def get_prev_point(priority)
54
+ if @priority_pointer[priority]
55
+ @priority_pointer[priority]
56
+ else
57
+ next_index = @priorities.index(priority) - 1
58
+ get_prev_point @priorities[next_index] if 0 <= next_index
59
+ end
60
+ end
61
+
62
+ def validate_priority(symbol)
63
+ unless @priorities.include? symbol
64
+ raise Delayer::InvalidPriorityError, "undefined priority '#{symbol}'"
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def forward
71
+ lock.synchronize do
72
+ prev = @first_pointer
73
+ @first_pointer = @first_pointer.next
74
+ @last_pointer = nil unless @first_pointer
75
+ @priority_pointer.each do |priority, pointer|
76
+ @priority_pointer[priority] = @first_pointer if prev == pointer
77
+ end
78
+ prev
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,61 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Delayer
4
+ class Procedure
5
+ attr_reader :state, :delayer
6
+ attr_accessor :next
7
+ def initialize(delayer, &proc)
8
+ @delayer, @proc = delayer, proc
9
+ @state = :stop
10
+ @next = nil
11
+ @delayer.class.register(self)
12
+ end
13
+
14
+ # Run a process
15
+ # ==== Exception
16
+ # Delayer::TooLate :: if already called run()
17
+ # ==== Return
18
+ # node
19
+ def run
20
+ unless :stop == @state
21
+ raise Delayer::StateError(@state), "call twice Delayer::Procedure"
22
+ end
23
+ @state = :run
24
+ @proc.call
25
+ @state = :done
26
+ @proc = nil
27
+ end
28
+
29
+ # Cancel this job
30
+ # ==== Exception
31
+ # Delayer::TooLate :: if already called run()
32
+ # ==== Return
33
+ # self
34
+ def cancel
35
+ unless :stop == @state
36
+ raise Delayer::StateError(@state), "cannot cancel Delayer::Procedure"
37
+ end
38
+ @state = :cancel
39
+ self
40
+ end
41
+
42
+ # Return true if canceled this task
43
+ # ==== Return
44
+ # true if canceled this task
45
+ def canceled?
46
+ :cancel == @state
47
+ end
48
+
49
+ # insert node between self and self.next
50
+ # ==== Args
51
+ # [node] insertion
52
+ # ==== Return
53
+ # node
54
+ def break(node)
55
+ tail = @next
56
+ @next = node
57
+ node.next = tail
58
+ node
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Delayer
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,317 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'test/unit'
6
+ require 'delayer'
7
+
8
+ class TestDelayer < Test::Unit::TestCase
9
+ def setup
10
+ Delayer.default = nil
11
+ end
12
+
13
+ def test_delayed
14
+ delayer = Delayer.generate_class
15
+ a = 0
16
+ delayer.new { a = 1 }
17
+
18
+ assert_equal(0, a)
19
+ delayer.run
20
+ assert_equal(1, a)
21
+ end
22
+
23
+ def test_default
24
+ a = 0
25
+ Delayer.new { a = 1 }
26
+
27
+ assert_equal(0, a)
28
+ Delayer.run
29
+ assert_equal(1, a)
30
+ end
31
+
32
+ def test_timelimited
33
+ delayer = Delayer.generate_class(expire: 0.01)
34
+ a = 0
35
+ delayer.new { sleep 0.1 }
36
+ delayer.new { a = 1 }
37
+
38
+ assert_equal(0, a)
39
+ delayer.run
40
+ assert_equal(0, a)
41
+ delayer.run
42
+ assert_equal(1, a)
43
+ end
44
+
45
+ def test_busy
46
+ delayer = Delayer.generate_class
47
+ a = false
48
+ delayer.new { a = delayer.busy? }
49
+
50
+ assert_equal(false, a)
51
+ assert_equal(false, delayer.busy?)
52
+ delayer.run
53
+ assert_equal(false, delayer.busy?)
54
+ assert_equal(true, a)
55
+ end
56
+
57
+ def test_empty
58
+ delayer = Delayer.generate_class
59
+ a = false
60
+ delayer.new { a = delayer.empty? }
61
+
62
+ assert_equal(false, a)
63
+ assert_equal(false, delayer.empty?)
64
+ delayer.run
65
+ assert_equal(true, delayer.empty?)
66
+ assert_equal(true, a)
67
+ end
68
+
69
+ def test_size
70
+ delayer = Delayer.generate_class
71
+ a = 0
72
+ assert_equal(0, delayer.size)
73
+ delayer.new { a += 1 }
74
+ assert_equal(1, delayer.size)
75
+ delayer.new { a += 1 }
76
+ delayer.new { a += 1 }
77
+ assert_equal(3, delayer.size)
78
+ delayer.run
79
+ assert_equal(0, delayer.size)
80
+ end
81
+
82
+ def test_cancel_begin
83
+ delayer = Delayer.generate_class
84
+ a = 0
85
+ d = delayer.new { a += 1 }
86
+ delayer.new { a += 2 }
87
+ delayer.new { a += 4 }
88
+
89
+ assert_equal(0, a)
90
+ d.cancel
91
+ delayer.run
92
+ assert_equal(6, a)
93
+ end
94
+
95
+ def test_cancel_center
96
+ delayer = Delayer.generate_class
97
+ a = 0
98
+ delayer.new { a += 1 }
99
+ d = delayer.new { a += 2 }
100
+ delayer.new { a += 4 }
101
+
102
+ assert_equal(0, a)
103
+ d.cancel
104
+ delayer.run
105
+ assert_equal(5, a)
106
+ end
107
+
108
+ def test_cancel_end
109
+ delayer = Delayer.generate_class
110
+ a = 0
111
+ delayer.new { a += 1 }
112
+ delayer.new { a += 2 }
113
+ d = delayer.new { a += 4 }
114
+
115
+ assert_equal(0, a)
116
+ d.cancel
117
+ delayer.run
118
+ assert_equal(3, a)
119
+ end
120
+
121
+ def test_priority_asc
122
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
123
+ default: :middle)
124
+ buffer = []
125
+ delayer.new(:high) { buffer << 1 }
126
+ delayer.new(:middle) { buffer << 2 }
127
+ delayer.new(:low) { buffer << 3 }
128
+ delayer.run
129
+ assert_equal([1,2,3], buffer)
130
+ end
131
+
132
+ def test_priority_desc
133
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
134
+ default: :middle)
135
+ buffer = []
136
+ delayer.new(:low) { buffer << 3 }
137
+ delayer.new(:middle) { buffer << 2 }
138
+ delayer.new(:high) { buffer << 1 }
139
+ delayer.run
140
+ assert_equal([1,2,3], buffer)
141
+ end
142
+
143
+ def test_priority_complex
144
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
145
+ default: :middle)
146
+ buffer = []
147
+ delayer.new(:high) { buffer << 1 }
148
+ delayer.new(:middle) { buffer << 2 }
149
+ delayer.new(:low) { buffer << 3 }
150
+ delayer.new(:middle) { buffer << 4 }
151
+ delayer.new(:high) { buffer << 5 }
152
+ delayer.new(:middle) { buffer << 6 }
153
+ delayer.new(:low) { buffer << 7 }
154
+ delayer.new(:middle) { buffer << 8 }
155
+ delayer.new(:high) { buffer << 9 }
156
+ delayer.run
157
+ assert_equal([1,5,9,2,4,6,8,3,7], buffer)
158
+
159
+ buffer = []
160
+ delayer.new(:high) { buffer << 1 }
161
+ delayer.new(:low) { buffer << 2 }
162
+ delayer.new(:high) { buffer << 3 }
163
+ delayer.new(:low) { buffer << 4 }
164
+ delayer.run
165
+ assert_equal([1,3,2,4], buffer)
166
+ end
167
+
168
+ def test_priority_cancel_begin
169
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
170
+ default: :middle)
171
+ a = 0
172
+ d = delayer.new { a += 1 }
173
+ delayer.new { a += 2 }
174
+ delayer.new { a += 4 }
175
+ assert_equal(0, a)
176
+ d.cancel
177
+ delayer.run
178
+ assert_equal(6, a)
179
+
180
+ a = 0
181
+ d = delayer.new(:low) { a += 1 }
182
+ delayer.new(:high) { a += 2 }
183
+ delayer.new(:high) { a += 4 }
184
+ assert_equal(0, a)
185
+ d.cancel
186
+ delayer.run
187
+ assert_equal(6, a)
188
+
189
+ a = 0
190
+ d = delayer.new(:high) { a += 1 }
191
+ delayer.new(:low) { a += 2 }
192
+ delayer.new(:low) { a += 4 }
193
+ assert_equal(0, a)
194
+ d.cancel
195
+ delayer.run
196
+ assert_equal(6, a)
197
+ end
198
+
199
+ def test_priority_cancel_center
200
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
201
+ default: :middle)
202
+ a = 0
203
+ delayer.new { a += 1 }
204
+ d = delayer.new { a += 2 }
205
+ delayer.new { a += 4 }
206
+ assert_equal(0, a)
207
+ d.cancel
208
+ delayer.run
209
+ assert_equal(5, a)
210
+
211
+ a = 0
212
+ delayer.new(:low) { a += 1 }
213
+ d = delayer.new(:high) { a += 2 }
214
+ delayer.new(:low) { a += 4 }
215
+ assert_equal(0, a)
216
+ d.cancel
217
+ delayer.run
218
+ assert_equal(5, a)
219
+
220
+ a = 0
221
+ delayer.new(:high) { a += 1 }
222
+ d = delayer.new(:low) { a += 2 }
223
+ delayer.new(:high) { a += 4 }
224
+ assert_equal(0, a)
225
+ d.cancel
226
+ delayer.run
227
+ assert_equal(5, a)
228
+ end
229
+
230
+ def test_priority_cancel_end
231
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
232
+ default: :middle)
233
+ a = 0
234
+ delayer.new { a += 1 }
235
+ delayer.new { a += 2 }
236
+ d = delayer.new { a += 4 }
237
+ assert_equal(0, a)
238
+ d.cancel
239
+ delayer.run
240
+ assert_equal(3, a)
241
+
242
+ a = 0
243
+ delayer.new(:low) { a += 1 }
244
+ delayer.new(:low) { a += 2 }
245
+ d = delayer.new(:high) { a += 4 }
246
+ assert_equal(0, a)
247
+ d.cancel
248
+ delayer.run
249
+ assert_equal(3, a)
250
+
251
+ a = 0
252
+ delayer.new(:high) { a += 1 }
253
+ delayer.new(:high) { a += 2 }
254
+ d = delayer.new(:low) { a += 4 }
255
+ assert_equal(0, a)
256
+ d.cancel
257
+ delayer.run
258
+ assert_equal(3, a)
259
+ end
260
+
261
+ def test_multithread_register
262
+ delayer = Delayer.generate_class
263
+ buffer = []
264
+ threads = []
265
+ 10.times do
266
+ threads << Thread.new do
267
+ 1000.times do |number|
268
+ delayer.new { buffer << number }
269
+ end
270
+ end
271
+ end
272
+ delayer.run
273
+ threads.each &:join
274
+ delayer.run
275
+ assert_equal(10000, buffer.size)
276
+ assert_equal((0..999).inject(&:+)*10, buffer.inject(&:+))
277
+ end
278
+
279
+ def test_nested
280
+ delayer = Delayer.generate_class
281
+ buffer = []
282
+ delayer.new { buffer << 1 }
283
+ delayer.new do
284
+ delayer.new { buffer << 3 }
285
+ delayer.new do
286
+ delayer.new { buffer << 5 }
287
+ delayer.new { buffer << 6 }
288
+ end
289
+ delayer.new { buffer << 4 }
290
+ end
291
+ delayer.new { buffer << 2 }
292
+
293
+ delayer.run
294
+ assert_equal([1,2,3,4,5,6], buffer)
295
+ end
296
+
297
+ def test_remain_hook
298
+ delayer = Delayer.generate_class expire: 0.01
299
+ a = []
300
+ delayer.register_remain_hook {
301
+ a << :remain
302
+ }
303
+ delayer.new { a << 0 }
304
+ delayer.new { a << 1; sleep 0.1 }
305
+ delayer.new { a << 2 }
306
+
307
+ delayer.run
308
+
309
+ delayer.new { a << 3 }
310
+ delayer.new { a << 4 }
311
+
312
+ delayer.run
313
+
314
+ assert_equal([:remain, 0, 1, :remain, 2, 3, 4], a)
315
+
316
+ end
317
+ end
@@ -0,0 +1,257 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'test/unit'
6
+ require 'delayer'
7
+
8
+ class TestPriorityDelayer < Test::Unit::TestCase
9
+ def test_asc
10
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
11
+ default: :middle)
12
+ buffer = []
13
+ delayer.new(:high) { buffer << 1 }
14
+ delayer.new(:middle) { buffer << 2 }
15
+ delayer.new(:low) { buffer << 3 }
16
+ delayer.run
17
+ assert_equal([1,2,3], buffer)
18
+ end
19
+
20
+ def test_desc
21
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
22
+ default: :middle)
23
+ buffer = []
24
+ delayer.new(:low) { buffer << 3 }
25
+ delayer.new(:middle) { buffer << 2 }
26
+ delayer.new(:high) { buffer << 1 }
27
+ delayer.run
28
+ assert_equal([1,2,3], buffer)
29
+ end
30
+
31
+ def test_complex
32
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
33
+ default: :middle)
34
+ buffer = []
35
+ delayer.new(:high) { buffer << 1 }
36
+ delayer.new(:middle) { buffer << 2 }
37
+ delayer.new(:low) { buffer << 3 }
38
+ delayer.new(:middle) { buffer << 4 }
39
+ delayer.new(:high) { buffer << 5 }
40
+ delayer.new(:middle) { buffer << 6 }
41
+ delayer.new(:low) { buffer << 7 }
42
+ delayer.new(:middle) { buffer << 8 }
43
+ delayer.new(:high) { buffer << 9 }
44
+ delayer.run
45
+ assert_equal([1,5,9,2,4,6,8,3,7], buffer)
46
+
47
+ buffer = []
48
+ delayer.new(:high) { buffer << 1 }
49
+ delayer.new(:low) { buffer << 2 }
50
+ delayer.new(:high) { buffer << 3 }
51
+ delayer.new(:low) { buffer << 4 }
52
+ delayer.run
53
+ assert_equal([1,3,2,4], buffer)
54
+ end
55
+
56
+ def test_timelimited
57
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
58
+ default: :middle,
59
+ expire: 0.01)
60
+ a = 0
61
+ delayer.new { sleep 0.1 }
62
+ delayer.new { a = 1 }
63
+
64
+ assert_equal(0, a)
65
+ delayer.run
66
+ assert_equal(0, a)
67
+ delayer.run
68
+ assert_equal(1, a)
69
+ end
70
+
71
+ def test_busy
72
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
73
+ default: :middle)
74
+ a = false
75
+ delayer.new { a = delayer.busy? }
76
+
77
+ assert_equal(false, a)
78
+ assert_equal(false, delayer.busy?)
79
+ delayer.run
80
+ assert_equal(false, delayer.busy?)
81
+ assert_equal(true, a)
82
+ end
83
+
84
+ def test_empty
85
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
86
+ default: :middle)
87
+ a = false
88
+ delayer.new { a = delayer.empty? }
89
+
90
+ assert_equal(false, a)
91
+ assert_equal(false, delayer.empty?)
92
+ delayer.run
93
+ assert_equal(true, delayer.empty?)
94
+ assert_equal(true, a)
95
+ end
96
+
97
+ def test_size
98
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
99
+ default: :middle)
100
+ a = 0
101
+ assert_equal(0, delayer.size)
102
+ delayer.new { a += 1 }
103
+ assert_equal(1, delayer.size)
104
+ delayer.new { a += 1 }
105
+ delayer.new { a += 1 }
106
+ assert_equal(3, delayer.size)
107
+ delayer.run
108
+ assert_equal(0, delayer.size)
109
+ end
110
+
111
+ def test_cancel_begin
112
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
113
+ default: :middle)
114
+ a = 0
115
+ d = delayer.new { a += 1 }
116
+ delayer.new { a += 2 }
117
+ delayer.new { a += 4 }
118
+ assert_equal(0, a)
119
+ d.cancel
120
+ delayer.run
121
+ assert_equal(6, a)
122
+
123
+ a = 0
124
+ d = delayer.new(:low) { a += 1 }
125
+ delayer.new(:high) { a += 2 }
126
+ delayer.new(:high) { a += 4 }
127
+ assert_equal(0, a)
128
+ d.cancel
129
+ delayer.run
130
+ assert_equal(6, a)
131
+
132
+ a = 0
133
+ d = delayer.new(:high) { a += 1 }
134
+ delayer.new(:low) { a += 2 }
135
+ delayer.new(:low) { a += 4 }
136
+ assert_equal(0, a)
137
+ d.cancel
138
+ delayer.run
139
+ assert_equal(6, a)
140
+ end
141
+
142
+ def test_cancel_center
143
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
144
+ default: :middle)
145
+ a = 0
146
+ delayer.new { a += 1 }
147
+ d = delayer.new { a += 2 }
148
+ delayer.new { a += 4 }
149
+ assert_equal(0, a)
150
+ d.cancel
151
+ delayer.run
152
+ assert_equal(5, a)
153
+
154
+ a = 0
155
+ delayer.new(:low) { a += 1 }
156
+ d = delayer.new(:high) { a += 2 }
157
+ delayer.new(:low) { a += 4 }
158
+ assert_equal(0, a)
159
+ d.cancel
160
+ delayer.run
161
+ assert_equal(5, a)
162
+
163
+ a = 0
164
+ delayer.new(:high) { a += 1 }
165
+ d = delayer.new(:low) { a += 2 }
166
+ delayer.new(:high) { a += 4 }
167
+ assert_equal(0, a)
168
+ d.cancel
169
+ delayer.run
170
+ assert_equal(5, a)
171
+ end
172
+
173
+ def test_cancel_end
174
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
175
+ default: :middle)
176
+ a = 0
177
+ delayer.new { a += 1 }
178
+ delayer.new { a += 2 }
179
+ d = delayer.new { a += 4 }
180
+ assert_equal(0, a)
181
+ d.cancel
182
+ delayer.run
183
+ assert_equal(3, a)
184
+
185
+ a = 0
186
+ delayer.new(:low) { a += 1 }
187
+ delayer.new(:low) { a += 2 }
188
+ d = delayer.new(:high) { a += 4 }
189
+ assert_equal(0, a)
190
+ d.cancel
191
+ delayer.run
192
+ assert_equal(3, a)
193
+
194
+ a = 0
195
+ delayer.new(:high) { a += 1 }
196
+ delayer.new(:high) { a += 2 }
197
+ d = delayer.new(:low) { a += 4 }
198
+ assert_equal(0, a)
199
+ d.cancel
200
+ delayer.run
201
+ assert_equal(3, a)
202
+ end
203
+
204
+ def test_multithread_register
205
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
206
+ default: :middle)
207
+ buffer = []
208
+ threads = []
209
+ 10.times do
210
+ threads << Thread.new do
211
+ 1000.times do |number|
212
+ delayer.new { buffer << number }
213
+ end
214
+ end
215
+ end
216
+ delayer.run
217
+ threads.each &:join
218
+ delayer.run
219
+ assert_equal(10000, buffer.size)
220
+ assert_equal((0..999).inject(&:+)*10, buffer.inject(&:+))
221
+ end
222
+
223
+ def test_nested
224
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low],
225
+ default: :middle)
226
+ buffer = []
227
+ delayer.new { buffer << 1 }
228
+ delayer.new do
229
+ delayer.new { buffer << 3 }
230
+ delayer.new do
231
+ delayer.new { buffer << 5 }
232
+ delayer.new { buffer << 6 }
233
+ end
234
+ delayer.new { buffer << 4 }
235
+ end
236
+ delayer.new { buffer << 2 }
237
+
238
+ delayer.run
239
+ assert_equal([1,2,3,4,5,6], buffer)
240
+ end
241
+
242
+ def test_invalid_priority
243
+ delayer = Delayer.generate_class(priority: [:high, :middle, :low])
244
+ buffer = []
245
+ assert_raise Delayer::InvalidPriorityError do
246
+ delayer.new(0) { buffer << 1 }
247
+ end
248
+ assert_raise Delayer::InvalidPriorityError do
249
+ delayer.new("middle") { buffer << 2 }
250
+ end
251
+ assert_raise Delayer::InvalidPriorityError do
252
+ delayer.new { buffer << 3 }
253
+ end
254
+ delayer.run
255
+ assert_equal([], buffer)
256
+ end
257
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delayer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Toshiaki Asai
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &15390660 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.3
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *15390660
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &18232940 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *18232940
36
+ description: Delay the processing
37
+ email:
38
+ - toshi.alternative@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - LICENSE.txt
46
+ - README.md
47
+ - Rakefile
48
+ - delayer.gemspec
49
+ - lib/delayer.rb
50
+ - lib/delayer/error.rb
51
+ - lib/delayer/extend.rb
52
+ - lib/delayer/priority.rb
53
+ - lib/delayer/procedure.rb
54
+ - lib/delayer/version.rb
55
+ - test/test_delayer.rb
56
+ - test/test_priority.rb
57
+ homepage: ''
58
+ licenses:
59
+ - MIT
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 1.8.11
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Delay the processing
82
+ test_files:
83
+ - test/test_delayer.rb
84
+ - test/test_priority.rb