hijacker 0.0.2 → 0.1.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/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
|