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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hijacker (0.0.1)
4
+ hijacker (0.1.0)
5
5
  trollop
6
6
 
7
7
  GEM
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. Useful for logging and those awfully hardcore
5
- debugging afternoons! There might be other uses to it, for sure. Just be
6
- creative :)
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
- And it will output the URI for this server. *Note this* and pass it to your
29
- configuration block!
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 --without-timestamps (don't show the timestamps)
34
- hijacker --without-classes (don't show the object classes)
35
- hijacker --port 1234 (spawn the server in port 1234 rather than 8787)
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 0.0.1 (c) 2010 Josep M. Bach"
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, Hijacker::Logger.new(opts)
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 + ANSI[:RESET]
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/logger'
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.log method, args, retval, object
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 log(method, args, retval, object)
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]
@@ -1,3 +1,3 @@
1
1
  module Hijacker
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -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
- describe "#log" do
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.log(*args)
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.log(*args)
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.log(*args)
80
+ logger.handle(*args)
72
81
 
73
82
  ["(Class)", "(Fixnum)", "(String)"].each do |str|
74
83
  out.string.should_not include(str)
@@ -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(:log).with *expected_args
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', :log => true)
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
- - 2
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-20 00:00:00 +01:00
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/logger.rb
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/logger_spec.rb
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/logger_spec.rb
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