hijacker 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +11 -0
- data/Gemfile.lock +1 -1
- data/Readme.md +24 -9
- data/bin/hijacker +1 -1
- data/lib/hijacker.rb +14 -93
- data/lib/hijacker/config.rb +2 -2
- data/lib/hijacker/exceptions.rb +3 -0
- data/lib/hijacker/handler.rb +17 -5
- data/lib/hijacker/handlers/logger.rb +12 -5
- data/lib/hijacker/method_definer.rb +27 -0
- data/lib/hijacker/spy.rb +75 -0
- data/lib/hijacker/version.rb +1 -1
- data/spec/acceptance/acceptance_spec.rb +98 -0
- data/spec/hijacker/config_spec.rb +27 -4
- data/spec/hijacker/handler_spec.rb +28 -5
- data/spec/hijacker/handlers/logger_spec.rb +41 -0
- data/spec/hijacker/method_definer_spec.rb +113 -0
- data/spec/hijacker/spy_spec.rb +156 -0
- data/spec/hijacker_spec.rb +10 -103
- metadata +13 -3
data/Changelog
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
=== Version 0.2.0 / 2010-12-05
|
2
|
+
|
3
|
+
* enhancements
|
4
|
+
* report blocks passed to hijacked methods as regular arguments
|
5
|
+
* report raised exceptions in hijacked methods
|
6
|
+
* automatically load custom handler classes in these paths:
|
7
|
+
* ./.hijacker/**/*.rb
|
8
|
+
* ~/.hijacker/**/*.rb
|
9
|
+
|
10
|
+
* bug fixes
|
11
|
+
* fixed many issues with 1.8.7
|
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
@@ -16,7 +16,9 @@ creative! :)
|
|
16
16
|
(See the "Extending hijacker blabla" part below to know how to write your own
|
17
17
|
handlers)
|
18
18
|
|
19
|
-
Hijacker is tested with Ruby 1.8.7, 1.9.2, JRuby 1.5.3
|
19
|
+
Hijacker is tested with Ruby 1.8.7, 1.9.2, and JRuby 1.5.3. Unfortunately there
|
20
|
+
are some issues with Rubinius, mostly due to the metaprogramming stuff, which I
|
21
|
+
will definitely look into.
|
20
22
|
|
21
23
|
##Install and configure
|
22
24
|
|
@@ -36,7 +38,7 @@ And that's it! Oooor not. You have to spawn your server. In the command line:
|
|
36
38
|
|
37
39
|
hijacker <handler>
|
38
40
|
|
39
|
-
Where
|
41
|
+
Where \<handler\> must be a registered handler (for now there is only 'logger').
|
40
42
|
So you type:
|
41
43
|
|
42
44
|
hijacker logger
|
@@ -44,6 +46,15 @@ So you type:
|
|
44
46
|
And it will output the URI for this super fancy hijacker logging server.
|
45
47
|
*Remember this URI* and pass it to your configuration block!
|
46
48
|
|
49
|
+
If you have some custom handler, you should send me a pull request! In case you
|
50
|
+
don't want to, Hijacker automatically requires all ruby files inside these
|
51
|
+
paths:
|
52
|
+
|
53
|
+
./.hijacker/**/**.rb
|
54
|
+
~/.hijacker/**/**.rb
|
55
|
+
|
56
|
+
So you put your handlers in there and have fun! :)
|
57
|
+
|
47
58
|
Some options you can pass to the server command:
|
48
59
|
|
49
60
|
hijacker <handler> --port 1234 (spawn the server in port 1234 rather than 8787)
|
@@ -122,13 +133,13 @@ Of course, you can specify a particular server uri for a block, with #spying:
|
|
122
133
|
It is really easy to write your own handlers. Why don't you write one and send
|
123
134
|
me a pull request? I mean now. What are you waiting for, why are you still reading?
|
124
135
|
|
125
|
-
Ok, maybe a bit of explanation on that. Handlers
|
126
|
-
|
127
|
-
lib/hijacker/handlers/your_handler.rb
|
136
|
+
Ok, maybe a bit of explanation on that. Handlers are automatically loaded from
|
137
|
+
here:
|
128
138
|
|
129
|
-
|
130
|
-
|
139
|
+
./.hijacker/**/*.rb
|
140
|
+
~/.hijacker/**/*.rb
|
131
141
|
|
142
|
+
They are automatically registered, so all you have to do is write them like this:
|
132
143
|
|
133
144
|
module Hijacker
|
134
145
|
class MyHandler < Handler # Yes, you have to subclass Hijacker::Handler!
|
@@ -154,10 +165,14 @@ write them like this:
|
|
154
165
|
#
|
155
166
|
# args [{:inspect => '3', :class => 'Fixnum'},
|
156
167
|
# {:inspect => '"string"', :class => 'String'}]
|
168
|
+
#
|
169
|
+
# retval {:inspect => ':bar', :class => 'Symbol'}
|
170
|
+
# (note: retval will be nil if the method raised)
|
157
171
|
#
|
158
|
-
#
|
172
|
+
# raised {:inspect => 'oops', :class => 'StandardError'}
|
173
|
+
# (note: raised will be nil unless the method raised, obviously)
|
159
174
|
#
|
160
|
-
# object
|
175
|
+
# object {:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}
|
161
176
|
#
|
162
177
|
def handle(method, args, retval, object)
|
163
178
|
# Do what you want with these!
|
data/bin/hijacker
CHANGED
@@ -58,7 +58,7 @@ puts welcome.join("#{ANSI[:RESET]} ") + "\n"
|
|
58
58
|
|
59
59
|
# We need the uri of the service to connect a client
|
60
60
|
instructions = "Put this code in the configuration of your ruby program #{ANSI[:BOLD]}before any call to Hijacker#{ANSI[:RESET]}:\n\n"
|
61
|
-
instructions += "\t" + "Hijacker.
|
61
|
+
instructions += "\t" + "Hijacker.configure do\n"
|
62
62
|
instructions += "\t" + " uri '#{DRb.uri}'\n"
|
63
63
|
instructions += "\t" + "end\n\n"
|
64
64
|
puts instructions
|
data/lib/hijacker.rb
CHANGED
@@ -1,113 +1,34 @@
|
|
1
1
|
require 'drb'
|
2
2
|
require 'trollop'
|
3
|
+
require 'hijacker/exceptions'
|
4
|
+
require 'hijacker/method_definer'
|
5
|
+
require 'hijacker/spy'
|
3
6
|
require 'hijacker/config'
|
4
7
|
require 'hijacker/handler'
|
5
8
|
|
6
9
|
module Hijacker
|
7
10
|
|
8
|
-
# Methods that won't be hijacked in any case
|
9
|
-
REJECTED_METHODS = (Object.instance_methods | Module.methods | %w{< <= > >= __original_[\w\d]+ [^\w\d]+})
|
10
|
-
FORBIDDEN_CLASSES = [Array, Hash, String, Fixnum, Float, Numeric, Symbol, Proc, Class, Object, BasicObject, Module]
|
11
|
-
|
12
11
|
class << self
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
Hijacker.spy(*args)
|
17
|
-
block.call
|
18
|
-
Hijacker.restore(args.first)
|
19
|
-
end
|
20
|
-
|
21
|
-
def spy(object, options = {})
|
22
|
-
raise "Cannot spy on the following forbidden classes: #{FORBIDDEN_CLASSES.map(&:to_s).join(', ')}" if FORBIDDEN_CLASSES.include?(object)
|
23
|
-
rejection = /^(#{REJECTED_METHODS.join('|')})/
|
24
|
-
only = options[:only]
|
25
|
-
uri = options[:uri]
|
26
|
-
custom_rejection = options[:reject] if options[:reject].is_a?(Regexp)
|
27
|
-
|
28
|
-
inst_methods = guess_instance_methods_from(object).reject{|m| (m =~ rejection)}.reject{|m| m =~ custom_rejection}
|
29
|
-
sing_methods = guess_class_methods_from(object).reject{|m| m =~ rejection}.reject{|m| m =~ custom_rejection}
|
30
|
-
|
31
|
-
receiver = if object.is_a?(Class)
|
32
|
-
object
|
33
|
-
else
|
34
|
-
(class << object; self; end)
|
35
|
-
end
|
36
|
-
|
37
|
-
inst_methods.each do |met|
|
38
|
-
receiver.send(:alias_method, :"__original_#{met}", :"#{met}")
|
39
|
-
receiver.send(:undef_method, :"#{met}")
|
40
|
-
receiver.class_eval <<EOS
|
41
|
-
def #{met}(*args, &blk)
|
42
|
-
__original_#{met}(*args,&blk).tap do |retval|
|
43
|
-
Hijacker.register :#{met}, args, retval, self, #{uri.inspect}
|
44
|
-
end
|
45
|
-
end
|
46
|
-
EOS
|
47
|
-
end unless options[:only] == :singleton_methods
|
13
|
+
include MethodDefiner
|
14
|
+
private :define_hijacked
|
48
15
|
|
49
|
-
|
50
|
-
|
51
|
-
receiver.send(:alias_method, :"__original_#{met}", :"#{met}")
|
52
|
-
receiver.send(:undef_method, :"#{met}")
|
53
|
-
receiver.class_eval <<EOS
|
54
|
-
def #{met}(*args, &blk)
|
55
|
-
__original_#{met}(*args,&blk).tap do |retval|
|
56
|
-
Hijacker.register :#{met}, args, retval, self, #{uri.inspect}
|
57
|
-
end
|
58
|
-
end
|
59
|
-
EOS
|
60
|
-
end unless options[:only] == :instance_methods
|
16
|
+
include Spy
|
17
|
+
public :spy, :spying, :restore
|
61
18
|
|
62
|
-
|
63
|
-
|
64
|
-
def restore(object)
|
65
|
-
receiver = if object.is_a?(Class)
|
66
|
-
object
|
67
|
-
else
|
68
|
-
(class << object; self; end)
|
69
|
-
end
|
70
|
-
guess_instance_methods_from(object).select{|m| m =~ /__original_/}.each do |met|
|
71
|
-
met = met.to_s.gsub!("__original_", "")
|
72
|
-
receiver.send(:undef_method, :"#{met}")
|
73
|
-
receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
|
74
|
-
end
|
75
|
-
|
76
|
-
receiver = (class << object; self; end)
|
77
|
-
guess_class_methods_from(object).select{|m| m =~ /__original_/}.each do |met|
|
78
|
-
met = met.to_s.gsub!("__original_", "")
|
79
|
-
receiver.send(:undef_method, :"#{met}")
|
80
|
-
receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def register(method, args, retval, object, uri = nil)
|
19
|
+
def register(method, args, retval, raised, object, uri = nil)
|
85
20
|
args.map! do |arg|
|
86
21
|
{:inspect => arg.inspect, :class => arg.class.name}
|
87
22
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
server = DRbObject.new nil, (uri || self.drb_uri)
|
92
|
-
server.handle method, args, retval, object
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
|
97
|
-
def guess_instance_methods_from(object)
|
98
|
-
if object.is_a?(Class)
|
99
|
-
object.instance_methods
|
23
|
+
if raised
|
24
|
+
raised = {:inspect => raised.message, :class => raised.class.name}
|
100
25
|
else
|
101
|
-
|
26
|
+
retval = {:inspect => retval.inspect, :class => retval.class.name}
|
102
27
|
end
|
103
|
-
|
28
|
+
object = {:inspect => object.inspect, :class => object.class.name}
|
104
29
|
|
105
|
-
|
106
|
-
|
107
|
-
object.methods
|
108
|
-
else
|
109
|
-
[]
|
110
|
-
end
|
30
|
+
server = DRbObject.new nil, (uri || self.drb_uri)
|
31
|
+
server.handle method, args, retval, raised, object
|
111
32
|
end
|
112
33
|
|
113
34
|
end
|
data/lib/hijacker/config.rb
CHANGED
@@ -11,8 +11,8 @@ module Hijacker
|
|
11
11
|
def drb_uri
|
12
12
|
begin
|
13
13
|
@@drb_uri
|
14
|
-
rescue
|
15
|
-
raise "Neither a global nor a local Hijacker server URI is configured. Please refer to the README to find out how to do this."
|
14
|
+
rescue NameError
|
15
|
+
raise UndefinedUriError, "Neither a global nor a local Hijacker server URI is configured. Please refer to the README to find out how to do this."
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/lib/hijacker/handler.rb
CHANGED
@@ -21,7 +21,7 @@ module Hijacker
|
|
21
21
|
@opts = opts
|
22
22
|
end
|
23
23
|
|
24
|
-
def handle(method, args, retval, object)
|
24
|
+
def handle(method, args, retval, raised, object)
|
25
25
|
# Parameters received
|
26
26
|
#
|
27
27
|
# method :foo
|
@@ -29,9 +29,14 @@ module Hijacker
|
|
29
29
|
# args [{:inspect => '3', :class => 'Fixnum'},
|
30
30
|
# {:inspect => '"string"', :class => 'String'}]
|
31
31
|
#
|
32
|
-
# retval
|
32
|
+
# retval {:inspect => ':bar', :class => 'Symbol'}
|
33
|
+
#
|
34
|
+
# - In case the method raised something, retval will be nil,
|
35
|
+
# and the exception info will be available in raised:
|
33
36
|
#
|
34
|
-
#
|
37
|
+
# raised {:inspect => 'wrong number of arguments (0 for 2)', :class => 'ArgumentError'}
|
38
|
+
#
|
39
|
+
# object {:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}
|
35
40
|
#
|
36
41
|
raise NotImplementedError.new("You are supposed to subclass Handler")
|
37
42
|
end
|
@@ -52,7 +57,14 @@ module Hijacker
|
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
55
|
-
# Automatically load all handlers
|
56
|
-
|
60
|
+
# Automatically load all handlers in the following paths:
|
61
|
+
#
|
62
|
+
# ./.hijacker/**/*.rb
|
63
|
+
# ~/.hijacker/**/*.rb
|
64
|
+
# lib/handlers/**/*.rb
|
65
|
+
#
|
66
|
+
(Dir[File.dirname(File.join(Dir.pwd, '.hijacker', '**', '*.rb'))] + \
|
67
|
+
Dir[File.dirname(File.expand_path(File.join('~', '.hijacker', '**', '*.rb')))] + \
|
68
|
+
Dir[File.dirname(File.join(File.dirname(__FILE__), 'handlers', '**', '*.rb'))]).entries.each do |handler|
|
57
69
|
require(handler) && Hijacker::Handler.register_handler(handler)
|
58
70
|
end
|
@@ -18,7 +18,7 @@ module Hijacker
|
|
18
18
|
:CYAN=>"\e[36m", :LCYAN=>"\e[1;36m",
|
19
19
|
:WHITE=>"\e[37m"}
|
20
20
|
|
21
|
-
def handle(method, args, retval, object)
|
21
|
+
def handle(method, args, retval, raised, object)
|
22
22
|
out = []
|
23
23
|
out << ANSI[:BOLD] + ANSI[:UNDERLINE] + "#{Time.now}" unless opts[:without_timestamps]
|
24
24
|
out << ANSI[:CYAN] + object[:inspect]
|
@@ -32,10 +32,17 @@ module Hijacker
|
|
32
32
|
ANSI[:RESET]
|
33
33
|
end.join(', ')
|
34
34
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
if raised
|
36
|
+
out << "and raised"
|
37
|
+
out << ANSI[:BLUE] + raised[:inspect]
|
38
|
+
out << ANSI[:LBLUE] + "(#{raised[:class]})" unless opts[:without_classes]
|
39
|
+
out << ANSI[:RESET] + "\n"
|
40
|
+
else
|
41
|
+
out << "and returned"
|
42
|
+
out << ANSI[:BLUE] + retval[:inspect]
|
43
|
+
out << ANSI[:LBLUE] + "(#{retval[:class]})" unless opts[:without_classes]
|
44
|
+
out << ANSI[:RESET] + "\n"
|
45
|
+
end
|
39
46
|
stdout.print out.join("#{ANSI[:RESET]} ")
|
40
47
|
end
|
41
48
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Hijacker
|
2
|
+
module MethodDefiner
|
3
|
+
|
4
|
+
def define_hijacked(methods, receiver, uri)
|
5
|
+
methods.each do |met|
|
6
|
+
receiver.send(:alias_method, :"__original_#{met}", :"#{met}")
|
7
|
+
receiver.send(:undef_method, :"#{met}")
|
8
|
+
writer = (met =~ /=$/)
|
9
|
+
receiver.class_eval <<EOS
|
10
|
+
def #{met}(#{writer ? 'arg' : '*args, &blk'})
|
11
|
+
_args = #{writer ? '[arg]' : 'args'}
|
12
|
+
_args += [blk] if block_given?
|
13
|
+
begin
|
14
|
+
__original_#{met}(#{writer ? 'arg' : '*args, &blk'}).tap do |retval|
|
15
|
+
Hijacker.register :#{met}, _args, retval, nil, self, #{uri.inspect}
|
16
|
+
end
|
17
|
+
rescue=>error
|
18
|
+
Hijacker.register :#{met}, _args, nil, error, self, #{uri.inspect}
|
19
|
+
raise error
|
20
|
+
end
|
21
|
+
end
|
22
|
+
EOS
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/hijacker/spy.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Hijacker
|
2
|
+
module Spy
|
3
|
+
|
4
|
+
REJECTED_METHODS = (Object.instance_methods | Module.methods | %w{__original_[\w\d]+})
|
5
|
+
FORBIDDEN_CLASSES = [Array, Hash, String, Fixnum, Float, Numeric, Symbol, Proc, Class, Object, Module]
|
6
|
+
|
7
|
+
def spying(*args, &block)
|
8
|
+
raise "No block given" unless block
|
9
|
+
Hijacker.spy(*args)
|
10
|
+
block.call
|
11
|
+
Hijacker.restore(args.first)
|
12
|
+
end
|
13
|
+
|
14
|
+
def spy(object, options = {})
|
15
|
+
raise "Cannot spy on the following forbidden classes: #{FORBIDDEN_CLASSES.map(&:to_s).join(', ')}" if FORBIDDEN_CLASSES.include?(object)
|
16
|
+
rejection = /^(#{REJECTED_METHODS.join('|')})/
|
17
|
+
only = options[:only]
|
18
|
+
uri = options[:uri]
|
19
|
+
custom_rejection = options[:reject] if options[:reject].is_a?(Regexp)
|
20
|
+
|
21
|
+
inst_methods = guess_instance_methods_from(object).reject{|m| m.to_s =~ rejection}.reject{|m| m.to_s =~ custom_rejection}
|
22
|
+
sing_methods = guess_singleton_methods_from(object).reject{|m| m.to_s =~ rejection}.reject{|m| m.to_s =~ custom_rejection}
|
23
|
+
|
24
|
+
receiver = if object.is_a?(Class)
|
25
|
+
object
|
26
|
+
else
|
27
|
+
(class << object; self; end)
|
28
|
+
end
|
29
|
+
|
30
|
+
define_hijacked(inst_methods, receiver, uri) unless options[:only] == :singleton_methods
|
31
|
+
receiver = (class << object; self; end)
|
32
|
+
define_hijacked(sing_methods, receiver, uri) unless options[:only] == :instance_methods
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def restore(object)
|
37
|
+
receiver = if object.is_a?(Class)
|
38
|
+
object
|
39
|
+
else
|
40
|
+
(class << object; self; end)
|
41
|
+
end
|
42
|
+
guess_instance_methods_from(object).select{|m| m.to_s =~ /__original_/}.each do |met|
|
43
|
+
met = met.to_s.gsub!("__original_", "")
|
44
|
+
receiver.send(:undef_method, :"#{met}")
|
45
|
+
receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
|
46
|
+
end
|
47
|
+
|
48
|
+
receiver = (class << object; self; end)
|
49
|
+
guess_singleton_methods_from(object).select{|m| m.to_s =~ /__original_/}.each do |met|
|
50
|
+
met = met.to_s.gsub!("__original_", "")
|
51
|
+
receiver.send(:undef_method, :"#{met}")
|
52
|
+
receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def guess_instance_methods_from(object)
|
59
|
+
if object.is_a?(Class)
|
60
|
+
object.instance_methods
|
61
|
+
else
|
62
|
+
object.methods
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def guess_singleton_methods_from(object)
|
67
|
+
if object.is_a?(Class)
|
68
|
+
object.methods
|
69
|
+
else
|
70
|
+
[]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
data/lib/hijacker/version.rb
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# TODO: Turn into green cukes!
|
4
|
+
describe Hijacker, "acceptance specs" do
|
5
|
+
describe "#spy - #restore" do
|
6
|
+
|
7
|
+
describe "hijacking a Class" do
|
8
|
+
describe "instance methods" do
|
9
|
+
before(:each) do
|
10
|
+
Hijacker.spy(MyClass, :only => :instance_methods)
|
11
|
+
end
|
12
|
+
it "registers method calls without arguments" do
|
13
|
+
Hijacker.should_receive(:register).with(:foo, [], 7, nil, kind_of(MyClass), nil).ordered
|
14
|
+
MyClass.new.foo.should == 7
|
15
|
+
end
|
16
|
+
it "registers method calls with arguments" do
|
17
|
+
Hijacker.should_receive(:register).with(:bar, [2, "string"], "string", nil, kind_of(MyClass), nil).ordered
|
18
|
+
MyClass.new.bar(2, "string").should == "string"
|
19
|
+
end
|
20
|
+
after(:each) do
|
21
|
+
Hijacker.restore(MyClass)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
describe "class methods" do
|
25
|
+
before(:each) do
|
26
|
+
Hijacker.spy(MyClass)
|
27
|
+
end
|
28
|
+
it "registers method calls without arguments" do
|
29
|
+
Hijacker.should_receive(:register).with(:foo, [], 7, nil, kind_of(Class), nil).ordered
|
30
|
+
MyClass.foo.should == 7
|
31
|
+
end
|
32
|
+
it "registers method calls with arguments" do
|
33
|
+
Hijacker.should_receive(:register).with(:bar, [2, "string"], "string", nil, kind_of(Class), nil).ordered
|
34
|
+
MyClass.bar(2, "string").should == "string"
|
35
|
+
end
|
36
|
+
after(:each) do
|
37
|
+
Hijacker.restore(MyClass)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
describe "forbidden classes (are not hijacked)" do
|
41
|
+
[Array, Hash, String, Fixnum, Float, Numeric, Symbol].each do |forbidden|
|
42
|
+
it "protects #{forbidden}" do
|
43
|
+
expect {
|
44
|
+
Hijacker.spy(forbidden)
|
45
|
+
}.to raise_error
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
describe "hijacking an object" do
|
51
|
+
describe "instance methods" do
|
52
|
+
let(:object) { MyClass.new }
|
53
|
+
|
54
|
+
before(:each) do
|
55
|
+
def object.my_method
|
56
|
+
8
|
57
|
+
end
|
58
|
+
def object.my_method_with_args(a,b)
|
59
|
+
b
|
60
|
+
end
|
61
|
+
Hijacker.spy(object)
|
62
|
+
end
|
63
|
+
it "registers method calls without arguments" do
|
64
|
+
Hijacker.should_receive(:register).with(:foo, [], 7, nil, kind_of(MyClass), nil).ordered
|
65
|
+
Hijacker.should_receive(:register).with(:my_method, [], 8, nil, kind_of(MyClass), nil).ordered
|
66
|
+
|
67
|
+
object.foo.should == 7
|
68
|
+
object.my_method.should == 8
|
69
|
+
end
|
70
|
+
it "registers method calls with arguments" do
|
71
|
+
Hijacker.should_receive(:register).with(:bar, [2, "string"], "string", nil, kind_of(MyClass), nil).ordered
|
72
|
+
Hijacker.should_receive(:register).with(:my_method_with_args, [2, "string"], "string", nil, kind_of(MyClass), nil).ordered
|
73
|
+
|
74
|
+
object.bar(2, "string").should == "string"
|
75
|
+
object.my_method_with_args(2, "string").should == "string"
|
76
|
+
end
|
77
|
+
it "works well with writers" do
|
78
|
+
Hijacker.should_receive(:register).with(:baz=, [2], 2, nil, kind_of(MyClass), nil).ordered
|
79
|
+
object.baz = 2
|
80
|
+
end
|
81
|
+
it "records exceptions" do
|
82
|
+
Hijacker.should_receive(:register).with(:nasty_method, [], nil, kind_of(StandardError), kind_of(MyClass), nil).ordered
|
83
|
+
expect {
|
84
|
+
object.nasty_method
|
85
|
+
}.to raise_error(StandardError)
|
86
|
+
end
|
87
|
+
it "does not affect other instances of the object's class" do
|
88
|
+
Hijacker.should_not_receive(:register)
|
89
|
+
MyClass.new.foo.should == 7
|
90
|
+
end
|
91
|
+
after(:each) do
|
92
|
+
Hijacker.restore(object)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -3,11 +3,34 @@ require 'spec_helper'
|
|
3
3
|
describe Hijacker, "configuration" do
|
4
4
|
|
5
5
|
describe "#configure" do
|
6
|
-
it '
|
7
|
-
|
8
|
-
|
6
|
+
it 'evaluates the passed block' do
|
7
|
+
block = Proc.new {}
|
8
|
+
Hijacker.should_receive(:instance_eval).with(&block).once
|
9
|
+
Hijacker.configure(&block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#uri" do
|
14
|
+
it 'assigns the DRb uri as a class variable' do
|
15
|
+
Hijacker.uri 'druby://localhost:8787'
|
16
|
+
Hijacker.send(:class_variable_get, :@@drb_uri).should == 'druby://localhost:8787'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#drb_uri" do
|
21
|
+
context "when the class variable is set" do
|
22
|
+
it 'is an accessor to it' do
|
23
|
+
Hijacker.send(:class_variable_set, :@@drb_uri, 'druby://localhost:8787')
|
24
|
+
Hijacker.drb_uri.should == 'druby://localhost:8787'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
context "otherwise" do
|
28
|
+
it 'raises an error' do
|
29
|
+
Hijacker.send(:remove_class_variable, :@@drb_uri)
|
30
|
+
expect {
|
31
|
+
Hijacker.drb_uri
|
32
|
+
}.to raise_error(Hijacker::UndefinedUriError)
|
9
33
|
end
|
10
|
-
Hijacker.drb_uri.should == 'druby://localhost:8787'
|
11
34
|
end
|
12
35
|
end
|
13
36
|
|
@@ -9,8 +9,13 @@ module Hijacker
|
|
9
9
|
subject.opts.should == {:my => :option}
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
it { should respond_to(:opts)}
|
13
|
+
|
14
|
+
it "includes DRb::DRbUndumpled" do
|
15
|
+
Handler.included_modules.should include(DRb::DRbUndumped)
|
16
|
+
end
|
13
17
|
|
18
|
+
describe "#handle" do
|
14
19
|
let(:args) do
|
15
20
|
[:bar,
|
16
21
|
[
|
@@ -18,6 +23,7 @@ module Hijacker
|
|
18
23
|
{:inspect => "\"string\"", :class => "String"},
|
19
24
|
],
|
20
25
|
{:inspect => "\"retval\"", :class => "String"},
|
26
|
+
nil,
|
21
27
|
{:inspect => "MyClass", :class => "Class"}]
|
22
28
|
end
|
23
29
|
|
@@ -31,12 +37,29 @@ module Hijacker
|
|
31
37
|
describe "class methods" do
|
32
38
|
|
33
39
|
describe "#register_handler" do
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
context "when given a relative path" do
|
41
|
+
it 'registers that file as a handler' do
|
42
|
+
Hijacker::Handler.register_handler "/path/to/my/handlers/benchmark.rb"
|
43
|
+
Hijacker::Handler.handlers.should include('benchmark')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
context "when given an absolute path" do
|
47
|
+
it 'registers that file as well' do
|
48
|
+
Hijacker::Handler.register_handler "~/.handlers/custom_handler.rb"
|
49
|
+
Hijacker::Handler.handlers.should include('custom_handler')
|
50
|
+
end
|
37
51
|
end
|
38
52
|
end
|
39
|
-
|
53
|
+
|
54
|
+
describe "#handlers" do
|
55
|
+
it 'is an accessor to the class variable' do
|
56
|
+
handlers = [double('handler'),
|
57
|
+
double('another handler')]
|
58
|
+
Handler.send(:class_variable_set, :@@handlers, handlers)
|
59
|
+
Handler.handlers.should == handlers
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
40
63
|
end
|
41
64
|
|
42
65
|
end
|
@@ -27,6 +27,7 @@ module Hijacker
|
|
27
27
|
{:inspect => "\"string\"", :class => "String"},
|
28
28
|
],
|
29
29
|
{:inspect => "\"retval\"", :class => "String"},
|
30
|
+
nil,
|
30
31
|
{:inspect => "MyClass", :class => "Class"}]
|
31
32
|
end
|
32
33
|
|
@@ -84,6 +85,46 @@ module Hijacker
|
|
84
85
|
end
|
85
86
|
end
|
86
87
|
end
|
88
|
+
context "when given a raised exception" do
|
89
|
+
|
90
|
+
let(:args) do
|
91
|
+
[:bar,
|
92
|
+
[
|
93
|
+
{:inspect => "2", :class => "Fixnum"},
|
94
|
+
{:inspect => "\"string\"", :class => "String"},
|
95
|
+
],
|
96
|
+
nil,
|
97
|
+
{:inspect => "wrong number of arguments (0 for 2)", :class => "ArgumentError"},
|
98
|
+
{:inspect => "MyClass", :class => "Class"}]
|
99
|
+
end
|
100
|
+
|
101
|
+
it "prints it instead of the return value" do
|
102
|
+
out = StringIO.new
|
103
|
+
subject.stub(:stdout).and_return out
|
104
|
+
|
105
|
+
Time.stub(:now).and_return Time.parse('2010-11-20')
|
106
|
+
|
107
|
+
subject.handle(*args)
|
108
|
+
|
109
|
+
["00:00:00 +0100",
|
110
|
+
"MyClass",
|
111
|
+
"(Class)",
|
112
|
+
"received",
|
113
|
+
":bar",
|
114
|
+
"with",
|
115
|
+
"2",
|
116
|
+
"(Fixnum)",
|
117
|
+
"\"string\"",
|
118
|
+
"(String)",
|
119
|
+
"and raised",
|
120
|
+
"wrong number of arguments (0 for 2)",
|
121
|
+
"(ArgumentError)"].each do |str|
|
122
|
+
out.string.should include(str)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
87
128
|
end
|
88
129
|
|
89
130
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Hijacker
|
4
|
+
describe MethodDefiner do
|
5
|
+
|
6
|
+
describe "#define_hijacked" do
|
7
|
+
let(:receiver) do
|
8
|
+
class SomeClass
|
9
|
+
def foo
|
10
|
+
7
|
11
|
+
end
|
12
|
+
def bar(a, b)
|
13
|
+
a + b
|
14
|
+
end
|
15
|
+
def baz=(value)
|
16
|
+
@baz = value
|
17
|
+
end
|
18
|
+
def method_with_block(argument)
|
19
|
+
yield if block_given?
|
20
|
+
end
|
21
|
+
def method_that_raises
|
22
|
+
raise StandardError, "Something went wrong"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
SomeClass
|
26
|
+
end
|
27
|
+
|
28
|
+
before(:each) do
|
29
|
+
Hijacker.stub(:register)
|
30
|
+
end
|
31
|
+
|
32
|
+
after(:each) do
|
33
|
+
Hijacker.restore(receiver)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'saves original methods on the receiver' do
|
37
|
+
Hijacker.send(:define_hijacked, [:foo, :bar], receiver, nil)
|
38
|
+
instance = receiver.new
|
39
|
+
instance.should respond_to(:__original_foo, :__original_bar)
|
40
|
+
instance.should_not respond_to(:__original_baz)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'creates aliased methods' do
|
44
|
+
Hijacker.send(:define_hijacked, [:foo], receiver, nil)
|
45
|
+
instance = receiver.new
|
46
|
+
|
47
|
+
instance.should_receive(:__original_foo).once
|
48
|
+
instance.foo
|
49
|
+
instance.should_not_receive(:__original_bar)
|
50
|
+
instance.bar(9,10)
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "registering method calls" do
|
54
|
+
context "with no arguments" do
|
55
|
+
it "registers the method call" do
|
56
|
+
Hijacker.send(:define_hijacked, [:foo], receiver, nil)
|
57
|
+
instance = receiver.new
|
58
|
+
Hijacker.should_receive(:register).with :foo,
|
59
|
+
[],
|
60
|
+
7,
|
61
|
+
nil,
|
62
|
+
instance,
|
63
|
+
nil
|
64
|
+
instance.foo.should == 7
|
65
|
+
end
|
66
|
+
end
|
67
|
+
context "with arguments" do
|
68
|
+
it "registers the method call" do
|
69
|
+
Hijacker.send(:define_hijacked, [:bar], receiver, nil)
|
70
|
+
instance = receiver.new
|
71
|
+
Hijacker.should_receive(:register).with :bar,
|
72
|
+
[1,2],
|
73
|
+
3,
|
74
|
+
nil,
|
75
|
+
instance,
|
76
|
+
nil
|
77
|
+
instance.bar(1,2).should == 3
|
78
|
+
end
|
79
|
+
end
|
80
|
+
context "with arguments and a block" do
|
81
|
+
it "registers the method call" do
|
82
|
+
Hijacker.send(:define_hijacked, [:method_with_block], receiver, nil)
|
83
|
+
instance = receiver.new
|
84
|
+
Hijacker.should_receive(:register).with :method_with_block,
|
85
|
+
[1,kind_of(Proc)],
|
86
|
+
3,
|
87
|
+
nil,
|
88
|
+
instance,
|
89
|
+
nil
|
90
|
+
instance.method_with_block(1) do
|
91
|
+
3
|
92
|
+
end.should == 3
|
93
|
+
end
|
94
|
+
end
|
95
|
+
context "raising an exception" do
|
96
|
+
it "registers the method call" do
|
97
|
+
Hijacker.send(:define_hijacked, [:method_that_raises], receiver, nil)
|
98
|
+
instance = receiver.new
|
99
|
+
Hijacker.should_receive(:register).with :method_that_raises,
|
100
|
+
[],
|
101
|
+
nil,
|
102
|
+
kind_of(StandardError),
|
103
|
+
instance,
|
104
|
+
nil
|
105
|
+
expect {
|
106
|
+
instance.method_that_raises
|
107
|
+
}.to raise_error(StandardError)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class MyClass
|
4
|
+
def self.foo
|
5
|
+
3 + 4
|
6
|
+
end
|
7
|
+
def self.bar(a,b)
|
8
|
+
b
|
9
|
+
end
|
10
|
+
|
11
|
+
def foo
|
12
|
+
3 + 4
|
13
|
+
end
|
14
|
+
def bar(a,b)
|
15
|
+
b
|
16
|
+
end
|
17
|
+
|
18
|
+
def baz=(value)
|
19
|
+
@value = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def nasty_method
|
23
|
+
raise StandardError, "Something went wrong"
|
24
|
+
end
|
25
|
+
|
26
|
+
end unless defined?(MyClass)
|
27
|
+
|
28
|
+
module Hijacker
|
29
|
+
describe Spy do
|
30
|
+
let(:object) { MyClass.new }
|
31
|
+
let(:klass) { MyClass }
|
32
|
+
let(:inst_methods) { [:foo, :bar] }
|
33
|
+
let(:sing_methods) { [:foo, :bar] }
|
34
|
+
|
35
|
+
describe "#spying" do
|
36
|
+
it 'runs a block spying on a particular object' do
|
37
|
+
blk = lambda {
|
38
|
+
MyClass.foo
|
39
|
+
}
|
40
|
+
Hijacker.should_receive(:spy).with(MyClass).once.ordered
|
41
|
+
MyClass.should_receive(:foo).once.ordered
|
42
|
+
Hijacker.should_receive(:restore).with(MyClass).once.ordered
|
43
|
+
|
44
|
+
Hijacker.spying(MyClass, &blk)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'raises if no block given' do
|
48
|
+
expect {
|
49
|
+
Hijacker.spying(MyClass)
|
50
|
+
}.to raise_error("No block given")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#spy" do
|
55
|
+
|
56
|
+
context "when given a class" do
|
57
|
+
before(:each) do
|
58
|
+
Hijacker.should_receive(:guess_instance_methods_from).with(klass).and_return(inst_methods)
|
59
|
+
Hijacker.should_receive(:guess_singleton_methods_from).with(klass).and_return(sing_methods)
|
60
|
+
end
|
61
|
+
|
62
|
+
let(:metaclass) { (class << klass; self; end) }
|
63
|
+
|
64
|
+
it 'calls define_hijacked on all methods' do
|
65
|
+
Hijacker.should_receive(:define_hijacked).with(inst_methods, klass, nil).once
|
66
|
+
Hijacker.should_receive(:define_hijacked).with(sing_methods, metaclass, nil).once
|
67
|
+
|
68
|
+
Hijacker.spy(klass)
|
69
|
+
end
|
70
|
+
context "with :only => :singleton_methods" do
|
71
|
+
it 'calls define_hijacked only on singleton methods' do
|
72
|
+
Hijacker.should_not_receive(:define_hijacked).with(inst_methods, klass, nil)
|
73
|
+
Hijacker.should_receive(:define_hijacked).with(sing_methods, metaclass, nil).once
|
74
|
+
|
75
|
+
Hijacker.spy(klass, :only => :singleton_methods)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
context "with :only => :instance_methods" do
|
79
|
+
it 'calls define_hijacked only on instance methods' do
|
80
|
+
Hijacker.should_receive(:define_hijacked).with(inst_methods, klass, nil)
|
81
|
+
Hijacker.should_not_receive(:define_hijacked).with(sing_methods, metaclass, nil)
|
82
|
+
|
83
|
+
Hijacker.spy(klass, :only => :instance_methods)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
context "when given an object" do
|
88
|
+
before(:each) do
|
89
|
+
Hijacker.stub(:guess_instance_methods_from).with(object).and_return(inst_methods)
|
90
|
+
Hijacker.stub(:guess_singleton_methods_from).with(object).and_return(sing_methods)
|
91
|
+
end
|
92
|
+
|
93
|
+
let(:metaclass) { (class << object; self; end) }
|
94
|
+
it 'calls define_hijacked on all methods' do
|
95
|
+
Hijacker.should_receive(:define_hijacked).with(inst_methods, metaclass, nil).once
|
96
|
+
Hijacker.should_receive(:define_hijacked).with(sing_methods, metaclass, nil).once
|
97
|
+
|
98
|
+
Hijacker.spy(object)
|
99
|
+
end
|
100
|
+
context "with :only => :singleton_methods" do
|
101
|
+
it 'calls define_hijacked only on singleton methods' do
|
102
|
+
Hijacker.should_receive(:define_hijacked).with(sing_methods, metaclass, nil).once
|
103
|
+
|
104
|
+
Hijacker.spy(object, :only => :singleton_methods)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
context "with :only => :instance_methods" do
|
108
|
+
it 'calls define_hijacked only on instance methods' do
|
109
|
+
Hijacker.should_receive(:define_hijacked).with(inst_methods, metaclass, nil).once
|
110
|
+
|
111
|
+
Hijacker.spy(object, :only => :instance_methods)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
context "when given a forbidden class" do
|
116
|
+
it "raises" do
|
117
|
+
expect {
|
118
|
+
Hijacker.spy(Array)
|
119
|
+
}.to raise_error(StandardError)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
it "rejects methods from REJECTED_METHODS constant" do
|
123
|
+
inst_methods_with_some_rejected = inst_methods | [:instance_eval, :__original_something]
|
124
|
+
sing_methods_with_some_rejected = sing_methods | [:instance_eval, :__original_something]
|
125
|
+
|
126
|
+
Hijacker.should_receive(:guess_instance_methods_from).with(object).and_return(inst_methods_with_some_rejected)
|
127
|
+
Hijacker.should_receive(:guess_singleton_methods_from).with(object).and_return(sing_methods_with_some_rejected)
|
128
|
+
|
129
|
+
Hijacker.should_receive(:define_hijacked).with(inst_methods, kind_of(Class), nil).once
|
130
|
+
Hijacker.should_receive(:define_hijacked).with(sing_methods, kind_of(Class), nil).once
|
131
|
+
|
132
|
+
Hijacker.spy(object)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "#restore" do
|
137
|
+
it "restores all methods from the object" do
|
138
|
+
inst_methods_with_some_hijacked = inst_methods | [:__original_foo, :__original_bar]
|
139
|
+
sing_methods_with_some_hijacked = sing_methods | [:__original_foo, :__original_bar]
|
140
|
+
receiver = (class << object; self; end)
|
141
|
+
|
142
|
+
Hijacker.should_receive(:guess_instance_methods_from).with(object).and_return(inst_methods_with_some_hijacked)
|
143
|
+
Hijacker.should_receive(:guess_singleton_methods_from).with(object).and_return(sing_methods_with_some_hijacked)
|
144
|
+
|
145
|
+
receiver.should_receive(:undef_method).with(:foo).twice # instance and singleton methods
|
146
|
+
receiver.should_receive(:alias_method).with(:foo, :__original_foo).twice
|
147
|
+
receiver.should_receive(:undef_method).with(:bar).twice
|
148
|
+
receiver.should_receive(:alias_method).with(:bar, :__original_bar).twice
|
149
|
+
|
150
|
+
Hijacker.restore(object)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
data/spec/hijacker_spec.rb
CHANGED
@@ -14,112 +14,18 @@ class MyClass
|
|
14
14
|
def bar(a,b)
|
15
15
|
b
|
16
16
|
end
|
17
|
-
end
|
18
|
-
|
19
|
-
describe Hijacker do
|
20
|
-
|
21
|
-
describe "#spying" do
|
22
|
-
it 'runs a block spying on a particular object' do
|
23
|
-
blk = lambda {
|
24
|
-
MyClass.foo
|
25
|
-
}
|
26
|
-
Hijacker.should_receive(:spy).with(MyClass).once.ordered
|
27
|
-
MyClass.should_receive(:foo).once.ordered
|
28
|
-
Hijacker.should_receive(:restore).with(MyClass).once.ordered
|
29
|
-
|
30
|
-
Hijacker.spying(MyClass, &blk)
|
31
|
-
end
|
32
17
|
|
33
|
-
|
34
|
-
|
35
|
-
Hijacker.spying(MyClass)
|
36
|
-
}.to raise_error("No block given")
|
37
|
-
end
|
18
|
+
def baz=(value)
|
19
|
+
@value = value
|
38
20
|
end
|
39
21
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
describe "instance methods" do
|
44
|
-
before(:each) do
|
45
|
-
Hijacker.spy(MyClass, :only => :instance_methods)
|
46
|
-
end
|
47
|
-
it "registers method calls without arguments" do
|
48
|
-
Hijacker.should_receive(:register).with(:foo, [], 7, kind_of(MyClass), nil).ordered
|
49
|
-
MyClass.new.foo.should == 7
|
50
|
-
end
|
51
|
-
it "registers method calls with arguments" do
|
52
|
-
Hijacker.should_receive(:register).with(:bar, [2, "string"], "string", kind_of(MyClass), nil).ordered
|
53
|
-
MyClass.new.bar(2, "string").should == "string"
|
54
|
-
end
|
55
|
-
after(:each) do
|
56
|
-
Hijacker.restore(MyClass)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
describe "class methods" do
|
60
|
-
before(:each) do
|
61
|
-
Hijacker.spy(MyClass)
|
62
|
-
end
|
63
|
-
it "registers method calls without arguments" do
|
64
|
-
Hijacker.should_receive(:register).with(:foo, [], 7, kind_of(Class), nil).ordered
|
65
|
-
MyClass.foo.should == 7
|
66
|
-
end
|
67
|
-
it "registers method calls with arguments" do
|
68
|
-
Hijacker.should_receive(:register).with(:bar, [2, "string"], "string", kind_of(Class), nil).ordered
|
69
|
-
MyClass.bar(2, "string").should == "string"
|
70
|
-
end
|
71
|
-
after(:each) do
|
72
|
-
Hijacker.restore(MyClass)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
describe "forbidden classes (are not hijacked)" do
|
76
|
-
[Array, Hash, String, Fixnum, Float, Numeric, Symbol].each do |forbidden|
|
77
|
-
it "protects #{forbidden}" do
|
78
|
-
expect {
|
79
|
-
Hijacker.spy(forbidden)
|
80
|
-
}.to raise_error
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
describe "hijacking an object" do
|
86
|
-
describe "instance methods" do
|
87
|
-
let(:object) { MyClass.new }
|
88
|
-
|
89
|
-
before(:each) do
|
90
|
-
def object.my_method
|
91
|
-
8
|
92
|
-
end
|
93
|
-
def object.my_method_with_args(a,b)
|
94
|
-
b
|
95
|
-
end
|
96
|
-
Hijacker.spy(object)
|
97
|
-
end
|
98
|
-
it "registers method calls without arguments" do
|
99
|
-
Hijacker.should_receive(:register).with(:foo, [], 7, kind_of(MyClass), nil).ordered
|
100
|
-
Hijacker.should_receive(:register).with(:my_method, [], 8, kind_of(MyClass), nil).ordered
|
22
|
+
def method_that_raises
|
23
|
+
raise StandardError, "Something went wrong"
|
24
|
+
end
|
101
25
|
|
102
|
-
|
103
|
-
object.my_method.should == 8
|
104
|
-
end
|
105
|
-
it "registers method calls with arguments" do
|
106
|
-
Hijacker.should_receive(:register).with(:bar, [2, "string"], "string", kind_of(MyClass), nil).ordered
|
107
|
-
Hijacker.should_receive(:register).with(:my_method_with_args, [2, "string"], "string", kind_of(MyClass), nil).ordered
|
26
|
+
end unless defined?(MyClass)
|
108
27
|
|
109
|
-
|
110
|
-
object.my_method_with_args(2, "string").should == "string"
|
111
|
-
end
|
112
|
-
it "does not affect other instances of the object's class" do
|
113
|
-
Hijacker.should_not_receive(:register)
|
114
|
-
MyClass.new.foo.should == 7
|
115
|
-
end
|
116
|
-
after(:each) do
|
117
|
-
Hijacker.restore(object)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
28
|
+
describe Hijacker do
|
123
29
|
|
124
30
|
describe "#register" do
|
125
31
|
it 'sends the registered method call to the DRb server' do
|
@@ -133,18 +39,19 @@ describe Hijacker do
|
|
133
39
|
{:inspect => "\"string\"", :class => "String"},
|
134
40
|
],
|
135
41
|
{:inspect => "\"retval\"", :class => "String"},
|
42
|
+
nil,
|
136
43
|
{:inspect => "MyClass", :class => "Class"}
|
137
44
|
]
|
138
45
|
|
139
46
|
DRbObject.should_receive(:new).with(nil, "druby://localhost:9999").and_return server
|
140
47
|
server.should_receive(:handle).with *expected_args
|
141
48
|
|
142
|
-
Hijacker.register(:bar, [2, "string"], "retval", MyClass)
|
49
|
+
Hijacker.register(:bar, [2, "string"], "retval", nil, MyClass)
|
143
50
|
end
|
144
51
|
context "when given a particular DRb uri" do
|
145
52
|
it "sends the call to that uri" do
|
146
53
|
DRbObject.should_receive(:new).with(nil, "druby://localhost:1212").and_return mock('DRb server', :handle => true)
|
147
|
-
Hijacker.register(:bar, [2, "string"], "retval", MyClass, "druby://localhost:1212")
|
54
|
+
Hijacker.register(:bar, [2, "string"], "retval", nil, MyClass, "druby://localhost:1212")
|
148
55
|
end
|
149
56
|
end
|
150
57
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 2
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Josep M. Bach
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-12-05 00:00:00 +01:00
|
18
18
|
default_executable: hijacker
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -112,6 +112,7 @@ files:
|
|
112
112
|
- .gitignore
|
113
113
|
- .rspec
|
114
114
|
- .rvmrc
|
115
|
+
- Changelog
|
115
116
|
- Gemfile
|
116
117
|
- Gemfile.lock
|
117
118
|
- Guardfile
|
@@ -121,12 +122,18 @@ files:
|
|
121
122
|
- hijacker.gemspec
|
122
123
|
- lib/hijacker.rb
|
123
124
|
- lib/hijacker/config.rb
|
125
|
+
- lib/hijacker/exceptions.rb
|
124
126
|
- lib/hijacker/handler.rb
|
125
127
|
- lib/hijacker/handlers/logger.rb
|
128
|
+
- lib/hijacker/method_definer.rb
|
129
|
+
- lib/hijacker/spy.rb
|
126
130
|
- lib/hijacker/version.rb
|
131
|
+
- spec/acceptance/acceptance_spec.rb
|
127
132
|
- spec/hijacker/config_spec.rb
|
128
133
|
- spec/hijacker/handler_spec.rb
|
129
134
|
- spec/hijacker/handlers/logger_spec.rb
|
135
|
+
- spec/hijacker/method_definer_spec.rb
|
136
|
+
- spec/hijacker/spy_spec.rb
|
130
137
|
- spec/hijacker_spec.rb
|
131
138
|
- spec/spec_helper.rb
|
132
139
|
has_rdoc: true
|
@@ -162,8 +169,11 @@ signing_key:
|
|
162
169
|
specification_version: 3
|
163
170
|
summary: Spy on your ruby objects and send their activity to a hijacker server anywhere through DRb
|
164
171
|
test_files:
|
172
|
+
- spec/acceptance/acceptance_spec.rb
|
165
173
|
- spec/hijacker/config_spec.rb
|
166
174
|
- spec/hijacker/handler_spec.rb
|
167
175
|
- spec/hijacker/handlers/logger_spec.rb
|
176
|
+
- spec/hijacker/method_definer_spec.rb
|
177
|
+
- spec/hijacker/spy_spec.rb
|
168
178
|
- spec/hijacker_spec.rb
|
169
179
|
- spec/spec_helper.rb
|