rask 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.0 2010-02-11
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/README.rdoc ADDED
@@ -0,0 +1,105 @@
1
+ = rask
2
+
3
+ * http://github.com/mewlist/Rask
4
+
5
+ == DESCRIPTION:
6
+
7
+ Rask を使うと、タスク処理をシンプルに記述できます。
8
+
9
+ タスクの実行状態が自動的に永続化されるので、
10
+ タスクの中断、復帰が容易です。
11
+ これらの処理は、web のように処理がまばらな環境での利用を想定しています。
12
+ また、膨大な時間がかかる計算処理などでの利用も考えられます。
13
+
14
+
15
+
16
+ == FEATURES/PROBLEMS:
17
+
18
+ * ステートマシンの記述 (Act As State Machine と似てる)
19
+ * タスク状態の永続化
20
+
21
+ == SYNOPSIS:
22
+
23
+ * タスクの定義 (countup.rb)
24
+ require 'rubygems'
25
+ require 'rask'
26
+ #
27
+ # 数値のカウントアップ 10 までカウントする
28
+ # タスクの定義
29
+ #
30
+ class CountupTask < Rask::Task
31
+ define_state :start, :initial => true # 初期状態
32
+ define_state :running # 実行
33
+ define_state :finish, :from => [:running] # 終了 (遷移元は:runningからのみ)
34
+
35
+ def start
36
+ @count = 0
37
+ p "start"
38
+ transition_to_running # :running へ遷移
39
+ end
40
+
41
+ def running
42
+ p "running count => #{@count+=1}"
43
+ transition_to_finish if @count>=10 # :finish へ遷移
44
+ end
45
+
46
+ def finish
47
+ p "finished"
48
+ destroy # タスクの破棄
49
+ end
50
+ end
51
+
52
+
53
+ # タスクを動かす
54
+ if __FILE__ == $0
55
+ task = CountupTask.new # タスクの作成
56
+ Rask.insert task # タスクの登録
57
+ end
58
+
59
+
60
+ * タスクを実行するデーモン(daemon.rb)
61
+ require 'rubygems'
62
+ require 'rask'
63
+
64
+ # バックグラウンドタスクの実行
65
+ Rask.daemon(:sleep=>0.1)
66
+
67
+
68
+ デーモンを実行しておくと、Rask.insert を行うだけで
69
+ タスクが自動的に実行されていきます。
70
+
71
+ $ ruby daemon.rb
72
+ $ ruby countup.rb
73
+
74
+ == REQUIREMENTS:
75
+
76
+ ruby1.8.7で作ってる
77
+
78
+ == INSTALL:
79
+
80
+ gem install rask
81
+
82
+ == LICENSE:
83
+
84
+ (The MIT License)
85
+
86
+ Copyright (c) 2010 mewlist / Hidenori Doi
87
+
88
+ Permission is hereby granted, free of charge, to any person obtaining
89
+ a copy of this software and associated documentation files (the
90
+ 'Software'), to deal in the Software without restriction, including
91
+ without limitation the rights to use, copy, modify, merge, publish,
92
+ distribute, sublicense, and/or sell copies of the Software, and to
93
+ permit persons to whom the Software is furnished to do so, subject to
94
+ the following conditions:
95
+
96
+ The above copyright notice and this permission notice shall be
97
+ included in all copies or substantial portions of the Software.
98
+
99
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
100
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
101
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
102
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
103
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
104
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
105
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,90 @@
1
+ #
2
+ # Rask
3
+ # StateMachinelibrary
4
+ # (c)2010 mewlist
5
+ #
6
+ require 'thread'
7
+
8
+
9
+
10
+ module Rask
11
+
12
+ module StateMachine
13
+ attr_accessor :state
14
+
15
+
16
+ def initialize
17
+ @state = initial_state
18
+ end
19
+
20
+
21
+ def initial_state
22
+ nil
23
+ end
24
+
25
+
26
+ def transition(to)
27
+ @state = to
28
+ end
29
+
30
+
31
+ def destroy
32
+ transition nil
33
+ end
34
+
35
+
36
+ def destroy?
37
+ @state == nil
38
+ end
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+ def self.included(base)
48
+ base.extend(ClassMethods)
49
+ end
50
+
51
+
52
+
53
+
54
+
55
+
56
+ module ClassMethods
57
+ def define_state(name, *args)
58
+
59
+ self.instance_eval{
60
+ define_method(name){
61
+ }
62
+ define_method("transition_to_#{name}"){
63
+ if args[0].is_a?(Hash)
64
+ self.state = name if args[0][:from] && args[0][:from].include?(state)
65
+ else
66
+ self.state = name
67
+ end
68
+ }
69
+ define_method("#{name}?"){
70
+ self.state == name
71
+ }
72
+ if !method_defined?(name) || ( args[0].is_a?(Hash) && args[0][:initial] )
73
+ define_method("initial_state") {
74
+ name
75
+ }
76
+ end
77
+ }
78
+ end
79
+ end
80
+ end
81
+
82
+
83
+
84
+
85
+ end
86
+
87
+
88
+
89
+
90
+
data/lib/rask.rb ADDED
@@ -0,0 +1,158 @@
1
+ #
2
+ # Rask library
3
+ # (c)2010 mewlist
4
+ #
5
+ require 'fileutils'
6
+ require 'thread'
7
+
8
+ require File.dirname(__FILE__) + '/rask/state_machine'
9
+
10
+
11
+ module Rask
12
+
13
+ class Task
14
+ include StateMachine
15
+ attr_accessor :task_id
16
+ attr_accessor :group
17
+
18
+ def initialize(_group=nil)
19
+ group = _group
20
+ super()
21
+ end
22
+
23
+
24
+ def run
25
+ if @state
26
+ eval @state.to_s
27
+ end
28
+ end
29
+
30
+
31
+ def transition(to)
32
+ @state = to
33
+ end
34
+
35
+
36
+ def destroy
37
+ transition nil
38
+ end
39
+
40
+
41
+ def destroy?
42
+ @state == nil
43
+ end
44
+
45
+ end
46
+
47
+
48
+ @@base_dir = '/tmp/rask'
49
+ @@threading = false
50
+
51
+ def self.base_directory=(new_directory)
52
+ @@base_dir = new_directory
53
+ end
54
+
55
+ def self.enable_thread
56
+ @@threading = true
57
+ end
58
+
59
+ def self.disable_thread
60
+ @@threading = false
61
+ end
62
+
63
+ def self.insert(task)
64
+ initialize_storage
65
+ task_id = "#{safe_class_name(task.class.name)}-#{task.group.to_s}-#{Time.now.to_i}-#{Time.now.usec}"
66
+ task.task_id = task_id
67
+ FileUtils.touch(task_path(task_id)) unless File.exists? task_path(task_id)
68
+ f = File.open(task_path(task_id), 'w')
69
+ f.flock(File::LOCK_EX)
70
+ Marshal.dump(task, f)
71
+ f.flock(File::LOCK_UN)
72
+ f.close
73
+ end
74
+
75
+
76
+ def self.run(task_path)
77
+ f = File.open(task_path, 'r+')
78
+ f.flock(File::LOCK_EX)
79
+
80
+ task = Marshal.restore(f)
81
+ yield task
82
+
83
+ f.truncate(0)
84
+ f.pos = 0
85
+ Marshal.dump(task, f)
86
+ f.flock(File::LOCK_UN)
87
+ f.close
88
+ FileUtils.rm(task_path) if task.destroy?
89
+ end
90
+
91
+ def self.each(options = { :class=>nil, :group=>nil }, &blk)
92
+ threads = []
93
+ tasks(options).each { |d|
94
+ if @@threading
95
+ threads << Thread::new(d) { |task_path| run(task_path, &blk) }
96
+ else
97
+ run(d, &blk)
98
+ end
99
+ }
100
+ threads.each { |t| t.join } if @@threading
101
+ end
102
+
103
+ def self.tasks(options = { :class=>nil, :group=>nil })
104
+ target = task_dir
105
+ target += '/' if options[:class] || options[:group]
106
+ target += "#{safe_class_name(options[:class])}" if options[:class]
107
+ target += "-#{options[:group]}-" if options[:group]
108
+
109
+ task_list = []
110
+ Dir.glob(task_dir+"/*.task") { |d|
111
+ if target.empty? || /#{target}/ =~ d
112
+ task_list.push d
113
+ end
114
+ }
115
+ task_list
116
+ end
117
+
118
+ def self.task_dir
119
+ @@base_dir
120
+ end
121
+
122
+ def self.task_path(task_id)
123
+ task_dir+"/#{task_id}.task"
124
+ end
125
+
126
+ def self.initialize_storage
127
+ unless File.exists? @@base_dir
128
+ FileUtils.makedirs @@base_dir
129
+ end
130
+ end
131
+
132
+ def self.destroy(task)
133
+ FileUtils.rm(task_path(task.task_id)) if File.exists? task_path(task.task_id)
134
+ end
135
+
136
+ def self.safe_class_name(c)
137
+ c.gsub(/[:]/,'@')
138
+ end
139
+
140
+ def self.daemon(options = { :class=>nil, :group=>nil, :sleep=>1 })
141
+ exit if fork
142
+ Process.setsid
143
+ open(task_dir+"/Rask.pid","w"){|f| f.write Process.pid}
144
+ while true
145
+ Rask.each { |task|
146
+ task.run
147
+ }
148
+ sleep(options[:sleep])
149
+ end
150
+ end
151
+
152
+
153
+ end
154
+
155
+
156
+
157
+
158
+
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/rask'
data/test/test_rask.rb ADDED
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestRask < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rask
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - mewlist / Hidenori Doi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-11 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: mewlist@mewlist.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ files:
25
+ - test/test_helper.rb
26
+ - test/test_rask.rb
27
+ - lib/rask.rb
28
+ - lib/rask/state_machine.rb
29
+ - README.rdoc
30
+ - History.txt
31
+ has_rdoc: true
32
+ homepage: http://mewlist.com/
33
+ licenses: []
34
+
35
+ post_install_message:
36
+ rdoc_options:
37
+ - --main
38
+ - README.rdoc
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: !binary |
60
+ 44K/44K544Kv44Op44Kk44OW44Op44Oq
61
+
62
+ test_files: []
63
+