otaku 0.1.0 → 0.2.0
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/HISTORY.txt +15 -0
- data/README.rdoc +1 -0
- data/Rakefile +2 -3
- data/VERSION +1 -1
- data/lib/otaku.rb +8 -169
- data/lib/otaku/client.rb +34 -0
- data/lib/otaku/encoder.rb +15 -0
- data/lib/otaku/handler.rb +101 -0
- data/lib/otaku/server.rb +72 -0
- data/otaku.gemspec +70 -0
- data/spec/handler_spec.rb +228 -0
- data/spec/integration_spec.rb +52 -0
- metadata +19 -12
- data/spec/processing_spec.rb +0 -30
data/HISTORY.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
=== 0.2.0 2010-07-19
|
2
|
+
|
3
|
+
= Features
|
4
|
+
* it is now possible to specify which ruby to run the server in [#ngty]
|
5
|
+
* officially support MRI-1.8.7, MRI-1.9.1, JRUBY-1.5.1 & REE-1.8.7 [#ngty]
|
6
|
+
|
7
|
+
= Maintenance
|
8
|
+
* split single file into separate files for readability [#ngty]
|
9
|
+
* use RubyParser instead of ParseTree [#ngty]
|
10
|
+
|
11
|
+
= Issues
|
12
|
+
* magic variable __FILE__ works as expected, but not __LINE__, in fact, __LINE__ reflects the
|
13
|
+
line no starting from the line where the source code is extracted from (not sure if we wanna
|
14
|
+
fix this problem though, unless someone explicitely ask for it)
|
15
|
+
|
1
16
|
=== 0.1.0 2010-07-18
|
2
17
|
|
3
18
|
first gem release! [#ngty]
|
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "otaku"
|
8
|
-
gem.summary = %Q{Dead simple
|
8
|
+
gem.summary = %Q{Dead simple service framework built on eventmachine}
|
9
9
|
gem.description = %Q{}
|
10
10
|
gem.email = "ngty77@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/ngty/otaku"
|
@@ -13,8 +13,7 @@ begin
|
|
13
13
|
gem.add_development_dependency "bacon", ">= 0"
|
14
14
|
gem.add_dependency "eventmachine", ">= 0.12.10"
|
15
15
|
gem.add_dependency "ruby2ruby", ">= 1.2.4"
|
16
|
-
|
17
|
-
gem.add_dependency "ParseTree", ">= 3.0.5"
|
16
|
+
gem.add_dependency "ruby_parser", ">= 2.0.4"
|
18
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
19
18
|
end
|
20
19
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/otaku.rb
CHANGED
@@ -3,25 +3,25 @@ require 'eventmachine'
|
|
3
3
|
require 'logger'
|
4
4
|
require 'base64'
|
5
5
|
require 'ruby2ruby'
|
6
|
+
require 'ruby_parser'
|
6
7
|
|
7
|
-
|
8
|
-
require '
|
9
|
-
require '
|
8
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
9
|
+
require 'otaku/encoder'
|
10
|
+
require 'otaku/handler'
|
11
|
+
require 'otaku/server'
|
12
|
+
require 'otaku/client'
|
10
13
|
|
11
14
|
module Otaku
|
12
15
|
|
13
16
|
class HandlerNotDefinedError < Exception ; end
|
14
17
|
class DataProcessError < Exception ; end
|
15
18
|
|
16
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
17
|
-
# Otaku
|
18
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
19
|
-
|
20
19
|
DEFAULTS = {
|
20
|
+
:ruby => 'ruby',
|
21
21
|
:address => '127.0.0.1',
|
22
22
|
:port => 10999,
|
23
23
|
:log_file => '/tmp/otaku.log',
|
24
|
-
:init_wait_time => 2
|
24
|
+
:init_wait_time => 2 * (RUBY_PLATFORM =~ /java/i ? 3 : 1)
|
25
25
|
}
|
26
26
|
|
27
27
|
class << self
|
@@ -57,167 +57,6 @@ module Otaku
|
|
57
57
|
|
58
58
|
end
|
59
59
|
|
60
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
61
|
-
# Otaku::Encoder
|
62
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
63
|
-
|
64
|
-
module Encoder
|
65
|
-
class << self
|
66
|
-
|
67
|
-
def encode(thing)
|
68
|
-
Base64.encode64(Marshal.dump(thing))
|
69
|
-
end
|
70
|
-
|
71
|
-
def decode(thing)
|
72
|
-
Marshal.load(Base64.decode64(thing))
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
79
|
-
# Otaku::Handler
|
80
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
81
|
-
|
82
|
-
class Handler
|
83
|
-
|
84
|
-
def initialize(context, handler)
|
85
|
-
@context = __context_as_code__(context)
|
86
|
-
@proc = __proc_as_code__(handler)
|
87
|
-
end
|
88
|
-
|
89
|
-
def [](data)
|
90
|
-
eval(@context).instance_exec(data, &eval(@proc))
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def __proc_as_code__(block)
|
96
|
-
Ruby2Ruby.new.process(block.to_sexp)
|
97
|
-
end
|
98
|
-
|
99
|
-
def __context_as_code__(methods_hash)
|
100
|
-
'Class.new{ %s }.new' %
|
101
|
-
methods_hash.map do |method, val|
|
102
|
-
"def #{method}; Encoder.decode(%|#{Encoder.encode(val).gsub('|','\|')}|); end"
|
103
|
-
end.join('; ')
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
109
|
-
# Otaku::Server
|
110
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
111
|
-
|
112
|
-
module Server
|
113
|
-
|
114
|
-
class << self
|
115
|
-
|
116
|
-
attr_accessor :handler
|
117
|
-
|
118
|
-
def start(other_process=false)
|
119
|
-
other_process ? run_evented_server : (
|
120
|
-
# print '[Otaku] initializing at %s:%s ... ' % [Otaku.address, Otaku.port] # DBUG
|
121
|
-
run_server_script
|
122
|
-
# puts 'done [pid#%s]' % @process.pid # DEBUG
|
123
|
-
)
|
124
|
-
end
|
125
|
-
|
126
|
-
def run_evented_server
|
127
|
-
log 'started with pid #%s' % Process.pid,
|
128
|
-
'listening at %s:%s' % [Otaku.address, Otaku.port]
|
129
|
-
EventMachine::run { EventMachine::start_server(Otaku.address, Otaku.port, EM) }
|
130
|
-
end
|
131
|
-
|
132
|
-
def run_server_script
|
133
|
-
args = Encoder.encode({
|
134
|
-
:config => Otaku.config,
|
135
|
-
:handler => @handler
|
136
|
-
})
|
137
|
-
@process = IO.popen(%|ruby #{__FILE__} "#{args.gsub('"','\"')}"|,'r')
|
138
|
-
sleep Otaku.init_wait_time
|
139
|
-
end
|
140
|
-
|
141
|
-
def stop
|
142
|
-
Process.kill('SIGHUP', @process.pid) if @process
|
143
|
-
end
|
144
|
-
|
145
|
-
def log(*msgs)
|
146
|
-
@logger ||= Logger.new(Otaku.log_file)
|
147
|
-
msgs.each{|msg| @logger << "[Otaku] %s\n" % msg }
|
148
|
-
end
|
149
|
-
|
150
|
-
def cleanup
|
151
|
-
@logger.close
|
152
|
-
end
|
153
|
-
|
154
|
-
end
|
155
|
-
|
156
|
-
private
|
157
|
-
|
158
|
-
module EM #:nodoc:
|
159
|
-
|
160
|
-
def receive_data(data)
|
161
|
-
log 'receives data: %s' % data.inspect
|
162
|
-
result = process_data(data)
|
163
|
-
log 'returning result: %s' % result.inspect
|
164
|
-
send_data(Encoder.encode(result))
|
165
|
-
end
|
166
|
-
|
167
|
-
def process_data(data)
|
168
|
-
begin
|
169
|
-
Server.handler[data]
|
170
|
-
rescue
|
171
|
-
error = DataProcessError.new($!.inspect)
|
172
|
-
log(error.inspect)
|
173
|
-
error
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def log(*msg)
|
178
|
-
Server.log(*msg)
|
179
|
-
end
|
180
|
-
|
181
|
-
end
|
182
|
-
|
183
|
-
end
|
184
|
-
|
185
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
186
|
-
# Otaku::Client
|
187
|
-
# //////////////////////////////////////////////////////////////////////////////////////////
|
188
|
-
|
189
|
-
module Client
|
190
|
-
|
191
|
-
class << self
|
192
|
-
def get(data)
|
193
|
-
EventMachine::run do
|
194
|
-
EventMachine::connect(Otaku.address, Otaku.port, EM).
|
195
|
-
execute(data) do |data|
|
196
|
-
@result = Encoder.decode(data)
|
197
|
-
end
|
198
|
-
end
|
199
|
-
@result
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
private
|
204
|
-
|
205
|
-
module EM #:nodoc:
|
206
|
-
|
207
|
-
def receive_data(data)
|
208
|
-
result = @callback.call(data)
|
209
|
-
result.is_a?(DataProcessError) ? raise(result) : result
|
210
|
-
EventMachine::stop_event_loop # ends loop & resumes program flow
|
211
|
-
end
|
212
|
-
|
213
|
-
def execute(method, &callback)
|
214
|
-
@callback = callback
|
215
|
-
send_data(method)
|
216
|
-
end
|
217
|
-
|
218
|
-
end
|
219
|
-
|
220
|
-
end
|
221
60
|
end
|
222
61
|
|
223
62
|
if $0 == __FILE__ && (encoded_data = ARGV[0])
|
data/lib/otaku/client.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Otaku
|
2
|
+
module Client
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def get(data)
|
6
|
+
EventMachine::run do
|
7
|
+
EventMachine::connect(Otaku.address, Otaku.port, EM).
|
8
|
+
execute(data) do |data|
|
9
|
+
@result = Encoder.decode(data)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
@result
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
module EM #:nodoc:
|
19
|
+
|
20
|
+
def receive_data(data)
|
21
|
+
result = @callback.call(data)
|
22
|
+
result.is_a?(DataProcessError) ? raise(result) : result
|
23
|
+
EventMachine::stop_event_loop # ends loop & resumes program flow
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute(method, &callback)
|
27
|
+
@callback = callback
|
28
|
+
send_data(method)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Otaku
|
2
|
+
class Handler
|
3
|
+
|
4
|
+
def initialize(context, handler)
|
5
|
+
@context = __context_as_code__(context)
|
6
|
+
@proc = __proc_as_code__(handler)
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](data)
|
10
|
+
eval(@context).instance_exec(data, &eval(@proc))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def __context_as_code__(methods_hash)
|
16
|
+
'Class.new{ %s }.new' %
|
17
|
+
methods_hash.map do |method, val|
|
18
|
+
"def #{method}; Encoder.decode(%|#{Encoder.encode(val).gsub('|','\|')}|); end"
|
19
|
+
end.sort.join('; ')
|
20
|
+
end
|
21
|
+
|
22
|
+
def __proc_as_code__(block)
|
23
|
+
MagicProc.new(block).to_code
|
24
|
+
end
|
25
|
+
|
26
|
+
class MagicProc
|
27
|
+
|
28
|
+
RUBY_PARSER = RubyParser.new
|
29
|
+
RUBY_2_RUBY = Ruby2Ruby.new
|
30
|
+
|
31
|
+
def initialize(block)
|
32
|
+
@block = block
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_code
|
36
|
+
code, remaining = code_fragments
|
37
|
+
|
38
|
+
while frag = remaining[frag_regexp,1]
|
39
|
+
begin
|
40
|
+
sexp = RUBY_PARSER.parse(code += frag, File.expand_path(@file))
|
41
|
+
return RUBY_2_RUBY.process(sexp) if sexp.inspect =~ sexp_regexp
|
42
|
+
rescue SyntaxError, Racc::ParseError, NoMethodError
|
43
|
+
remaining.sub!(frag,'')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def code_fragments
|
49
|
+
ignore, start_marker, arg =
|
50
|
+
[:ignore, :start_marker, :arg].map{|key| code_match_args[key] }
|
51
|
+
[
|
52
|
+
"proc #{start_marker} |#{arg}| ",
|
53
|
+
source_code.sub(ignore, '')
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
def sexp_regexp
|
58
|
+
@sexp_regexp ||= (
|
59
|
+
Regexp.new([
|
60
|
+
Regexp.quote("s(:iter, s(:call, nil, :"),
|
61
|
+
"(proc|lambda)",
|
62
|
+
Regexp.quote(", s(:arglist)), s(:lasgn, :#{code_match_args[:arg]}), s("),
|
63
|
+
].join)
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def frag_regexp
|
68
|
+
@frag_regexp ||= (
|
69
|
+
end_marker = {'do' => 'end', '{' => '\}'}[code_match_args[:start_marker]]
|
70
|
+
/^(.*?\W#{end_marker})/m
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def code_regexp
|
75
|
+
@code_regexp ||=
|
76
|
+
/^(.*?(Otaku\.start.*?|lambda|proc|Proc\.new)\s*(do|\{)\s*\|(\w+)\|\s*)/m
|
77
|
+
end
|
78
|
+
|
79
|
+
def code_match_args
|
80
|
+
@code_match_args ||= (
|
81
|
+
args = source_code.match(code_regexp)
|
82
|
+
{
|
83
|
+
:ignore => args[1],
|
84
|
+
:start_marker => args[3],
|
85
|
+
:arg => args[4]
|
86
|
+
}
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def source_code
|
91
|
+
@source_code ||= (
|
92
|
+
@file, line_no = /^#<Proc:0x[0-9A-Fa-f]+@(.+):(\d+).*?>$/.match(@block.inspect)[1..2]
|
93
|
+
@line_no = line_no.to_i
|
94
|
+
File.readlines(@file)[@line_no.pred .. -1].join
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
data/lib/otaku/server.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Otaku
|
2
|
+
module Server
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
attr_accessor :handler
|
7
|
+
|
8
|
+
def start(other_process=false)
|
9
|
+
other_process ? run_evented_server : (
|
10
|
+
# print '[Otaku] initializing at %s:%s ... ' % [Otaku.address, Otaku.port] # DEBUG
|
11
|
+
run_server_script
|
12
|
+
# puts 'done [pid#%s]' % @process.pid # DEBUG
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_evented_server
|
17
|
+
log 'started with pid #%s' % Process.pid,
|
18
|
+
'listening at %s:%s' % [Otaku.address, Otaku.port]
|
19
|
+
EventMachine::run { EventMachine::start_server(Otaku.address, Otaku.port, EM) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def run_server_script
|
23
|
+
script = File.join(File.dirname(__FILE__), '..', 'otaku.rb')
|
24
|
+
args = Encoder.encode(:config => Otaku.config, :handler => @handler)
|
25
|
+
@process = IO.popen(%|#{Otaku.ruby} #{script} "#{args.gsub('"','\"')}"|,'r')
|
26
|
+
sleep Otaku.init_wait_time
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop
|
30
|
+
Process.kill('SIGHUP', @process.pid) if @process
|
31
|
+
end
|
32
|
+
|
33
|
+
def log(*msgs)
|
34
|
+
@logger ||= Logger.new(Otaku.log_file)
|
35
|
+
msgs.each{|msg| @logger << "[Otaku] %s\n" % msg }
|
36
|
+
end
|
37
|
+
|
38
|
+
def cleanup
|
39
|
+
@logger.close
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
module EM #:nodoc:
|
47
|
+
|
48
|
+
def receive_data(data)
|
49
|
+
log 'receives data: %s' % data.inspect
|
50
|
+
result = process_data(data)
|
51
|
+
log 'returning result: %s' % result.inspect
|
52
|
+
send_data(Encoder.encode(result))
|
53
|
+
end
|
54
|
+
|
55
|
+
def process_data(data)
|
56
|
+
begin
|
57
|
+
Server.handler[data]
|
58
|
+
rescue
|
59
|
+
error = DataProcessError.new($!.inspect)
|
60
|
+
log(error.inspect)
|
61
|
+
error
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def log(*msg)
|
66
|
+
Server.log(*msg)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/otaku.gemspec
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{otaku}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["NgTzeYang"]
|
12
|
+
s.date = %q{2010-07-19}
|
13
|
+
s.description = %q{}
|
14
|
+
s.email = %q{ngty77@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"HISTORY.txt",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/otaku.rb",
|
28
|
+
"lib/otaku/client.rb",
|
29
|
+
"lib/otaku/encoder.rb",
|
30
|
+
"lib/otaku/handler.rb",
|
31
|
+
"lib/otaku/server.rb",
|
32
|
+
"otaku.gemspec",
|
33
|
+
"spec/handler_spec.rb",
|
34
|
+
"spec/integration_spec.rb",
|
35
|
+
"spec/spec_helper.rb"
|
36
|
+
]
|
37
|
+
s.homepage = %q{http://github.com/ngty/otaku}
|
38
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = %q{1.3.7}
|
41
|
+
s.summary = %q{Dead simple service framework built on eventmachine}
|
42
|
+
s.test_files = [
|
43
|
+
"spec/integration_spec.rb",
|
44
|
+
"spec/handler_spec.rb",
|
45
|
+
"spec/spec_helper.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_development_dependency(%q<bacon>, [">= 0"])
|
54
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
|
55
|
+
s.add_runtime_dependency(%q<ruby2ruby>, [">= 1.2.4"])
|
56
|
+
s.add_runtime_dependency(%q<ruby_parser>, [">= 2.0.4"])
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<bacon>, [">= 0"])
|
59
|
+
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
60
|
+
s.add_dependency(%q<ruby2ruby>, [">= 1.2.4"])
|
61
|
+
s.add_dependency(%q<ruby_parser>, [">= 2.0.4"])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<bacon>, [">= 0"])
|
65
|
+
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
66
|
+
s.add_dependency(%q<ruby2ruby>, [">= 1.2.4"])
|
67
|
+
s.add_dependency(%q<ruby_parser>, [">= 2.0.4"])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,228 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
Otaku::Handler.class_eval do
|
4
|
+
attr_reader :context, :proc
|
5
|
+
end
|
6
|
+
|
7
|
+
Otaku.instance_eval do
|
8
|
+
def start(context = {}, &block)
|
9
|
+
Otaku::Handler.new({}, block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Otaku Service Handler" do
|
14
|
+
|
15
|
+
describe '>> initializing context' do
|
16
|
+
|
17
|
+
should 'assign to empty anoynmous class instance code when given {}' do
|
18
|
+
Otaku::Handler.new({}, lambda{}).context.should.equal('Class.new{ }.new')
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'assign to non-empty anoynmous class instance code when given {:m1 => v1, :m2 => v2, ...}' do
|
22
|
+
encode = lambda{|val| Otaku::Encoder.encode(val).gsub('|','\|') }
|
23
|
+
Otaku::Handler.new({:m1 => 'v|1', :m2 => 'v|2'}, lambda{}).context.should.equal(
|
24
|
+
'Class.new{ %s; %s }.new' % [
|
25
|
+
"def m1; Encoder.decode(%|#{encode['v|1']}|); end",
|
26
|
+
"def m2; Encoder.decode(%|#{encode['v|2']}|); end"
|
27
|
+
])
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '>> initializing proc' do
|
33
|
+
|
34
|
+
expected = "proc { |watever| [\"a\", \"b\"].map { |x| puts(x) } }"
|
35
|
+
|
36
|
+
{
|
37
|
+
# ////////////////////////////////////////////////////////////////////////
|
38
|
+
# >> Always newlinling
|
39
|
+
# ////////////////////////////////////////////////////////////////////////
|
40
|
+
__LINE__ => (
|
41
|
+
lambda do |watever|
|
42
|
+
%w{a b}.map do |x|
|
43
|
+
puts x
|
44
|
+
end
|
45
|
+
end
|
46
|
+
),
|
47
|
+
__LINE__ => (
|
48
|
+
lambda { |watever|
|
49
|
+
%w{a b}.map{|x|
|
50
|
+
puts x
|
51
|
+
}
|
52
|
+
}
|
53
|
+
),
|
54
|
+
__LINE__ => (
|
55
|
+
proc do |watever|
|
56
|
+
%w{a b}.map do |x|
|
57
|
+
puts x
|
58
|
+
end
|
59
|
+
end
|
60
|
+
),
|
61
|
+
__LINE__ => (
|
62
|
+
proc { |watever|
|
63
|
+
%w{a b}.map{|x|
|
64
|
+
puts x
|
65
|
+
}
|
66
|
+
}
|
67
|
+
),
|
68
|
+
__LINE__ => (
|
69
|
+
Proc.new do |watever|
|
70
|
+
%w{a b}.map do |x|
|
71
|
+
puts x
|
72
|
+
end
|
73
|
+
end
|
74
|
+
),
|
75
|
+
__LINE__ => (
|
76
|
+
Proc.new { |watever|
|
77
|
+
%w{a b}.map{|x|
|
78
|
+
puts x
|
79
|
+
}
|
80
|
+
}
|
81
|
+
),
|
82
|
+
# ////////////////////////////////////////////////////////////////////////
|
83
|
+
# >> Partial newlining
|
84
|
+
# ////////////////////////////////////////////////////////////////////////
|
85
|
+
__LINE__ => (
|
86
|
+
lambda do |watever|
|
87
|
+
%w{a b}.map do |x| puts x end
|
88
|
+
end
|
89
|
+
),
|
90
|
+
__LINE__ => (
|
91
|
+
lambda { |watever|
|
92
|
+
%w{a b}.map{|x| puts x }
|
93
|
+
}
|
94
|
+
),
|
95
|
+
__LINE__ => (
|
96
|
+
proc do |watever|
|
97
|
+
%w{a b}.map do |x| puts x end
|
98
|
+
end
|
99
|
+
),
|
100
|
+
__LINE__ => (
|
101
|
+
proc { |watever|
|
102
|
+
%w{a b}.map{|x| puts x }
|
103
|
+
}
|
104
|
+
),
|
105
|
+
__LINE__ => (
|
106
|
+
Proc.new do |watever|
|
107
|
+
%w{a b}.map do |x| puts x end
|
108
|
+
end
|
109
|
+
),
|
110
|
+
__LINE__ => (
|
111
|
+
Proc.new { |watever|
|
112
|
+
%w{a b}.map{|x| puts x }
|
113
|
+
}
|
114
|
+
),
|
115
|
+
# ////////////////////////////////////////////////////////////////////////
|
116
|
+
# >> No newlining
|
117
|
+
# ////////////////////////////////////////////////////////////////////////
|
118
|
+
__LINE__ => (
|
119
|
+
lambda do |watever| %w{a b}.map do |x| puts x end end
|
120
|
+
),
|
121
|
+
__LINE__ => (
|
122
|
+
lambda { |watever| %w{a b}.map{|x| puts x } }
|
123
|
+
),
|
124
|
+
__LINE__ => (
|
125
|
+
proc do |watever| %w{a b}.map do |x| puts x end end
|
126
|
+
),
|
127
|
+
__LINE__ => (
|
128
|
+
proc { |watever| %w{a b}.map{|x| puts x } }
|
129
|
+
),
|
130
|
+
__LINE__ => (
|
131
|
+
Proc.new do |watever| %w{a b}.map do |x| puts x end end
|
132
|
+
),
|
133
|
+
__LINE__ => (
|
134
|
+
Proc.new { |watever| %w{a b}.map{|x| puts x } }
|
135
|
+
),
|
136
|
+
}.each do |debug, block|
|
137
|
+
should "handle proc as variable [##{debug}]" do
|
138
|
+
Otaku::Handler.new({}, block).proc.should.equal(expected)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
should "handle block using do ... end [##{__LINE__}]" do
|
143
|
+
Otaku.start({}) do |watever|
|
144
|
+
%w{a b}.map do |x|
|
145
|
+
puts x
|
146
|
+
end
|
147
|
+
end.proc.should.equal(expected)
|
148
|
+
end
|
149
|
+
|
150
|
+
should "handle block using do ... end [##{__LINE__}]" do
|
151
|
+
Otaku.start do |watever|
|
152
|
+
%w{a b}.map do |x|
|
153
|
+
puts x
|
154
|
+
end
|
155
|
+
end.proc.should.equal(expected)
|
156
|
+
end
|
157
|
+
|
158
|
+
should "handle block using do ... end [##{__LINE__}]" do
|
159
|
+
Otaku.start({}) do |watever|
|
160
|
+
%w{a b}.map do |x| puts x end
|
161
|
+
end.proc.should.equal(expected)
|
162
|
+
end
|
163
|
+
|
164
|
+
should "handle block using do ... end [##{__LINE__}]" do
|
165
|
+
Otaku.start do |watever|
|
166
|
+
%w{a b}.map do |x| puts x end
|
167
|
+
end.proc.should.equal(expected)
|
168
|
+
end
|
169
|
+
|
170
|
+
should "handle block using do ... end [##{__LINE__}]" do
|
171
|
+
Otaku.start({}) do |watever| %w{a b}.map do |x| puts x end end.
|
172
|
+
proc.should.equal(expected)
|
173
|
+
end
|
174
|
+
|
175
|
+
should "handle block using do ... end [##{__LINE__}]" do
|
176
|
+
Otaku.start do |watever| %w{a b}.map do |x| puts x end end.
|
177
|
+
proc.should.equal(expected)
|
178
|
+
end
|
179
|
+
|
180
|
+
should "handle block using { ... } [##{__LINE__}]" do
|
181
|
+
Otaku.start({}) { |watever|
|
182
|
+
%w{a b}.map do |x|
|
183
|
+
puts x
|
184
|
+
end
|
185
|
+
}.proc.should.equal(expected)
|
186
|
+
end
|
187
|
+
|
188
|
+
should "handle block using { ... } [##{__LINE__}]" do
|
189
|
+
Otaku.start { |watever|
|
190
|
+
%w{a b}.map do |x|
|
191
|
+
puts x
|
192
|
+
end
|
193
|
+
}.proc.should.equal(expected)
|
194
|
+
end
|
195
|
+
|
196
|
+
should "handle block using { ... } [##{__LINE__}]" do
|
197
|
+
Otaku.start({}) { |watever|
|
198
|
+
%w{a b}.map { |x| puts x }
|
199
|
+
}.proc.should.equal(expected)
|
200
|
+
end
|
201
|
+
|
202
|
+
should "handle block using { ... } [##{__LINE__}]" do
|
203
|
+
Otaku.start { |watever|
|
204
|
+
%w{a b}.map { |x| puts x }
|
205
|
+
}.proc.should.equal(expected)
|
206
|
+
end
|
207
|
+
|
208
|
+
should "handle block using { ... } [##{__LINE__}]" do
|
209
|
+
Otaku.start({}) { |watever| %w{a b}.map { |x| puts x } }.proc.should.equal(expected)
|
210
|
+
end
|
211
|
+
|
212
|
+
should "handle block using { ... } [##{__LINE__}]" do
|
213
|
+
Otaku.start { |watever| %w{a b}.map { |x| puts x } }.proc.should.equal(expected)
|
214
|
+
end
|
215
|
+
|
216
|
+
should "handle __FILE__ correctly [##{__LINE__}]" do
|
217
|
+
Otaku.start { |watever| __FILE__ }.proc.should.
|
218
|
+
equal("proc { |watever| \"%s\" }" % File.expand_path('spec/handler_spec.rb'))
|
219
|
+
end
|
220
|
+
|
221
|
+
should "handle __LINE__ incorrectly [##{__LINE__}]" do
|
222
|
+
Otaku.start { |watever| __LINE__ }.proc.should.
|
223
|
+
equal("proc { |watever| 1 }")
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Otaku Service" do
|
4
|
+
|
5
|
+
describe '>> starting' do
|
6
|
+
|
7
|
+
after do
|
8
|
+
Otaku.stop
|
9
|
+
end
|
10
|
+
|
11
|
+
should 'raise Otaku::HandlerNotDefinedError when processing wo specified proc' do
|
12
|
+
lambda { Otaku.start }.should.raise(Otaku::HandlerNotDefinedError)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '>> processing' do
|
18
|
+
|
19
|
+
after do
|
20
|
+
Otaku.stop
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'succeed w proc that has no contextual reference' do
|
24
|
+
Otaku.start{|data| '~ %s ~' % data }
|
25
|
+
Otaku.process('hello').should.equal '~ hello ~'
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'raise Otaku::DataProcessError w proc that has contextual reference yet has no specified context' do
|
29
|
+
mark = '*'
|
30
|
+
Otaku.start{|data| '%s %s %s' % [mark, data, mark] }
|
31
|
+
lambda { Otaku.process('hello') }.should.raise(Otaku::DataProcessError).
|
32
|
+
message.should.match(/#<NameError: undefined local variable or method `mark' for /)
|
33
|
+
end
|
34
|
+
|
35
|
+
should 'succeed w proc that has contextual reference & has context specified' do
|
36
|
+
Otaku.start(:mark => '*') {|data| '%s %s %s' % [mark, data, mark] }
|
37
|
+
Otaku.process('hello').should.equal('* hello *')
|
38
|
+
end
|
39
|
+
|
40
|
+
should 'reflect __FILE__ as captured when declaring proc' do
|
41
|
+
Otaku.start{|data| __FILE__ }
|
42
|
+
Otaku.process(:watever_data).should.equal(File.expand_path(__FILE__))
|
43
|
+
end
|
44
|
+
|
45
|
+
should 'not reflect __LINE__ as captured when declaring proc' do
|
46
|
+
Otaku.start{|data| __LINE__ }
|
47
|
+
Otaku.process(:watever_data).should.not.equal(__LINE__.pred)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: otaku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- NgTzeYang
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-07-
|
18
|
+
date: 2010-07-19 00:00:00 +08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -65,19 +65,19 @@ dependencies:
|
|
65
65
|
type: :runtime
|
66
66
|
version_requirements: *id003
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
|
-
name:
|
68
|
+
name: ruby_parser
|
69
69
|
prerelease: false
|
70
70
|
requirement: &id004 !ruby/object:Gem::Requirement
|
71
71
|
none: false
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
hash:
|
75
|
+
hash: 7
|
76
76
|
segments:
|
77
|
-
-
|
77
|
+
- 2
|
78
78
|
- 0
|
79
|
-
-
|
80
|
-
version:
|
79
|
+
- 4
|
80
|
+
version: 2.0.4
|
81
81
|
type: :runtime
|
82
82
|
version_requirements: *id004
|
83
83
|
description: ""
|
@@ -98,7 +98,13 @@ files:
|
|
98
98
|
- Rakefile
|
99
99
|
- VERSION
|
100
100
|
- lib/otaku.rb
|
101
|
-
-
|
101
|
+
- lib/otaku/client.rb
|
102
|
+
- lib/otaku/encoder.rb
|
103
|
+
- lib/otaku/handler.rb
|
104
|
+
- lib/otaku/server.rb
|
105
|
+
- otaku.gemspec
|
106
|
+
- spec/handler_spec.rb
|
107
|
+
- spec/integration_spec.rb
|
102
108
|
- spec/spec_helper.rb
|
103
109
|
has_rdoc: true
|
104
110
|
homepage: http://github.com/ngty/otaku
|
@@ -133,7 +139,8 @@ rubyforge_project:
|
|
133
139
|
rubygems_version: 1.3.7
|
134
140
|
signing_key:
|
135
141
|
specification_version: 3
|
136
|
-
summary: Dead simple
|
142
|
+
summary: Dead simple service framework built on eventmachine
|
137
143
|
test_files:
|
138
|
-
- spec/
|
144
|
+
- spec/integration_spec.rb
|
145
|
+
- spec/handler_spec.rb
|
139
146
|
- spec/spec_helper.rb
|
data/spec/processing_spec.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
-
|
3
|
-
describe "Otaku doing processing" do
|
4
|
-
|
5
|
-
after do
|
6
|
-
Otaku.stop
|
7
|
-
end
|
8
|
-
|
9
|
-
should 'succeed when using proc that has no contextual reference' do
|
10
|
-
Otaku.start{|data| '~ %s ~' % data }
|
11
|
-
Otaku.process('hello').should.equal '~ hello ~'
|
12
|
-
end
|
13
|
-
|
14
|
-
should 'fail when using proc that has contextual reference yet has no specified context' do
|
15
|
-
mark = '*'
|
16
|
-
Otaku.start{|data| '%s %s %s' % [mark, data, mark] }
|
17
|
-
lambda { Otaku.process('hello') }.should.raise(Otaku::DataProcessError).
|
18
|
-
message.should.match(/#<NameError: undefined local variable or method `mark' for /)
|
19
|
-
end
|
20
|
-
|
21
|
-
should 'succeed when using proc that has contextual reference & has context specified' do
|
22
|
-
Otaku.start(:mark => '*') {|data| '%s %s %s' % [mark, data, mark] }
|
23
|
-
Otaku.process('hello').should.equal('* hello *')
|
24
|
-
end
|
25
|
-
|
26
|
-
should 'raise Otaku::HandlerNotDefinedError when processing wo specified proc' do
|
27
|
-
lambda { Otaku.start }.should.raise(Otaku::HandlerNotDefinedError)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|