otaku 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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]
@@ -56,6 +56,7 @@ Otaku ships with the following defaults:
56
56
  Otaku.port # >> 10999
57
57
  Otaku.init_wait_time # >> 2
58
58
  Otaku.log_file # >> '/tmp/otaku.log'
59
+ Otaku.ruby # >> 'ruby' # (the current in-use ruby)
59
60
 
60
61
  Configuring can be done via:
61
62
 
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 server/client service built using eventmachine}
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
- # TODO: Should eventually remove requirement for ParseTree !!
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
1
+ 0.2.0
@@ -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
- # TODO: Preliminary try, should be removed eventually !! Should use RubyParser instead.
8
- require 'parse_tree'
9
- require 'parse_tree_extensions'
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])
@@ -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,15 @@
1
+ module Otaku
2
+ module Encoder
3
+ class << self
4
+
5
+ def encode(thing)
6
+ Base64.encode64(Marshal.dump(thing))
7
+ end
8
+
9
+ def decode(thing)
10
+ Marshal.load(Base64.decode64(thing))
11
+ end
12
+
13
+ end
14
+ end
15
+ 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
@@ -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
@@ -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: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.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 00:00:00 +08:00
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: ParseTree
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: 13
75
+ hash: 7
76
76
  segments:
77
- - 3
77
+ - 2
78
78
  - 0
79
- - 5
80
- version: 3.0.5
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
- - spec/processing_spec.rb
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 server/client service built using eventmachine
142
+ summary: Dead simple service framework built on eventmachine
137
143
  test_files:
138
- - spec/processing_spec.rb
144
+ - spec/integration_spec.rb
145
+ - spec/handler_spec.rb
139
146
  - spec/spec_helper.rb
@@ -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