hijacker 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/Readme.md +85 -13
- data/bin/hijacker +26 -7
- data/lib/hijacker.rb +2 -2
- data/lib/hijacker/handler.rb +58 -0
- data/lib/hijacker/{logger.rb → handlers/logger.rb} +9 -12
- data/lib/hijacker/version.rb +1 -1
- data/spec/hijacker/handler_spec.rb +43 -0
- data/spec/hijacker/{logger_spec.rb → handlers/logger_spec.rb} +13 -4
- data/spec/hijacker_spec.rb +2 -2
- metadata +9 -6
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
@@ -1,9 +1,20 @@
|
|
1
1
|
#hijacker
|
2
2
|
|
3
3
|
A little gem that hijacks any ruby object and broadcasts all its activity
|
4
|
-
to a particular hijacker server.
|
5
|
-
|
6
|
-
|
4
|
+
to a particular hijacker server. The server exposes a special handler object
|
5
|
+
which then does fun things with the received data!
|
6
|
+
|
7
|
+
For example, by now there is only one handler: Logger. This handler shows the
|
8
|
+
received activity in the server output with fancy logging-style colors. Could
|
9
|
+
be quite useful for those awfully long debugging afternoons!
|
10
|
+
|
11
|
+
Of course, you can write your own handlers to do whatever you want with the
|
12
|
+
data: maybe record how many arguments do your methods accept on average, log
|
13
|
+
into disk any method calls containing a certain type of argument... just be
|
14
|
+
creative! :)
|
15
|
+
|
16
|
+
(See the "Extending hijacker blabla" part below to know how to write your own
|
17
|
+
handlers)
|
7
18
|
|
8
19
|
Hijacker is tested with Ruby 1.8.7, 1.9.2, JRuby 1.5.3 and Rubinius 1.1.
|
9
20
|
|
@@ -23,16 +34,24 @@ otherwise, as long as it's before hijacking any object):
|
|
23
34
|
|
24
35
|
And that's it! Oooor not. You have to spawn your server. In the command line:
|
25
36
|
|
26
|
-
hijacker
|
37
|
+
hijacker <handler>
|
38
|
+
|
39
|
+
Where <handler> must be a registered handler (for now there is only 'logger').
|
40
|
+
So you type:
|
27
41
|
|
28
|
-
|
29
|
-
|
42
|
+
hijacker logger
|
43
|
+
|
44
|
+
And it will output the URI for this super fancy hijacker logging server.
|
45
|
+
*Remember this URI* and pass it to your configuration block!
|
30
46
|
|
31
47
|
Some options you can pass to the server command:
|
32
48
|
|
33
|
-
hijacker --
|
34
|
-
|
35
|
-
|
49
|
+
hijacker <handler> --port 1234 (spawn the server in port 1234 rather than 8787)
|
50
|
+
|
51
|
+
Specific handlers can accept specific options. Logger accepts these:
|
52
|
+
|
53
|
+
hijacker logger --without-timestamps (don't show the timestamps)
|
54
|
+
hijacker logger --without-classes (don't show the object classes)
|
36
55
|
|
37
56
|
##Ok, and now for some hijacking action!
|
38
57
|
|
@@ -54,11 +73,12 @@ Some options you can pass to the server command:
|
|
54
73
|
instance = MyClass.new
|
55
74
|
instance.foo(3, 4)
|
56
75
|
|
57
|
-
Run this code and, if you look at the server output, you'll see nothing less
|
58
|
-
than...
|
76
|
+
Run this code and, given we are using the Logger handler, if you look at the server output, you'll see nothing less than...
|
59
77
|
|
60
78
|
<a nice timestamp> MyClass (Class) received :new and returned #<MyClass:0x000000874> (MyClass)
|
61
|
-
<a nice timestamp> #<MyClass:0x000000874> (MyClass) received :foo with 3 (Fixnum), 4 (Fixnum) and returned 7
|
79
|
+
<a nice timestamp> #<MyClass:0x000000874> (MyClass) received :foo with 3 (Fixnum), 4 (Fixnum) and returned 7 (Fixnum)
|
80
|
+
|
81
|
+
But in a nice set of colors.
|
62
82
|
|
63
83
|
If you want to un-hijack any object, just call #restore:
|
64
84
|
|
@@ -96,7 +116,59 @@ Of course, you can specify a particular server uri for a block, with #spying:
|
|
96
116
|
# all the activity of foo_object inside this block
|
97
117
|
# will be sent to the hijacker server on druby://localhost:1234
|
98
118
|
end
|
99
|
-
|
119
|
+
|
120
|
+
##Extending hijacker with moar handlers
|
121
|
+
|
122
|
+
It is really easy to write your own handlers. Why don't you write one and send
|
123
|
+
me a pull request? I mean now. What are you waiting for, why are you still reading?
|
124
|
+
|
125
|
+
Ok, maybe a bit of explanation on that. Handlers live here:
|
126
|
+
|
127
|
+
lib/hijacker/handlers/your_handler.rb
|
128
|
+
|
129
|
+
They are autoloaded and automatically registered, so all you have to do is
|
130
|
+
write them like this:
|
131
|
+
|
132
|
+
|
133
|
+
module Hijacker
|
134
|
+
class MyHandler < Handler # Yes, you have to subclass Hijacker::Handler!
|
135
|
+
|
136
|
+
# You must implement a class method named cli_options which must
|
137
|
+
# return a Trollop-friendly Proc, for command-line options parsing.
|
138
|
+
#
|
139
|
+
# These options can be accessed within the #handle method by calling
|
140
|
+
# the opts method.
|
141
|
+
#
|
142
|
+
def self.cli_options
|
143
|
+
Proc.new {
|
144
|
+
opt :without_foo, "Don't use foo to handle the method name"
|
145
|
+
opt :using_bar, "Use bar as much as you can"
|
146
|
+
}
|
147
|
+
end
|
148
|
+
|
149
|
+
# This is the most important method. This is what is called every time
|
150
|
+
# a method call is performed on a hijacked object. The received params
|
151
|
+
# look like this:
|
152
|
+
#
|
153
|
+
# method :foo
|
154
|
+
#
|
155
|
+
# args [{:inspect => '3', :class => 'Fixnum'},
|
156
|
+
# {:inspect => '"string"', :class => 'String'}]
|
157
|
+
#
|
158
|
+
# retval [{:inspect => ':bar', :class => 'Symbol'}]
|
159
|
+
#
|
160
|
+
# object [{:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}]
|
161
|
+
#
|
162
|
+
def handle(method, args, retval, object)
|
163
|
+
# Do what you want with these!
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
Try to think of creative uses of hijacker, write your own handlers and send
|
170
|
+
them to me ZOMG I CAN HAZ MOAR HENDLARZ
|
171
|
+
|
100
172
|
##Note on Patches/Pull Requests
|
101
173
|
|
102
174
|
* Fork the project.
|
data/bin/hijacker
CHANGED
@@ -3,21 +3,32 @@
|
|
3
3
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
4
4
|
|
5
5
|
require 'hijacker'
|
6
|
+
require 'hijacker/version'
|
6
7
|
|
8
|
+
SUB_COMMANDS = Hijacker::Handler.handlers
|
7
9
|
opts = Trollop::options do
|
8
|
-
version "hijacker
|
10
|
+
version "hijacker #{Hijacker::VERSION} (c) 2010 Josep M. Bach"
|
9
11
|
banner <<-EOS
|
10
|
-
Hijacker server listens for reports by hijackers spying on ruby objects
|
12
|
+
Hijacker server listens for reports by hijackers spying on ruby objects,
|
13
|
+
and passes them to a given handler to process those reports.
|
14
|
+
|
15
|
+
Specific handlers may accept specific options. To learn about which options
|
16
|
+
does a particular handler accept, try:
|
17
|
+
|
18
|
+
hijacker <handler> --help
|
19
|
+
|
20
|
+
The available handlers are:
|
21
|
+
#{SUB_COMMANDS.join(', ')}
|
11
22
|
|
12
23
|
Usage:
|
13
|
-
hijacker [options]
|
24
|
+
hijacker <handler> [options]
|
14
25
|
where [options] are:
|
15
26
|
EOS
|
16
|
-
opt :without_classes, "Don't show classes of objects"
|
17
|
-
opt :without_timestamps, "Don't show timestamps"
|
18
27
|
opt :port, "DRb port to use (default is 8787)", :default => 8787
|
28
|
+
stop_on SUB_COMMANDS
|
19
29
|
end
|
20
30
|
|
31
|
+
# Port resolution
|
21
32
|
begin
|
22
33
|
raise unless opts[:port].to_i > 0 && opts[:port].to_i < 9999
|
23
34
|
rescue
|
@@ -26,15 +37,23 @@ end
|
|
26
37
|
|
27
38
|
DRB_URI="druby://localhost:#{opts[:port]}"
|
28
39
|
|
40
|
+
# Handler resolution
|
41
|
+
handler = ARGV.shift # get the handler
|
42
|
+
Trollop::die "You need to specify a handler, which must be one of the following: #{SUB_COMMANDS.join(', ')}\n\nMaybe you just feel a bit lost.." unless SUB_COMMANDS.include?(handler)
|
43
|
+
|
44
|
+
handler_class = eval("Hijacker::#{handler.capitalize}")
|
45
|
+
Trollop::options(&handler_class.cli_options)
|
46
|
+
|
29
47
|
# Start up the DRb service
|
30
|
-
DRb.start_service DRB_URI,
|
48
|
+
DRb.start_service DRB_URI, handler_class.new(opts)
|
31
49
|
|
32
50
|
ANSI = Hijacker::Logger::ANSI
|
33
51
|
# We need the uri of the service to connect a client
|
34
52
|
welcome = []
|
35
53
|
welcome << ANSI[:BOLD] + "hijacker server"
|
36
54
|
welcome << "listening on"
|
37
|
-
welcome << ANSI[:BOLD] + DRb.uri
|
55
|
+
welcome << ANSI[:BOLD] + DRb.uri
|
56
|
+
welcome << "\nUsing " + ANSI[:GREEN] + handler.capitalize + ANSI[:RESET] + " handler" + ANSI[:RESET]
|
38
57
|
puts welcome.join("#{ANSI[:RESET]} ") + "\n"
|
39
58
|
|
40
59
|
# We need the uri of the service to connect a client
|
data/lib/hijacker.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'drb'
|
2
2
|
require 'trollop'
|
3
3
|
require 'hijacker/config'
|
4
|
-
require 'hijacker/
|
4
|
+
require 'hijacker/handler'
|
5
5
|
|
6
6
|
module Hijacker
|
7
7
|
|
@@ -89,7 +89,7 @@ EOS
|
|
89
89
|
object = {:inspect => object.inspect, :class => object.class.name}
|
90
90
|
|
91
91
|
server = DRbObject.new nil, (uri || self.drb_uri)
|
92
|
-
server.
|
92
|
+
server.handle method, args, retval, object
|
93
93
|
end
|
94
94
|
|
95
95
|
private
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Hijacker
|
2
|
+
class Handler
|
3
|
+
# Your custom handlers need to respond to this class method, which will be
|
4
|
+
# expected to return a proc meant to be sent to Trollop during the command
|
5
|
+
# line parsing. For example, the Logger handler implements cli_options like
|
6
|
+
# this:
|
7
|
+
#
|
8
|
+
# def self.cli_options
|
9
|
+
# Proc.new {
|
10
|
+
# opt :without_classes, "Don't show classes of objects"
|
11
|
+
# opt :without_timestamps, "Don't show timestamps"
|
12
|
+
# }
|
13
|
+
# end
|
14
|
+
|
15
|
+
# Make dRuby send Handler instances as dRuby references,
|
16
|
+
# not copies.
|
17
|
+
include DRb::DRbUndumped
|
18
|
+
|
19
|
+
attr_reader :opts
|
20
|
+
def initialize(opts)
|
21
|
+
@opts = opts
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle(method, args, retval, object)
|
25
|
+
# Parameters received
|
26
|
+
#
|
27
|
+
# method :foo
|
28
|
+
#
|
29
|
+
# args [{:inspect => '3', :class => 'Fixnum'},
|
30
|
+
# {:inspect => '"string"', :class => 'String'}]
|
31
|
+
#
|
32
|
+
# retval [{:inspect => ':bar', :class => 'Symbol'}]
|
33
|
+
#
|
34
|
+
# object [{:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}]
|
35
|
+
#
|
36
|
+
raise NotImplementedError.new("You are supposed to subclass Handler")
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
|
41
|
+
@@handlers = []
|
42
|
+
|
43
|
+
def register_handler(handler)
|
44
|
+
handler.match(/handlers\/(\w+)/)
|
45
|
+
handler = $1.strip if $1
|
46
|
+
@@handlers << handler
|
47
|
+
end
|
48
|
+
def handlers
|
49
|
+
@@handlers
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Automatically load all handlers
|
56
|
+
Dir[File.dirname(File.join(File.dirname(__FILE__), 'handlers', '**', '*.rb'))].entries.each do |handler|
|
57
|
+
require(handler) && Hijacker::Handler.register_handler(handler)
|
58
|
+
end
|
@@ -1,5 +1,12 @@
|
|
1
1
|
module Hijacker
|
2
|
-
class Logger
|
2
|
+
class Logger < Handler
|
3
|
+
|
4
|
+
def self.cli_options
|
5
|
+
Proc.new {
|
6
|
+
opt :without_classes, "Don't show classes of objects"
|
7
|
+
opt :without_timestamps, "Don't show timestamps"
|
8
|
+
}
|
9
|
+
end
|
3
10
|
|
4
11
|
ANSI = {:RESET=>"\e[0m", :BOLD=>"\e[1m", :UNDERLINE=>"\e[4m",
|
5
12
|
:LGRAY=>"\e[0;37m", :GRAY=>"\e[1;30m",
|
@@ -10,18 +17,8 @@ module Hijacker
|
|
10
17
|
:PURPLE=>"\e[35m", :LPURPLE=>"\e[1;35m",
|
11
18
|
:CYAN=>"\e[36m", :LCYAN=>"\e[1;36m",
|
12
19
|
:WHITE=>"\e[37m"}
|
13
|
-
|
14
|
-
# Make dRuby send Logger instances as dRuby references,
|
15
|
-
# not copies.
|
16
|
-
include DRb::DRbUndumped
|
17
|
-
|
18
|
-
attr_reader :opts
|
19
|
-
|
20
|
-
def initialize(opts)
|
21
|
-
@opts = opts
|
22
|
-
end
|
23
20
|
|
24
|
-
def
|
21
|
+
def handle(method, args, retval, object)
|
25
22
|
out = []
|
26
23
|
out << ANSI[:BOLD] + ANSI[:UNDERLINE] + "#{Time.now}" unless opts[:without_timestamps]
|
27
24
|
out << ANSI[:CYAN] + object[:inspect]
|
data/lib/hijacker/version.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Hijacker
|
4
|
+
describe Handler do
|
5
|
+
|
6
|
+
subject { Handler.new({:my => :option}) }
|
7
|
+
|
8
|
+
it "initializes with options" do
|
9
|
+
subject.opts.should == {:my => :option}
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#handle" do
|
13
|
+
|
14
|
+
let(:args) do
|
15
|
+
[:bar,
|
16
|
+
[
|
17
|
+
{:inspect => "2", :class => "Fixnum"},
|
18
|
+
{:inspect => "\"string\"", :class => "String"},
|
19
|
+
],
|
20
|
+
{:inspect => "\"retval\"", :class => "String"},
|
21
|
+
{:inspect => "MyClass", :class => "Class"}]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "is meant to be overriden by subclasses" do
|
25
|
+
expect {
|
26
|
+
subject.handle(*args)
|
27
|
+
}.to raise_error NotImplementedError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "class methods" do
|
32
|
+
|
33
|
+
describe "#register_handler" do
|
34
|
+
it 'registers a loaded handler' do
|
35
|
+
Hijacker::Handler.register_handler "/path/to/my/handlers/benchmark.rb"
|
36
|
+
Hijacker::Handler.handlers.should include('benchmark')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -9,7 +9,16 @@ module Hijacker
|
|
9
9
|
subject.opts.should == {:my => :option}
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
it "inherits from Handler" do
|
13
|
+
subject.should be_kind_of(Handler)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "implements the cli_options class method" do
|
17
|
+
Hijacker::Logger.should respond_to(:cli_options)
|
18
|
+
Hijacker::Logger.cli_options.should be_kind_of(Proc)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#handle" do
|
13
22
|
|
14
23
|
let(:args) do
|
15
24
|
[:bar,
|
@@ -27,7 +36,7 @@ module Hijacker
|
|
27
36
|
|
28
37
|
Time.stub(:now).and_return Time.parse('2010-11-20')
|
29
38
|
|
30
|
-
subject.
|
39
|
+
subject.handle(*args)
|
31
40
|
|
32
41
|
["00:00:00 +0100",
|
33
42
|
"MyClass",
|
@@ -54,7 +63,7 @@ module Hijacker
|
|
54
63
|
|
55
64
|
Time.stub(:now).and_return Time.parse('2010-11-20')
|
56
65
|
|
57
|
-
logger.
|
66
|
+
logger.handle(*args)
|
58
67
|
|
59
68
|
out.string.should_not include("2010-11-20")
|
60
69
|
end
|
@@ -68,7 +77,7 @@ module Hijacker
|
|
68
77
|
|
69
78
|
Time.stub(:now).and_return Time.parse('2010-11-20')
|
70
79
|
|
71
|
-
logger.
|
80
|
+
logger.handle(*args)
|
72
81
|
|
73
82
|
["(Class)", "(Fixnum)", "(String)"].each do |str|
|
74
83
|
out.string.should_not include(str)
|
data/spec/hijacker_spec.rb
CHANGED
@@ -137,13 +137,13 @@ describe Hijacker do
|
|
137
137
|
]
|
138
138
|
|
139
139
|
DRbObject.should_receive(:new).with(nil, "druby://localhost:9999").and_return server
|
140
|
-
server.should_receive(:
|
140
|
+
server.should_receive(:handle).with *expected_args
|
141
141
|
|
142
142
|
Hijacker.register(:bar, [2, "string"], "retval", MyClass)
|
143
143
|
end
|
144
144
|
context "when given a particular DRb uri" do
|
145
145
|
it "sends the call to that uri" do
|
146
|
-
DRbObject.should_receive(:new).with(nil, "druby://localhost:1212").and_return mock('DRb server', :
|
146
|
+
DRbObject.should_receive(:new).with(nil, "druby://localhost:1212").and_return mock('DRb server', :handle => true)
|
147
147
|
Hijacker.register(:bar, [2, "string"], "retval", MyClass, "druby://localhost:1212")
|
148
148
|
end
|
149
149
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 0.0.2
|
9
|
+
version: 0.1.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-11-
|
17
|
+
date: 2010-11-21 00:00:00 +01:00
|
18
18
|
default_executable: hijacker
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -121,10 +121,12 @@ files:
|
|
121
121
|
- hijacker.gemspec
|
122
122
|
- lib/hijacker.rb
|
123
123
|
- lib/hijacker/config.rb
|
124
|
-
- lib/hijacker/
|
124
|
+
- lib/hijacker/handler.rb
|
125
|
+
- lib/hijacker/handlers/logger.rb
|
125
126
|
- lib/hijacker/version.rb
|
126
127
|
- spec/hijacker/config_spec.rb
|
127
|
-
- spec/hijacker/
|
128
|
+
- spec/hijacker/handler_spec.rb
|
129
|
+
- spec/hijacker/handlers/logger_spec.rb
|
128
130
|
- spec/hijacker_spec.rb
|
129
131
|
- spec/spec_helper.rb
|
130
132
|
has_rdoc: true
|
@@ -161,6 +163,7 @@ specification_version: 3
|
|
161
163
|
summary: Spy on your ruby objects and send their activity to a hijacker server anywhere through DRb
|
162
164
|
test_files:
|
163
165
|
- spec/hijacker/config_spec.rb
|
164
|
-
- spec/hijacker/
|
166
|
+
- spec/hijacker/handler_spec.rb
|
167
|
+
- spec/hijacker/handlers/logger_spec.rb
|
165
168
|
- spec/hijacker_spec.rb
|
166
169
|
- spec/spec_helper.rb
|