cross-stub 0.1.4 → 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 +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
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'includes')
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'service')
|
4
|
+
|
5
|
+
shared 'has standard setup' do
|
6
|
+
before { CrossStub.setup(cache_store(@store_type)) }
|
7
|
+
after { CrossStub.clear }
|
8
|
+
end
|
9
|
+
|
10
|
+
shared 'has current process setup' do
|
11
|
+
behaves_like 'has standard setup'
|
12
|
+
before { @call = Object.method(:do_local_method_call) }
|
13
|
+
end
|
14
|
+
|
15
|
+
shared 'has other process setup' do
|
16
|
+
|
17
|
+
behaves_like 'has standard setup'
|
18
|
+
|
19
|
+
before do
|
20
|
+
@call = lambda do |klass_and_method_and_args|
|
21
|
+
do_remote_method_call("%s/%s" % [@store_type, klass_and_method_and_args])
|
22
|
+
end
|
23
|
+
$service_started ||= (
|
24
|
+
EchoServer.start if ENV['ECHO_SERVER'] != 'false'
|
25
|
+
true
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
at_exit do
|
32
|
+
$service_started && (
|
33
|
+
EchoServer.stop unless ENV['ECHO_SERVER'] == 'false'
|
34
|
+
)
|
35
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'shared_spec')
|
2
|
+
|
3
|
+
describe 'Stubbing Error' do
|
4
|
+
|
5
|
+
describe ">> xstub (class/module)" do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@store_type = :file
|
9
|
+
end
|
10
|
+
|
11
|
+
behaves_like 'has standard setup'
|
12
|
+
|
13
|
+
should 'not be raised when stubbing module' do
|
14
|
+
lambda { AnyModule.send(:xstub, :bang => 'OOPS') }.
|
15
|
+
should.not.raise(CrossStub::Error)
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'not be raised when stubbing nested module' do
|
19
|
+
lambda { AnyModule::Inner.send(:xstub, :bang => 'OOPS') }.
|
20
|
+
should.not.raise(CrossStub::Error)
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'not be raised when stubbing class' do
|
24
|
+
lambda { AnyClass.send(:xstub, :bang => 'OOPS') }.
|
25
|
+
should.not.raise(CrossStub::Error)
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'not be raised when stubbing nested class' do
|
29
|
+
lambda { AnyClass::Inner.send(:xstub, :bang => 'OOPS') }.
|
30
|
+
should.not.raise(CrossStub::Error)
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'be raised when stubbing instance' do
|
34
|
+
lambda { AnyInstance.new.send(:xstub, :bang => 'OOPS') }.
|
35
|
+
should.raise(CrossStub::CannotStubInstanceError)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe ">> xstub (instance)" do
|
41
|
+
|
42
|
+
should 'not be raised when stubbing class' do
|
43
|
+
lambda { AnyClass.xstub({:bang => 'OOPS'}, :instance => true) }.
|
44
|
+
should.not.raise(CrossStub::Error)
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'not be raised when stubbing nested class' do
|
48
|
+
lambda { AnyClass::Inner.xstub({:bang => 'OOPS'}, :instance => true) }.
|
49
|
+
should.not.raise(CrossStub::Error)
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'be raised when stubbing module' do
|
53
|
+
lambda { AnyModule.xstub({:bang => 'OOPS'}, :instance => true) }.
|
54
|
+
should.raise(CrossStub::ModuleCannotBeInstantiatedError)
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'be raised when stubbing nested module' do
|
58
|
+
lambda { AnyModule::Inner.xstub({:bang => 'OOPS'}, :instance => true) }.
|
59
|
+
should.raise(CrossStub::ModuleCannotBeInstantiatedError)
|
60
|
+
end
|
61
|
+
|
62
|
+
should 'be raised when stubbing instance' do
|
63
|
+
lambda { AnyInstance.new.xstub({:bang => 'OOPS'}, :instance => true) }.
|
64
|
+
should.raise(CrossStub::CannotStubInstanceError)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
data/spec/service.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'eventmachine'
|
3
|
+
require File.join(File.dirname(__FILE__), 'includes')
|
4
|
+
|
5
|
+
module EchoClient
|
6
|
+
|
7
|
+
ADDRESS = ECHO_SERVER_HOST
|
8
|
+
PORT = ECHO_SERVER_PORT
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def get(klass_and_method)
|
12
|
+
EventMachine::run do
|
13
|
+
(EventMachine::connect(ADDRESS, PORT, EM)).
|
14
|
+
execute(klass_and_method){|data| @result = Marshal.load(Base64.decode64(data)) }
|
15
|
+
end
|
16
|
+
@result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
module EM
|
23
|
+
def receive_data(data)
|
24
|
+
@callback.call(data)
|
25
|
+
EventMachine::stop_event_loop
|
26
|
+
end
|
27
|
+
def execute(method, &blk)
|
28
|
+
@callback = blk
|
29
|
+
send_data(method)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
module EchoServer
|
36
|
+
|
37
|
+
ADDRESS = ECHO_SERVER_HOST
|
38
|
+
PORT = ECHO_SERVER_PORT
|
39
|
+
LOG = ECHO_SERVER_LOG
|
40
|
+
WAIT_TIME = ECHO_SERVER_INIT_WAIT_TIME
|
41
|
+
|
42
|
+
class << self
|
43
|
+
|
44
|
+
def log(*msg)
|
45
|
+
(@logger ||= (
|
46
|
+
require 'logger'
|
47
|
+
Logger.new(LOG)
|
48
|
+
)) << [msg, ""].flatten.join("\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
def cleanup
|
52
|
+
@logger.close
|
53
|
+
end
|
54
|
+
|
55
|
+
def start(other_process=false)
|
56
|
+
unless other_process
|
57
|
+
@process = IO.popen("ruby #{__FILE__}",'r')
|
58
|
+
sleep WAIT_TIME
|
59
|
+
else
|
60
|
+
log 'Starting echo service at %s:%s (#%s)' % [ADDRESS, PORT, Process.pid]
|
61
|
+
EventMachine::run { EventMachine::start_server(ADDRESS, PORT, EM) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def stop
|
66
|
+
Process.kill('SIGHUP', @process.pid) if @process
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
module EM
|
74
|
+
|
75
|
+
def receive_data(store_type_and_klass_and_method_and_args)
|
76
|
+
log "\n"
|
77
|
+
log "(1) EchoServer::EM#receive_data ... receives: #{store_type_and_klass_and_method_and_args}"
|
78
|
+
|
79
|
+
store_type, klass_and_method_and_args =
|
80
|
+
store_type_and_klass_and_method_and_args.match(/^(.*?)\/(.*)$/)[1..2]
|
81
|
+
|
82
|
+
CrossStub.refresh(cache_store($prev_store_type)) if $prev_store_type
|
83
|
+
CrossStub.refresh(cache_store($prev_store_type = store_type))
|
84
|
+
log "(2) EchoServer::EM#receive_data ... completes stubs refresh"
|
85
|
+
|
86
|
+
klass, is_instance, method, args = parse_call_args(klass_and_method_and_args)
|
87
|
+
log "(3) EchoServer::EM#receive_data ... parses arguments to:",
|
88
|
+
" * receiver ... #{klass}%s" % (is_instance ? "#new" : nil),
|
89
|
+
" * method ... #{method}",
|
90
|
+
" * args ... #{args.inspect}"
|
91
|
+
value = do_local_method_call(klass_and_method_and_args) rescue $!.message
|
92
|
+
|
93
|
+
log "(4) EchoServer::EM#receive_data ... returns: #{value.inspect}"
|
94
|
+
send_data(Base64.encode64(Marshal.dump(value)))
|
95
|
+
log "(5) EchoServer::EM#receive_data ... end"
|
96
|
+
end
|
97
|
+
|
98
|
+
def log(*msg)
|
99
|
+
EchoServer.log(*msg)
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
if $0 == __FILE__
|
107
|
+
begin
|
108
|
+
EchoServer.start(true)
|
109
|
+
rescue
|
110
|
+
EchoServer.log "#{$!.inspect}\n"
|
111
|
+
ensure
|
112
|
+
EchoServer.cleanup
|
113
|
+
end
|
114
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,45 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bacon'
|
3
|
-
require '
|
4
|
-
|
5
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
-
require 'helpers'
|
3
|
+
require File.join(File.dirname(__FILE__), 'includes')
|
7
4
|
|
8
5
|
Bacon.summary_on_exit
|
9
|
-
|
10
|
-
shared 'has standard setup' do
|
11
|
-
before do
|
12
|
-
CrossStub.setup(:file => $cache_file)
|
13
|
-
@get_context = lambda do |klass_or_module|
|
14
|
-
klass_or_module.split(/::/).inject(Object) { |context, name| context.const_get(name) }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
after do
|
18
|
-
CrossStub.clear
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
shared 'has current process setup' do
|
23
|
-
before do
|
24
|
-
@get_value = lambda do |klass_and_method_and_args|
|
25
|
-
klass, method, *args = klass_and_method_and_args.split('.')
|
26
|
-
konst = klass.split(/::/).inject(Object) { |const_train, const| const_train.const_get(const) }
|
27
|
-
args.empty? ? konst.send(method) :
|
28
|
-
konst.send(method, *args)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
shared 'has other process setup' do
|
34
|
-
before do
|
35
|
-
EchoServer.start unless ENV['ECHO_SERVER'] == 'false'
|
36
|
-
@get_value = lambda do |klass_and_method_and_args|
|
37
|
-
(value = EchoClient.get(klass_and_method_and_args)) !~ /^undefined method/ ? value :
|
38
|
-
Object.we_just_wanna_trigger_a_no_method_error_with_this_very_long_and_weird_method!
|
39
|
-
end
|
40
|
-
end
|
41
|
-
after do
|
42
|
-
EchoServer.stop unless ENV['ECHO_SERVER'] == 'false'
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cross-stub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- NgTzeYang
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-07-16 00:00:00 +08:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: bacon
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 31
|
27
30
|
segments:
|
28
31
|
- 0
|
29
32
|
- 0
|
@@ -35,9 +38,11 @@ dependencies:
|
|
35
38
|
name: eventmachine
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 31
|
41
46
|
segments:
|
42
47
|
- 0
|
43
48
|
- 0
|
@@ -46,31 +51,35 @@ dependencies:
|
|
46
51
|
type: :development
|
47
52
|
version_requirements: *id002
|
48
53
|
- !ruby/object:Gem::Dependency
|
49
|
-
name:
|
54
|
+
name: ruby2ruby
|
50
55
|
prerelease: false
|
51
56
|
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
52
58
|
requirements:
|
53
59
|
- - "="
|
54
60
|
- !ruby/object:Gem::Version
|
61
|
+
hash: 23
|
55
62
|
segments:
|
56
|
-
-
|
57
|
-
-
|
63
|
+
- 1
|
64
|
+
- 2
|
58
65
|
- 4
|
59
|
-
version:
|
66
|
+
version: 1.2.4
|
60
67
|
type: :runtime
|
61
68
|
version_requirements: *id003
|
62
69
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
70
|
+
name: ruby_parser
|
64
71
|
prerelease: false
|
65
72
|
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
66
74
|
requirements:
|
67
75
|
- - "="
|
68
76
|
- !ruby/object:Gem::Version
|
77
|
+
hash: 7
|
69
78
|
segments:
|
70
|
-
- 1
|
71
79
|
- 2
|
80
|
+
- 0
|
72
81
|
- 4
|
73
|
-
version:
|
82
|
+
version: 2.0.4
|
74
83
|
type: :runtime
|
75
84
|
version_requirements: *id004
|
76
85
|
description: ""
|
@@ -92,18 +101,30 @@ files:
|
|
92
101
|
- VERSION
|
93
102
|
- cross-stub.gemspec
|
94
103
|
- lib/cross-stub.rb
|
95
|
-
- lib/cross-stub/
|
96
|
-
- lib/cross-stub/
|
97
|
-
- lib/cross-stub/
|
98
|
-
- lib/cross-stub/
|
104
|
+
- lib/cross-stub/arguments.rb
|
105
|
+
- lib/cross-stub/arguments/array.rb
|
106
|
+
- lib/cross-stub/arguments/hash.rb
|
107
|
+
- lib/cross-stub/arguments/proc.rb
|
108
|
+
- lib/cross-stub/cache.rb
|
109
|
+
- lib/cross-stub/stores.rb
|
110
|
+
- lib/cross-stub/stores/base.rb
|
111
|
+
- lib/cross-stub/stores/file.rb
|
112
|
+
- lib/cross-stub/stores/memcache.rb
|
113
|
+
- lib/cross-stub/stores/redis.rb
|
114
|
+
- lib/cross-stub/stubber.rb
|
99
115
|
- rails_generators/cross_stub/cross_stub_generator.rb
|
100
116
|
- rails_generators/cross_stub/templates/config/initializers/cross-stub.rb
|
101
117
|
- rails_generators/cross_stub/templates/features/support/cross-stub.rb
|
102
118
|
- spec/.bacon
|
103
|
-
- spec/
|
104
|
-
- spec/
|
105
|
-
- spec/
|
106
|
-
- spec/
|
119
|
+
- spec/arguments/proc_spec.rb
|
120
|
+
- spec/includes.rb
|
121
|
+
- spec/integration/clearing_instance_stubs_spec.rb
|
122
|
+
- spec/integration/clearing_stubs_spec.rb
|
123
|
+
- spec/integration/creating_instance_stubs_spec.rb
|
124
|
+
- spec/integration/creating_stubs_spec.rb
|
125
|
+
- spec/integration/shared_spec.rb
|
126
|
+
- spec/integration/stubbing_error_spec.rb
|
127
|
+
- spec/service.rb
|
107
128
|
- spec/spec_helper.rb
|
108
129
|
- tmp/.dummy
|
109
130
|
has_rdoc: true
|
@@ -116,29 +137,40 @@ rdoc_options:
|
|
116
137
|
require_paths:
|
117
138
|
- lib
|
118
139
|
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
119
141
|
requirements:
|
120
142
|
- - ">="
|
121
143
|
- !ruby/object:Gem::Version
|
144
|
+
hash: 57
|
122
145
|
segments:
|
123
|
-
-
|
124
|
-
|
146
|
+
- 1
|
147
|
+
- 8
|
148
|
+
- 7
|
149
|
+
version: 1.8.7
|
125
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
126
152
|
requirements:
|
127
153
|
- - ">="
|
128
154
|
- !ruby/object:Gem::Version
|
155
|
+
hash: 3
|
129
156
|
segments:
|
130
157
|
- 0
|
131
158
|
version: "0"
|
132
159
|
requirements: []
|
133
160
|
|
134
161
|
rubyforge_project:
|
135
|
-
rubygems_version: 1.3.
|
162
|
+
rubygems_version: 1.3.7
|
136
163
|
signing_key:
|
137
164
|
specification_version: 3
|
138
165
|
summary: Simple cross process stubbing
|
139
166
|
test_files:
|
140
|
-
- spec/
|
141
|
-
- spec/
|
142
|
-
- spec/
|
143
|
-
- spec/
|
167
|
+
- spec/includes.rb
|
168
|
+
- spec/arguments/proc_spec.rb
|
169
|
+
- spec/service.rb
|
170
|
+
- spec/integration/stubbing_error_spec.rb
|
171
|
+
- spec/integration/creating_instance_stubs_spec.rb
|
172
|
+
- spec/integration/shared_spec.rb
|
173
|
+
- spec/integration/clearing_stubs_spec.rb
|
174
|
+
- spec/integration/creating_stubs_spec.rb
|
175
|
+
- spec/integration/clearing_instance_stubs_spec.rb
|
144
176
|
- spec/spec_helper.rb
|
@@ -1,48 +0,0 @@
|
|
1
|
-
module CrossStub
|
2
|
-
|
3
|
-
private
|
4
|
-
|
5
|
-
module CacheHelpers
|
6
|
-
|
7
|
-
def setup_cache
|
8
|
-
File.open(cache_file, 'w') {|f| Marshal.dump({}, f) }
|
9
|
-
end
|
10
|
-
|
11
|
-
def update_cache(&blk)
|
12
|
-
dump_cache(yield(load_cache))
|
13
|
-
end
|
14
|
-
|
15
|
-
def delete_cache
|
16
|
-
if File.exists?(cache_file)
|
17
|
-
File.exists?(backup_cache_file) ?
|
18
|
-
File.delete(cache_file) : File.rename(cache_file, backup_cache_file)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def load_cache
|
23
|
-
File.open(cache_file,'r') {|f| Marshal.load(f) }
|
24
|
-
end
|
25
|
-
|
26
|
-
def load_backup_cache
|
27
|
-
cache = {}
|
28
|
-
if File.exists?(backup_cache_file)
|
29
|
-
cache = File.open(backup_cache_file, 'r') {|f| Marshal.load(f) }
|
30
|
-
File.delete(backup_cache_file)
|
31
|
-
end
|
32
|
-
cache
|
33
|
-
end
|
34
|
-
|
35
|
-
def dump_cache(data)
|
36
|
-
File.open(cache_file,'w') {|f| Marshal.dump(data, f) }
|
37
|
-
end
|
38
|
-
|
39
|
-
def backup_cache_file
|
40
|
-
%\#{options[:file]}.bak\
|
41
|
-
end
|
42
|
-
|
43
|
-
def cache_file
|
44
|
-
options[:file]
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|