delayer 0.0.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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +13 -0
- data/delayer.gemspec +23 -0
- data/lib/delayer.rb +61 -0
- data/lib/delayer/error.rb +20 -0
- data/lib/delayer/extend.rb +126 -0
- data/lib/delayer/priority.rb +84 -0
- data/lib/delayer/procedure.rb +61 -0
- data/lib/delayer/version.rb +3 -0
- data/test/test_delayer.rb +317 -0
- data/test/test_priority.rb +257 -0
- metadata +84 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -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
|
data/delayer.gemspec
ADDED
@@ -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
|
data/lib/delayer.rb
ADDED
@@ -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,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
|