hijacker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ *.rbc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format documentation
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use ruby-1.9.2@hijacker
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in hijacker.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,48 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hijacker (0.0.1)
5
+ trollop
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ configuration (1.2.0)
11
+ diff-lcs (1.1.2)
12
+ guard (0.2.2)
13
+ open_gem (~> 1.4.2)
14
+ thor (~> 0.14.3)
15
+ guard-rspec (0.1.8)
16
+ guard (>= 0.2.0)
17
+ launchy (0.3.7)
18
+ configuration (>= 0.0.5)
19
+ rake (>= 0.8.1)
20
+ open_gem (1.4.2)
21
+ launchy (~> 0.3.5)
22
+ rake (0.8.7)
23
+ rspec (2.1.0)
24
+ rspec-core (~> 2.1.0)
25
+ rspec-expectations (~> 2.1.0)
26
+ rspec-mocks (~> 2.1.0)
27
+ rspec-core (2.1.0)
28
+ rspec-expectations (2.1.0)
29
+ diff-lcs (~> 1.1.2)
30
+ rspec-mocks (2.1.0)
31
+ simplecov (0.3.7)
32
+ simplecov-html (>= 0.3.7)
33
+ simplecov-html (0.3.9)
34
+ thor (0.14.4)
35
+ trollop (1.16.2)
36
+
37
+ PLATFORMS
38
+ java
39
+ ruby
40
+
41
+ DEPENDENCIES
42
+ bundler (~> 1.0.7)
43
+ guard
44
+ guard-rspec
45
+ hijacker!
46
+ rspec (~> 2.1.0)
47
+ simplecov
48
+ trollop
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at http://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch('^spec/(.*)_spec.rb')
6
+ watch('^lib/(.*)\.rb') { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('^spec/spec_helper.rb') { "spec" }
8
+ end
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+ task :default => :spec
data/Readme.md ADDED
@@ -0,0 +1,114 @@
1
+ #hijacker
2
+
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 :)
7
+
8
+ Hijacker is tested with Ruby 1.8.7, 1.9.2, JRuby 1.5.3 and Rubinius 1.1.
9
+
10
+ ##Install and configure
11
+
12
+ In your Gemfile:
13
+
14
+ gem 'hijacker'
15
+
16
+ If you are using Rails, you might want to put this configuration snippet in an
17
+ initializer or something (you can always put it in any other part of the code
18
+ otherwise, as long as it's before hijacking any object):
19
+
20
+ Hijacker.configure do
21
+ uri '<YOUR HIJACKER SERVER URI>'
22
+ end
23
+
24
+ And that's it! Oooor not. You have to spawn your server. In the command line:
25
+
26
+ hijacker
27
+
28
+ And it will output the URI for this server. *Note this* and pass it to your
29
+ configuration block!
30
+
31
+ Some options you can pass to the server command:
32
+
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)
36
+
37
+ ##Ok, and now for some hijacking action!
38
+
39
+ require 'hijacker' # You don't have to when using Bundler :)
40
+
41
+ class MyClass
42
+ def foo(bar, baz)
43
+ bar + baz
44
+ end
45
+ end
46
+
47
+ some_object = Object.new
48
+
49
+ # These are the important lines:
50
+
51
+ Hijacker.spy(some_object)
52
+ Hijacker.spy(MyClass)
53
+
54
+ instance = MyClass.new
55
+ instance.foo(3, 4)
56
+
57
+ Run this code and, if you look at the server output, you'll see nothing less
58
+ than...
59
+
60
+ <a nice timestamp> MyClass (Class) received :new and returned #<MyClass:0x000000874> (MyClass)
61
+ <a nice timestamp> #<MyClass:0x000000874> (MyClass) received :foo with 3
62
+ (Fixnum), 4 (Fixnum) and returned 7
63
+
64
+ If you want to un-hijack any object, just call #restore:
65
+
66
+ Hijacker.restore(MyClass)
67
+ Hijacker.restore(some_object)
68
+
69
+ If you don't want to have to remember every hijacked object you have to call
70
+ restore on it, you can just spy a particular object within the duration of a block:
71
+
72
+ Hijacker.spying(MyClass) do
73
+ # inside this block, MyClass will be spied
74
+ end
75
+ # here not anymore
76
+
77
+ Awesome! You can fine-tune your spying, for example by only spying on instance
78
+ methods or singleton methods only:
79
+
80
+ Hijacker.spy(MyClass, :only => :instance_methods) # or :singleton_methods
81
+
82
+ And, last but not least... you can specify a *particular hijacker server* for
83
+ a *particular object* you are spying on!
84
+
85
+ # All activity on MyClass and its instances will
86
+ # be sent to druby://localhost:9999
87
+ Hijacker.spy(MyClass, :uri => 'druby://localhost:9999')
88
+
89
+ # But for example, the activity of some_object will
90
+ # be sent to the default uri specified in the configuration
91
+ # back earlier (remember?)
92
+ Hijacker.spy(some_object)
93
+
94
+ Of course, you can specify a particular server uri for a block, with #spying:
95
+
96
+ Hijacker.spying(foo_object, :uri => 'druby://localhost:1234') do
97
+ # all the activity of foo_object inside this block
98
+ # will be sent to the hijacker server on druby://localhost:1234
99
+ end
100
+
101
+ ##Note on Patches/Pull Requests
102
+
103
+ * Fork the project.
104
+ * Make your feature addition or bug fix.
105
+ * Add specs for it. This is important so I don't break it in a
106
+ future version unintentionally.
107
+ * Commit, do not mess with rakefile, version, or history.
108
+ If you want to have your own version, that is fine but bump version
109
+ in a commit by itself I can ignore when I pull.
110
+ * Send me a pull request. Bonus points for topic branches.
111
+
112
+ ## Copyright
113
+
114
+ Copyright (c) 2010 Josep M. Bach. See LICENSE for details.
data/bin/hijacker ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby -w
2
+ # hijacker server
3
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'hijacker'
6
+
7
+ opts = Trollop::options do
8
+ version "hijacker 0.0.1 (c) 2010 Josep M. Bach"
9
+ banner <<-EOS
10
+ Hijacker server listens for reports by hijackers spying on ruby objects.
11
+
12
+ Usage:
13
+ hijacker [options]
14
+ where [options] are:
15
+ EOS
16
+ opt :without_classes, "Don't show classes of objects"
17
+ opt :without_timestamps, "Don't show timestamps"
18
+ opt :port, "DRb port to use (default is 8787)", :default => 8787
19
+ end
20
+
21
+ begin
22
+ raise unless opts[:port].to_i > 0 && opts[:port].to_i < 9999
23
+ rescue
24
+ Trollop::die :port, "must be a valid number between 0 and 9999"
25
+ end
26
+
27
+ DRB_URI="druby://localhost:#{opts[:port]}"
28
+
29
+ # Start up the DRb service
30
+ DRb.start_service DRB_URI, Hijacker::Logger.new(opts)
31
+
32
+ ANSI = Hijacker::Logger::ANSI
33
+ # We need the uri of the service to connect a client
34
+ welcome = []
35
+ welcome << ANSI[:BOLD] + "hijacker server"
36
+ welcome << "listening on"
37
+ welcome << ANSI[:BOLD] + DRb.uri + ANSI[:RESET]
38
+ puts welcome.join("#{ANSI[:RESET]} ") + "\n"
39
+
40
+ # We need the uri of the service to connect a client
41
+ instructions = "Put this code in the configuration of your ruby program #{ANSI[:BOLD]}before any call to Hijacker#{ANSI[:RESET]}:\n\n"
42
+ instructions += "\t" + "Hijacker.config do\n"
43
+ instructions += "\t" + " uri '#{DRb.uri}'\n"
44
+ instructions += "\t" + "end\n\n"
45
+ puts instructions
46
+ instructions = "Or optionally attach a particular hijacked object to this server adding :uri => '#{DRb.uri}' when calling Hijacker's :spy or :spying method.\n\n"
47
+ puts instructions
48
+
49
+ # wait for the DRb service to finish before exiting
50
+ DRb.thread.join
data/hijacker.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "hijacker/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "hijacker"
7
+ s.version = Hijacker::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Josep M. Bach"]
10
+ s.email = ["josep.m.bach@gmail.com"]
11
+ s.homepage = "http://github.com/txus/hijacker"
12
+ s.summary = %q{Spy on your ruby objects and send their activity to a hijacker server anywhere through DRb}
13
+ s.description = %q{Spy on your ruby objects and send their activity to a hijacker server anywhere through DRb}
14
+
15
+ s.rubyforge_project = "hijacker"
16
+
17
+ s.add_runtime_dependency 'trollop'
18
+ s.default_executable = "hijacker"
19
+
20
+ s.add_development_dependency 'bundler', '~> 1.0.7'
21
+ s.add_development_dependency 'rspec', '~> 2.1.0'
22
+ s.add_development_dependency 'guard'
23
+ s.add_development_dependency 'guard-rspec'
24
+ s.add_development_dependency "simplecov"
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
+ s.require_paths = ["lib"]
30
+ end
@@ -0,0 +1,19 @@
1
+ module Hijacker
2
+ class << self
3
+ def configure(&block)
4
+ self.instance_eval(&block)
5
+ end
6
+
7
+ def uri(drb)
8
+ @@drb_uri = drb
9
+ end
10
+
11
+ def drb_uri
12
+ begin
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."
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,53 @@
1
+ module Hijacker
2
+ class Logger
3
+
4
+ ANSI = {:RESET=>"\e[0m", :BOLD=>"\e[1m", :UNDERLINE=>"\e[4m",
5
+ :LGRAY=>"\e[0;37m", :GRAY=>"\e[1;30m",
6
+ :RED=>"\e[31m",
7
+ :GREEN=>"\e[32m", :LGREEN=>"\e[1;32m",
8
+ :YELLOW=>"\e[33m",
9
+ :BLUE=>"\e[34m", :LBLUE=>"\e[1;34m",
10
+ :PURPLE=>"\e[35m", :LPURPLE=>"\e[1;35m",
11
+ :CYAN=>"\e[36m", :LCYAN=>"\e[1;36m",
12
+ :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
+
24
+ def log(method, args, retval, object)
25
+ out = []
26
+ out << ANSI[:BOLD] + ANSI[:UNDERLINE] + "#{Time.now}" unless opts[:without_timestamps]
27
+ out << ANSI[:CYAN] + object[:inspect]
28
+ out << ANSI[:LCYAN] + "(#{object[:class]})" unless opts[:without_classes]
29
+ out << "received"
30
+ out << ANSI[:RED] + ":#{method}"
31
+ unless args.empty?
32
+ out << "with"
33
+ out << args.map do |arg|
34
+ ANSI[:GREEN] + arg[:inspect] + ANSI[:LGREEN] + (opts[:without_classes] ? "" : " (#{arg[:class]})") +
35
+ ANSI[:RESET]
36
+ end.join(', ')
37
+ end
38
+ out << "and returned"
39
+ out << ANSI[:BLUE] + retval[:inspect]
40
+ out << ANSI[:LBLUE] + "(#{retval[:class]})" unless opts[:without_classes]
41
+ out << ANSI[:RESET] + "\n"
42
+ stdout.print out.join("#{ANSI[:RESET]} ")
43
+ end
44
+
45
+ private
46
+
47
+ def stdout
48
+ $stdout
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,3 @@
1
+ module Hijacker
2
+ VERSION = "0.0.1"
3
+ end
data/lib/hijacker.rb ADDED
@@ -0,0 +1,116 @@
1
+ require 'drb'
2
+ require 'trollop'
3
+ require 'hijacker/config'
4
+ require 'hijacker/logger'
5
+
6
+ module Hijacker
7
+
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
+ class << self
13
+
14
+ def spying(*args, &block)
15
+ raise "No block given" unless block
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.dup, #{uri.inspect}
44
+ end
45
+ end
46
+ EOS
47
+ end unless options[:only] == :singleton_methods
48
+
49
+ receiver = (class << object; self; end)
50
+ sing_methods.each do |met|
51
+ puts "Defining #{met}"
52
+ receiver.send(:alias_method, :"__original_#{met}", :"#{met}")
53
+ receiver.send(:undef_method, :"#{met}")
54
+ receiver.class_eval <<EOS
55
+ def #{met}(*args, &blk)
56
+ __original_#{met}(*args,&blk).tap do |retval|
57
+ Hijacker.register :#{met}, args, retval, self.dup, #{uri.inspect}
58
+ end
59
+ end
60
+ EOS
61
+ end unless options[:only] == :instance_methods
62
+
63
+ end
64
+
65
+ def restore(object)
66
+ receiver = if object.is_a?(Class)
67
+ object
68
+ else
69
+ (class << object; self; end)
70
+ end
71
+ guess_instance_methods_from(object).select{|m| m =~ /__original_/}.each do |met|
72
+ met = met.to_s.gsub!("__original_", "")
73
+ receiver.send(:undef_method, :"#{met}")
74
+ receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
75
+ end
76
+
77
+ receiver = (class << object; self; end)
78
+ guess_class_methods_from(object).select{|m| m =~ /__original_/}.each do |met|
79
+ met = met.to_s.gsub!("__original_", "")
80
+ receiver.send(:undef_method, :"#{met}")
81
+ receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
82
+ end
83
+ end
84
+
85
+ def register(method, args, retval, object, uri = nil)
86
+ args.map! do |arg|
87
+ {:inspect => arg.inspect, :class => arg.class.name}
88
+ end
89
+ retval = {:inspect => retval.inspect, :class => retval.class.name}
90
+ object = {:inspect => object.inspect, :class => object.class.name}
91
+
92
+ server = DRbObject.new nil, (uri || self.drb_uri)
93
+ server.log method, args, retval, object
94
+ end
95
+
96
+ private
97
+
98
+ def guess_instance_methods_from(object)
99
+ if object.is_a?(Class)
100
+ object.instance_methods
101
+ else
102
+ object.methods
103
+ end
104
+ end
105
+
106
+ def guess_class_methods_from(object)
107
+ if object.is_a?(Class)
108
+ object.methods
109
+ else
110
+ []
111
+ end
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hijacker, "configuration" do
4
+
5
+ describe "#configure" do
6
+ it 'accepts a block with the \'uri\' configuration option' do
7
+ Hijacker.configure do
8
+ uri 'druby://localhost:8787'
9
+ end
10
+ Hijacker.drb_uri.should == 'druby://localhost:8787'
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ module Hijacker
4
+ describe Logger do
5
+
6
+ subject { Logger.new({:my => :option}) }
7
+
8
+ it "initializes with options" do
9
+ subject.opts.should == {:my => :option}
10
+ end
11
+
12
+ describe "#log" 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 'prints the received args' do
25
+ out = StringIO.new
26
+ subject.stub(:stdout).and_return out
27
+
28
+ Time.stub(:now).and_return Time.parse('2010-11-20')
29
+
30
+ subject.log(*args)
31
+
32
+ ["00:00:00 +0100",
33
+ "MyClass",
34
+ "(Class)",
35
+ "received",
36
+ ":bar",
37
+ "with",
38
+ "2",
39
+ "(Fixnum)",
40
+ "\"string\"",
41
+ "(String)",
42
+ "and returned",
43
+ "\"retval\"",
44
+ "(String)"].each do |str|
45
+ out.string.should include(str)
46
+ end
47
+ end
48
+ context "when given :without_timestamps" do
49
+ it 'discards the timestamps' do
50
+ logger = Logger.new({:without_timestamps => true})
51
+
52
+ out = StringIO.new
53
+ logger.stub(:stdout).and_return out
54
+
55
+ Time.stub(:now).and_return Time.parse('2010-11-20')
56
+
57
+ logger.log(*args)
58
+
59
+ out.string.should_not include("2010-11-20")
60
+ end
61
+ end
62
+ context "when given :without_classes" do
63
+ it 'discards the classes' do
64
+ logger = Logger.new({:without_classes => true})
65
+
66
+ out = StringIO.new
67
+ logger.stub(:stdout).and_return out
68
+
69
+ Time.stub(:now).and_return Time.parse('2010-11-20')
70
+
71
+ logger.log(*args)
72
+
73
+ ["(Class)", "(Fixnum)", "(String)"].each do |str|
74
+ out.string.should_not include(str)
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,152 @@
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
+ 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
+
33
+ it 'raises if no block given' do
34
+ expect {
35
+ Hijacker.spying(MyClass)
36
+ }.to raise_error("No block given")
37
+ end
38
+ end
39
+
40
+ describe "#spy - #restore" do
41
+
42
+ describe "hijacking a Class" do
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
101
+
102
+ object.foo.should == 7
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
108
+
109
+ object.bar(2, "string").should == "string"
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
123
+
124
+ describe "#register" do
125
+ it 'sends the registered method call to the DRb server' do
126
+ server = mock('DRb server')
127
+
128
+ Hijacker.stub(:drb_uri).and_return "druby://localhost:9999"
129
+
130
+ expected_args = [:bar,
131
+ [
132
+ {:inspect => "2", :class => "Fixnum"},
133
+ {:inspect => "\"string\"", :class => "String"},
134
+ ],
135
+ {:inspect => "\"retval\"", :class => "String"},
136
+ {:inspect => "MyClass", :class => "Class"}
137
+ ]
138
+
139
+ DRbObject.should_receive(:new).with(nil, "druby://localhost:9999").and_return server
140
+ server.should_receive(:log).with *expected_args
141
+
142
+ Hijacker.register(:bar, [2, "string"], "retval", MyClass)
143
+ end
144
+ context "when given a particular DRb uri" do
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)
147
+ Hijacker.register(:bar, [2, "string"], "retval", MyClass, "druby://localhost:1212")
148
+ end
149
+ end
150
+ end
151
+
152
+ end
@@ -0,0 +1,17 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
+
12
+ require 'hijacker'
13
+ require 'rspec'
14
+
15
+ # Requires supporting files with custom matchers and macros, etc,
16
+ # in ./support/ and its subdirectories.
17
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hijacker
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Josep M. Bach
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-20 00:00:00 +01:00
18
+ default_executable: hijacker
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: trollop
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 0
44
+ - 7
45
+ version: 1.0.7
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 2
58
+ - 1
59
+ - 0
60
+ version: 2.1.0
61
+ type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: guard
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: guard-rspec
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ type: :development
88
+ version_requirements: *id005
89
+ - !ruby/object:Gem::Dependency
90
+ name: simplecov
91
+ prerelease: false
92
+ requirement: &id006 !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ type: :development
101
+ version_requirements: *id006
102
+ description: Spy on your ruby objects and send their activity to a hijacker server anywhere through DRb
103
+ email:
104
+ - josep.m.bach@gmail.com
105
+ executables:
106
+ - hijacker
107
+ extensions: []
108
+
109
+ extra_rdoc_files: []
110
+
111
+ files:
112
+ - .gitignore
113
+ - .rspec
114
+ - .rvmrc
115
+ - Gemfile
116
+ - Gemfile.lock
117
+ - Guardfile
118
+ - Rakefile
119
+ - Readme.md
120
+ - bin/hijacker
121
+ - hijacker.gemspec
122
+ - lib/hijacker.rb
123
+ - lib/hijacker/config.rb
124
+ - lib/hijacker/logger.rb
125
+ - lib/hijacker/version.rb
126
+ - spec/hijacker/config_spec.rb
127
+ - spec/hijacker/logger_spec.rb
128
+ - spec/hijacker_spec.rb
129
+ - spec/spec_helper.rb
130
+ has_rdoc: true
131
+ homepage: http://github.com/txus/hijacker
132
+ licenses: []
133
+
134
+ post_install_message:
135
+ rdoc_options: []
136
+
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ segments:
153
+ - 0
154
+ version: "0"
155
+ requirements: []
156
+
157
+ rubyforge_project: hijacker
158
+ rubygems_version: 1.3.7
159
+ signing_key:
160
+ specification_version: 3
161
+ summary: Spy on your ruby objects and send their activity to a hijacker server anywhere through DRb
162
+ test_files:
163
+ - spec/hijacker/config_spec.rb
164
+ - spec/hijacker/logger_spec.rb
165
+ - spec/hijacker_spec.rb
166
+ - spec/spec_helper.rb