cross-stub 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.txt +12 -0
- data/README.rdoc +85 -29
- data/Rakefile +8 -1
- data/VERSION +1 -1
- data/cross-stub.gemspec +37 -19
- data/lib/cross-stub.rb +63 -24
- data/lib/cross-stub/arguments.rb +21 -0
- data/lib/cross-stub/arguments/array.rb +16 -0
- data/lib/cross-stub/arguments/hash.rb +17 -0
- data/lib/cross-stub/arguments/proc.rb +73 -0
- data/lib/cross-stub/cache.rb +36 -0
- data/lib/cross-stub/stores.rb +4 -0
- data/lib/cross-stub/stores/base.rb +38 -0
- data/lib/cross-stub/stores/file.rb +39 -0
- data/lib/cross-stub/stores/memcache.rb +40 -0
- data/lib/cross-stub/stores/redis.rb +41 -0
- data/lib/cross-stub/stubber.rb +132 -0
- data/rails_generators/cross_stub/cross_stub_generator.rb +1 -1
- data/rails_generators/cross_stub/templates/config/initializers/cross-stub.rb +9 -1
- data/rails_generators/cross_stub/templates/features/support/cross-stub.rb +16 -2
- data/spec/arguments/proc_spec.rb +689 -0
- data/spec/includes.rb +103 -0
- data/spec/integration/clearing_instance_stubs_spec.rb +119 -0
- data/spec/integration/clearing_stubs_spec.rb +118 -0
- data/spec/integration/creating_instance_stubs_spec.rb +91 -0
- data/spec/integration/creating_stubs_spec.rb +95 -0
- data/spec/integration/shared_spec.rb +35 -0
- data/spec/integration/stubbing_error_spec.rb +69 -0
- data/spec/service.rb +114 -0
- data/spec/spec_helper.rb +1 -41
- metadata +58 -26
- data/lib/cross-stub/cache_helpers.rb +0 -48
- data/lib/cross-stub/pseudo_class.rb +0 -82
- data/lib/cross-stub/setup_helpers.rb +0 -13
- data/lib/cross-stub/stub_helpers.rb +0 -64
- data/spec/cross-stub/clearing_stubs_spec.rb +0 -112
- data/spec/cross-stub/creating_stubs_spec.rb +0 -110
- data/spec/cross-stub/stubbing_error_spec.rb +0 -38
- data/spec/helpers.rb +0 -125
@@ -1,82 +0,0 @@
|
|
1
|
-
module CrossStub
|
2
|
-
|
3
|
-
private
|
4
|
-
|
5
|
-
class PseudoClass
|
6
|
-
|
7
|
-
@@translator ||= lambda do |metaclass, method|
|
8
|
-
@@convertor ||= lambda {|sexp| Ruby2Ruby.new.process(Unifier.new.process(sexp)) }
|
9
|
-
@@convertor[ParseTree.translate(metaclass, method)] rescue nil
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(klass)
|
13
|
-
@klass = get_class(klass)
|
14
|
-
@metaclass = (class << @klass ; self ; end)
|
15
|
-
end
|
16
|
-
|
17
|
-
def get_class(klass)
|
18
|
-
if klass.is_a?(String)
|
19
|
-
klass.split(/::/).inject(Object) { |const_train, const| const_train.const_get(const) }
|
20
|
-
else
|
21
|
-
klass
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def id
|
26
|
-
@klass.to_s
|
27
|
-
end
|
28
|
-
|
29
|
-
def method_code(method)
|
30
|
-
@@translator[@metaclass, method]
|
31
|
-
end
|
32
|
-
|
33
|
-
def replace_method(method, value_or_code)
|
34
|
-
status = backup_method(method)
|
35
|
-
@klass.instance_eval "#{value_or_code}" =~ /^def / ? value_or_code :
|
36
|
-
%\def #{method}; Marshal.load(%|#{Marshal.dump(value_or_code)}|) ; end\
|
37
|
-
status
|
38
|
-
end
|
39
|
-
|
40
|
-
def revert_method(method)
|
41
|
-
new_name = before_stubbing_method_name(method)
|
42
|
-
@metaclass.instance_eval("alias_method :#{method}, :#{new_name}") rescue nil
|
43
|
-
remove_method(new_name)
|
44
|
-
end
|
45
|
-
|
46
|
-
def backup_method(method)
|
47
|
-
if @klass.respond_to?(method)
|
48
|
-
!@klass.respond_to?(new_name = before_stubbing_method_name(method)) &&
|
49
|
-
@metaclass.instance_eval("alias_method :#{new_name}, :#{method}")
|
50
|
-
true
|
51
|
-
else
|
52
|
-
false
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def remove_method(method)
|
57
|
-
@metaclass.send(:remove_method, method) rescue nil
|
58
|
-
end
|
59
|
-
|
60
|
-
def replace_methods(&blk)
|
61
|
-
(tmp = BlankObject.new).__instance_eval__(&blk)
|
62
|
-
methods_in_block = tmp.__methods__ - BlankObject.new.__methods__
|
63
|
-
is_method_implemented_flags = methods_in_block.inject({}) do |memo, method|
|
64
|
-
memo.merge(method => backup_method(method))
|
65
|
-
end
|
66
|
-
@klass.instance_eval(&blk)
|
67
|
-
is_method_implemented_flags
|
68
|
-
end
|
69
|
-
|
70
|
-
def before_stubbing_method_name(method)
|
71
|
-
:"__#{method}_before_xstubbing"
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
class BlankObject
|
77
|
-
alias_method :__instance_eval__, :instance_eval
|
78
|
-
alias_method :__methods__, :methods
|
79
|
-
instance_methods.each {|m| undef_method m unless m =~ /^__.*__$/ }
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
module CrossStub
|
2
|
-
|
3
|
-
private
|
4
|
-
|
5
|
-
module StubHelpers
|
6
|
-
|
7
|
-
def clear_stubs_for_current_process
|
8
|
-
if File.exists?(options[:file])
|
9
|
-
unapply_stubs ; delete_cache
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def apply_stubs_for_current_process(*args, &blk)
|
14
|
-
pk, args = PseudoClass.new(args[0]), args[1]
|
15
|
-
update_cache do |entire_cache|
|
16
|
-
hash = (args[0].is_a?(Hash) ? args[0] : args.inject({}){|h, k| h.merge(k => nil) })
|
17
|
-
cache = entire_cache[pk.id] || {}
|
18
|
-
cache = create_stub_from_hash(pk, cache, hash)
|
19
|
-
cache = create_stub_from_block(pk, cache, &blk) if block_given?
|
20
|
-
entire_cache.merge(pk.id => cache)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def apply_or_unapply_stubs_for_other_process
|
25
|
-
lambda {
|
26
|
-
unapply_stubs(load_backup_cache)
|
27
|
-
load_cache.each do |klass, hash|
|
28
|
-
pk = PseudoClass.new(klass)
|
29
|
-
hash.each {|method, codes| pk.replace_method(method, codes[:after]) }
|
30
|
-
end
|
31
|
-
}[] rescue nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def unapply_stubs(cache=nil)
|
35
|
-
cache ||= load_cache
|
36
|
-
cache.each do |klass, hash|
|
37
|
-
pk = PseudoClass.new(klass)
|
38
|
-
hash.each do |method, codes|
|
39
|
-
codes[:before] ? pk.revert_method(method) : pk.remove_method(method)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def create_stub_from_hash(pk, cache, hash)
|
45
|
-
hash.inject(cache) do |cache, args|
|
46
|
-
method, value = args
|
47
|
-
is_method_implemented = pk.replace_method(method, value)
|
48
|
-
cache[method] ||= {:before => is_method_implemented}
|
49
|
-
cache[method][:after] = pk.method_code(method)
|
50
|
-
cache
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def create_stub_from_block(pk, cache, &blk)
|
55
|
-
pk.replace_methods(&blk).inject(cache) do |cache, args|
|
56
|
-
method, is_method_implemented = args
|
57
|
-
cache[method] ||= {:before => is_method_implemented}
|
58
|
-
cache[method][:after] = pk.method_code(method)
|
59
|
-
cache
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
-
|
3
|
-
describe 'Clearing Stubs' do
|
4
|
-
|
5
|
-
behaves_like 'has standard setup'
|
6
|
-
|
7
|
-
%w{current other}.each do |mode|
|
8
|
-
|
9
|
-
behaves_like "has #{mode} process setup"
|
10
|
-
|
11
|
-
%w{AnyClass AnyClass::Inner AnyModule AnyModule::Inner}.each do |klass_or_module|
|
12
|
-
|
13
|
-
before do
|
14
|
-
@context = @get_context[klass_or_module]
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should clear hash generated stub and return original value for #{klass_or_module} in #{mode} process" do
|
18
|
-
original_value = @context.say_world
|
19
|
-
@context.xstub(:say_world => 'i say world')
|
20
|
-
CrossStub.clear
|
21
|
-
@get_value["#{@context}.say_world"].should.equal original_value
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should clear hash generated stub and raise NoMethodError for #{klass_or_module} in #{mode} process" do
|
25
|
-
should.raise(NoMethodError) do
|
26
|
-
@context.xstub(:say_hello => 'i say hello')
|
27
|
-
CrossStub.clear
|
28
|
-
@get_value["#{@context}.say_hello"]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should clear symbol generated stub and return original value for #{klass_or_module} in #{mode} process" do
|
33
|
-
original_value = @context.say_world
|
34
|
-
@context.xstub(:say_world)
|
35
|
-
CrossStub.clear
|
36
|
-
@get_value["#{@context}.say_world"].should.equal original_value
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should clear symbol generated stub and raise NoMethodError for #{klass_or_module} in #{mode} process" do
|
40
|
-
should.raise(NoMethodError) do
|
41
|
-
@context.xstub(:say_hello)
|
42
|
-
CrossStub.clear
|
43
|
-
@get_value["#{@context}.say_hello"]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should clear block generated stub and return original value for #{klass_or_module} in #{mode} process" do
|
48
|
-
original_value = @context.say_world
|
49
|
-
@context.xstub do
|
50
|
-
def say_world ; 'i say world' ; end
|
51
|
-
end
|
52
|
-
CrossStub.clear
|
53
|
-
@get_value["#{@context}.say_world"].should.equal original_value
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should clear block generated stub and raise NoMethodError for #{klass_or_module} in #{mode} process" do
|
57
|
-
should.raise(NoMethodError) do
|
58
|
-
@context.xstub do
|
59
|
-
def say_hello ; 'i say hello' ; end
|
60
|
-
end
|
61
|
-
CrossStub.clear
|
62
|
-
@get_value["#{@context}.say_hello"]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should always clear previously generated stub for #{klass_or_module} in #{mode} process" do
|
67
|
-
original_value = @context.say_world
|
68
|
-
|
69
|
-
# Stub an existing method
|
70
|
-
@context.xstub(:say_world => 'i say world')
|
71
|
-
@get_value["#{@context}.say_world"]
|
72
|
-
|
73
|
-
# Clear stubs without refreshing another process
|
74
|
-
CrossStub.clear
|
75
|
-
CrossStub.setup(:file => $cache_file)
|
76
|
-
|
77
|
-
# Stub a non-existing method
|
78
|
-
@context.xstub(:say_hello => 'i say hello')
|
79
|
-
@get_value["#{@context}.say_hello"]
|
80
|
-
|
81
|
-
# Make sure existing method returns to original method
|
82
|
-
@get_value["#{@context}.say_world"].should.equal original_value
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should always clear previously generated stub and raise NoMethodError for #{klass_or_module} in #{mode} process" do
|
86
|
-
# Stub a non-existing method
|
87
|
-
@context.xstub(:say_hello => 'i say hello')
|
88
|
-
@get_value["#{@context}.say_hello"]
|
89
|
-
|
90
|
-
# Clear stubs without refreshing another process
|
91
|
-
CrossStub.clear
|
92
|
-
CrossStub.setup(:file => $cache_file)
|
93
|
-
|
94
|
-
# Stub an existing method
|
95
|
-
@context.xstub(:say_world => 'i say world')
|
96
|
-
@get_value["#{@context}.say_world"]
|
97
|
-
|
98
|
-
# Make sure accessing non-existing method throws error
|
99
|
-
should.raise(NoMethodError) { @get_value["#{@context}.say_hello"] }
|
100
|
-
end
|
101
|
-
|
102
|
-
it "should clear for method not implemented in ruby and return original value for #{klass_or_module} in #{mode} process" do
|
103
|
-
Time.xstub(:now => 'abc')
|
104
|
-
CrossStub.clear
|
105
|
-
value = nil
|
106
|
-
should.not.raise(NoMethodError) { value = @get_value['Time.now'] }
|
107
|
-
value.should.not.equal 'abc'
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
-
|
3
|
-
describe 'Creating Stubs' do
|
4
|
-
|
5
|
-
behaves_like 'has standard setup'
|
6
|
-
|
7
|
-
%w{current other}.each do |mode|
|
8
|
-
|
9
|
-
behaves_like "has #{mode} process setup"
|
10
|
-
|
11
|
-
%w{AnyClass AnyClass::Inner AnyModule AnyModule::Inner}.each do |klass_or_module|
|
12
|
-
|
13
|
-
before do
|
14
|
-
@context = @get_context[klass_or_module]
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should create with hash argument(s) for #{klass_or_module} class in #{mode} process" do
|
18
|
-
@context.xstub(:say_hello => 'i say hello', :say_world => 'i say world')
|
19
|
-
@get_value["#{@context}.say_hello"].should.equal 'i say hello'
|
20
|
-
@get_value["#{@context}.say_world"].should.equal 'i say world'
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should create with symbol argument(s) for #{klass_or_module} class in #{mode} process" do
|
24
|
-
@context.xstub(:say_hello)
|
25
|
-
@get_value["#{@context}.say_hello"].should.equal nil
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should create with block with no argument for #{klass_or_module} class in #{mode} process" do
|
29
|
-
@context.xstub do
|
30
|
-
def say_hello ; 'i say hello' ; end
|
31
|
-
end
|
32
|
-
@get_value["#{@context}.say_hello"].should.equal 'i say hello'
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should create with symbol & block with no argument for #{klass_or_module} class in #{mode} process" do
|
36
|
-
@context.xstub(:say_hello) do
|
37
|
-
def say_world
|
38
|
-
'i say world'
|
39
|
-
end
|
40
|
-
end
|
41
|
-
@get_value["#{@context}.say_hello"].should.equal nil
|
42
|
-
@get_value["#{@context}.say_world"].should.equal 'i say world'
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should create with hash & block with no argument for #{klass_or_module} class in #{mode} process" do
|
46
|
-
@context.xstub(:say_hello => 'i say hello') do
|
47
|
-
def say_world
|
48
|
-
'i say world'
|
49
|
-
end
|
50
|
-
end
|
51
|
-
@get_value["#{@context}.say_hello"].should.equal 'i say hello'
|
52
|
-
@get_value["#{@context}.say_world"].should.equal 'i say world'
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should always create the most recent for #{klass_or_module} class in #{mode} process" do
|
56
|
-
found, expected = [], ['i say hello', 'i say something else', 'i say something else again']
|
57
|
-
stub_and_get_value = lambda do |value|
|
58
|
-
@context.xstub(:say_hello => value)
|
59
|
-
@get_value["#{@context}.say_hello"]
|
60
|
-
end
|
61
|
-
|
62
|
-
found << stub_and_get_value[expected[0]]
|
63
|
-
found << stub_and_get_value[expected[1]]
|
64
|
-
|
65
|
-
CrossStub.clear
|
66
|
-
CrossStub.setup(:file => $cache_file)
|
67
|
-
|
68
|
-
found << stub_and_get_value[expected[2]]
|
69
|
-
found.should.equal expected
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should create stub with dependency on other stub for #{klass_or_module} class in #{mode} process" do
|
73
|
-
@context.xstub(:something => 'hello') do
|
74
|
-
def do_action(who, action)
|
75
|
-
%\#{who} #{action} #{something}\
|
76
|
-
end
|
77
|
-
end
|
78
|
-
@get_value["#{@context}.do_action.i.say"].should.equal 'i say hello'
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should create for method not implemented in ruby for #{klass_or_module} class in #{mode} process" do
|
82
|
-
now = Time.now - 365*60*60*24
|
83
|
-
Time.xstub(:now => now)
|
84
|
-
@get_value['Time.now'].should.equal now
|
85
|
-
end
|
86
|
-
|
87
|
-
# it "should create with block that takes argument(s) for #{mode} process" do
|
88
|
-
# # a, b = 1, 2
|
89
|
-
# # AnyClass.xstub do |a, b|
|
90
|
-
# # def say_hello
|
91
|
-
# # "i say #{a+b} hellos"
|
92
|
-
# # end
|
93
|
-
# # end
|
94
|
-
# # AnyClass.say_hello.should.equal 'i say 3 hellos'
|
95
|
-
# end
|
96
|
-
#
|
97
|
-
# it "should create with hash & block that takes argument(s) for #{mode} process" do
|
98
|
-
# # a, b = 1, 2
|
99
|
-
# # AnyClass.xstub(:say_world => 'i say world') do |a, b|
|
100
|
-
# # def say_hello
|
101
|
-
# # "i say #{a+b} hellos"
|
102
|
-
# # end
|
103
|
-
# # end
|
104
|
-
# # AnyClass.say_hello.should.equal 'i say 3 hellos'
|
105
|
-
# # AnyClass.say_world.should.equal 'i say world'
|
106
|
-
# end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
-
|
3
|
-
describe 'Stubbing Error' do
|
4
|
-
|
5
|
-
behaves_like 'has standard setup'
|
6
|
-
|
7
|
-
it 'should not be raised when stubbing module' do
|
8
|
-
should.not.raise(CrossStub::Error) {
|
9
|
-
AnyModule.xstub(:say_hello => 'i say hello')
|
10
|
-
}
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should not be raised when stubbing class' do
|
14
|
-
should.not.raise(CrossStub::Error) {
|
15
|
-
AnyClass.xstub(:say_hello => 'i say hello')
|
16
|
-
}
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'should not be raised when stubbing nested class' do
|
20
|
-
should.not.raise(CrossStub::Error) {
|
21
|
-
AnyClass::Inner.xstub(:say_hello => 'i say hello')
|
22
|
-
}
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should not be raised when stubbing nested module' do
|
26
|
-
should.not.raise(CrossStub::Error) {
|
27
|
-
AnyModule::Inner.xstub(:say_hello => 'i say hello')
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should be raised when stubbing instance' do
|
32
|
-
should.raise(CrossStub::CannotStubInstanceError) do
|
33
|
-
o = AnyClass.new
|
34
|
-
o.xstub(:say_hello => 'i say hello')
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
data/spec/helpers.rb
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'eventmachine'
|
3
|
-
|
4
|
-
$cache_file = File.join(File.dirname(__FILE__), '..', 'tmp', 'stubbing.cache')
|
5
|
-
$log_file = File.join(File.dirname(__FILE__), '..', 'tmp', 'echoserver.log')
|
6
|
-
$sleep_time = 1.5 # may need to increase this depending on ur machine's prowess
|
7
|
-
|
8
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
|
-
require 'cross-stub'
|
10
|
-
|
11
|
-
class AnyClass
|
12
|
-
def self.say_world
|
13
|
-
'u say world'
|
14
|
-
end
|
15
|
-
class Inner
|
16
|
-
def self.say_world
|
17
|
-
'u say world'
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
module AnyModule
|
23
|
-
def self.say_world
|
24
|
-
'u say world'
|
25
|
-
end
|
26
|
-
module Inner
|
27
|
-
def self.say_world
|
28
|
-
'u say world'
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
module EchoClient
|
34
|
-
|
35
|
-
class << self
|
36
|
-
|
37
|
-
attr_accessor :result
|
38
|
-
|
39
|
-
def get(klass_and_method)
|
40
|
-
address, port = EchoServer::ADDRESS, EchoServer::PORT
|
41
|
-
EventMachine::run do
|
42
|
-
(EventMachine::connect(address, port, EM)).
|
43
|
-
execute(klass_and_method) {|data| self.result = Marshal.load(data) }
|
44
|
-
end
|
45
|
-
self.result
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
module EM
|
53
|
-
def receive_data(data)
|
54
|
-
@callback[data]
|
55
|
-
EventMachine::stop_event_loop
|
56
|
-
end
|
57
|
-
def execute(method, &blk)
|
58
|
-
@callback = blk
|
59
|
-
send_data method
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
module EchoServer
|
66
|
-
|
67
|
-
ADDRESS, PORT = '127.0.0.1', 8081
|
68
|
-
|
69
|
-
class << self
|
70
|
-
|
71
|
-
def pid
|
72
|
-
@process.pid
|
73
|
-
end
|
74
|
-
|
75
|
-
def start(other_process=false)
|
76
|
-
unless other_process
|
77
|
-
@process = IO.popen("ruby #{__FILE__}")
|
78
|
-
sleep $sleep_time
|
79
|
-
else
|
80
|
-
EventMachine::run { EventMachine::start_server(ADDRESS, PORT, EM) }
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def stop
|
85
|
-
Process.kill('SIGHUP', pid)
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
module EM
|
93
|
-
def receive_data(klass_and_method)
|
94
|
-
log "(1) EchoServer::EM#receive_data ... receives: #{klass_and_method}"
|
95
|
-
CrossStub.refresh(:file => $cache_file)
|
96
|
-
log "(2) EchoServer::EM#receive_data ... completes stubs refresh"
|
97
|
-
klass, method, *args = klass_and_method.split('.')
|
98
|
-
konst = klass.split(/::/).inject(Object) { |const_train, const| const_train.const_get(const) }
|
99
|
-
log "(3) EchoServer::EM#receive_data ... parses arguments to:",
|
100
|
-
" * klass ... #{klass}",
|
101
|
-
" * method ... #{method}",
|
102
|
-
" * args ... #{args.inspect}"
|
103
|
-
value = args.empty? ? konst.send(method) :
|
104
|
-
konst.send(method, *args) rescue $!.message
|
105
|
-
log "(4) EchoServer::EM#receive_data ... returns: #{value.inspect}"
|
106
|
-
send_data(Marshal.dump(value))
|
107
|
-
log "(5) EchoServer::EM#receive_data ... end"
|
108
|
-
end
|
109
|
-
|
110
|
-
def log(*msg)
|
111
|
-
$logger << [msg, ""].flatten.join("\n")
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
if $0 == __FILE__
|
118
|
-
begin
|
119
|
-
require 'logger'
|
120
|
-
$logger = Logger.new($log_file)
|
121
|
-
EchoServer.start(true)
|
122
|
-
ensure
|
123
|
-
$logger.close
|
124
|
-
end
|
125
|
-
end
|