hijacker 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|