Permalink
Browse files

Conflicts

  • Loading branch information...
Josep M. Bach
Josep M. Bach committed Dec 5, 2010
2 parents b3bfaa0 + 78335c7 commit 3d04e2fa53e3fe9808751880386e7e2c05eb5bdf
View
@@ -0,0 +1,11 @@
+=== Version 0.2.0 / 2010-12-05
+
+* enhancements
+ * report blocks passed to hijacked methods as regular arguments
+ * report raised exceptions in hijacked methods
+ * automatically load custom handler classes in these paths:
+ * ./.hijacker/**/*.rb
+ * ~/.hijacker/**/*.rb
+
+* bug fixes
+ * fixed many issues with 1.8.7
View
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- hijacker (0.1.1)
+ hijacker (0.2.0)
trollop
GEM
View
@@ -16,7 +16,9 @@ creative! :)
(See the "Extending hijacker blabla" part below to know how to write your own
handlers)
-Hijacker is tested with Ruby 1.8.7, 1.9.2, JRuby 1.5.3 and Rubinius 1.1.
+Hijacker is tested with Ruby 1.8.7, 1.9.2, and JRuby 1.5.3. Unfortunately there
+are some issues with Rubinius, mostly due to the metaprogramming stuff, which I
+will definitely look into.
##Install and configure
@@ -44,6 +46,15 @@ So you type:
And it will output the URI for this super fancy hijacker logging server.
*Remember this URI* and pass it to your configuration block!
+If you have some custom handler, you should send me a pull request! In case you
+don't want to, Hijacker automatically requires all ruby files inside these
+paths:
+
+ ./.hijacker/**/**.rb
+ ~/.hijacker/**/**.rb
+
+So you put your handlers in there and have fun! :)
+
Some options you can pass to the server command:
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:
It is really easy to write your own handlers. Why don't you write one and send
me a pull request? I mean now. What are you waiting for, why are you still reading?
-Ok, maybe a bit of explanation on that. Handlers live here:
-
- lib/hijacker/handlers/your_handler.rb
+Ok, maybe a bit of explanation on that. Handlers are automatically loaded from
+here:
-They are autoloaded and automatically registered, so all you have to do is
-write them like this:
+ ./.hijacker/**/*.rb
+ ~/.hijacker/**/*.rb
+They are automatically registered, so all you have to do is write them like this:
module Hijacker
class MyHandler < Handler # Yes, you have to subclass Hijacker::Handler!
@@ -154,10 +165,14 @@ write them like this:
#
# args [{:inspect => '3', :class => 'Fixnum'},
# {:inspect => '"string"', :class => 'String'}]
+ #
+ # retval {:inspect => ':bar', :class => 'Symbol'}
+ # (note: retval will be nil if the method raised)
#
- # retval [{:inspect => ':bar', :class => 'Symbol'}]
+ # raised {:inspect => 'oops', :class => 'StandardError'}
+ # (note: raised will be nil unless the method raised, obviously)
#
- # object [{:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}]
+ # object {:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}
#
def handle(method, args, retval, object)
# Do what you want with these!
View
@@ -58,7 +58,7 @@ puts welcome.join("#{ANSI[:RESET]} ") + "\n"
# We need the uri of the service to connect a client
instructions = "Put this code in the configuration of your ruby program #{ANSI[:BOLD]}before any call to Hijacker#{ANSI[:RESET]}:\n\n"
-instructions += "\t" + "Hijacker.config do\n"
+instructions += "\t" + "Hijacker.configure do\n"
instructions += "\t" + " uri '#{DRb.uri}'\n"
instructions += "\t" + "end\n\n"
puts instructions
View
@@ -1,113 +1,34 @@
require 'drb'
require 'trollop'
+require 'hijacker/exceptions'
+require 'hijacker/method_definer'
+require 'hijacker/spy'
require 'hijacker/config'
require 'hijacker/handler'
module Hijacker
- # Methods that won't be hijacked in any case
- REJECTED_METHODS = (Object.instance_methods | Module.methods | %w{< <= > >= __original_[\w\d]+ [^\w\d]+})
- FORBIDDEN_CLASSES = [Array, Hash, String, Fixnum, Float, Numeric, Symbol, Proc, Class, Object, Module]
-
class << self
- def spying(*args, &block)
- raise "No block given" unless block
- Hijacker.spy(*args)
- block.call
- Hijacker.restore(args.first)
- end
-
- def spy(object, options = {})
- raise "Cannot spy on the following forbidden classes: #{FORBIDDEN_CLASSES.map(&:to_s).join(', ')}" if FORBIDDEN_CLASSES.include?(object)
- rejection = /^(#{REJECTED_METHODS.join('|')})/
- only = options[:only]
- uri = options[:uri]
- custom_rejection = options[:reject] if options[:reject].is_a?(Regexp)
-
- inst_methods = guess_instance_methods_from(object).reject{|m| (m =~ rejection)}.reject{|m| m =~ custom_rejection}
- sing_methods = guess_class_methods_from(object).reject{|m| m =~ rejection}.reject{|m| m =~ custom_rejection}
-
- receiver = if object.is_a?(Class)
- object
- else
- (class << object; self; end)
- end
-
- inst_methods.each do |met|
- receiver.send(:alias_method, :"__original_#{met}", :"#{met}")
- receiver.send(:undef_method, :"#{met}")
- receiver.class_eval <<EOS
- def #{met}(*args, &blk)
- __original_#{met}(*args,&blk).tap do |retval|
- Hijacker.register :#{met}, args, retval, self, #{uri.inspect}
- end
- end
-EOS
- end unless options[:only] == :singleton_methods
+ include MethodDefiner
+ private :define_hijacked
- receiver = (class << object; self; end)
- sing_methods.each do |met|
- receiver.send(:alias_method, :"__original_#{met}", :"#{met}")
- receiver.send(:undef_method, :"#{met}")
- receiver.class_eval <<EOS
- def #{met}(*args, &blk)
- __original_#{met}(*args,&blk).tap do |retval|
- Hijacker.register :#{met}, args, retval, self, #{uri.inspect}
- end
- end
-EOS
- end unless options[:only] == :instance_methods
+ include Spy
+ public :spy, :spying, :restore
- end
-
- def restore(object)
- receiver = if object.is_a?(Class)
- object
- else
- (class << object; self; end)
- end
- guess_instance_methods_from(object).select{|m| m =~ /__original_/}.each do |met|
- met = met.to_s.gsub!("__original_", "")
- receiver.send(:undef_method, :"#{met}")
- receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
- end
-
- receiver = (class << object; self; end)
- guess_class_methods_from(object).select{|m| m =~ /__original_/}.each do |met|
- met = met.to_s.gsub!("__original_", "")
- receiver.send(:undef_method, :"#{met}")
- receiver.send(:alias_method, :"#{met}", :"__original_#{met}")
- end
- end
-
- def register(method, args, retval, object, uri = nil)
+ def register(method, args, retval, raised, object, uri = nil)
args.map! do |arg|
{:inspect => arg.inspect, :class => arg.class.name}
end
- retval = {:inspect => retval.inspect, :class => retval.class.name}
- object = {:inspect => object.inspect, :class => object.class.name}
-
- server = DRbObject.new nil, (uri || self.drb_uri)
- server.handle method, args, retval, object
- end
-
- private
-
- def guess_instance_methods_from(object)
- if object.is_a?(Class)
- object.instance_methods
+ if raised
+ raised = {:inspect => raised.message, :class => raised.class.name}
else
- object.methods
+ retval = {:inspect => retval.inspect, :class => retval.class.name}
end
- end
+ object = {:inspect => object.inspect, :class => object.class.name}
- def guess_class_methods_from(object)
- if object.is_a?(Class)
- object.methods
- else
- []
- end
+ server = DRbObject.new nil, (uri || self.drb_uri)
+ server.handle method, args, retval, raised, object
end
end
View
@@ -11,8 +11,8 @@ def uri(drb)
def drb_uri
begin
@@drb_uri
- rescue
- raise "Neither a global nor a local Hijacker server URI is configured. Please refer to the README to find out how to do this."
+ rescue NameError
+ 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."
end
end
end
@@ -0,0 +1,3 @@
+module Hijacker
+ class UndefinedUriError < StandardError; end;
+end
View
@@ -21,17 +21,22 @@ def initialize(opts)
@opts = opts
end
- def handle(method, args, retval, object)
+ def handle(method, args, retval, raised, object)
# Parameters received
#
# method :foo
#
# args [{:inspect => '3', :class => 'Fixnum'},
# {:inspect => '"string"', :class => 'String'}]
#
- # retval [{:inspect => ':bar', :class => 'Symbol'}]
+ # retval {:inspect => ':bar', :class => 'Symbol'}
+ #
+ # - In case the method raised something, retval will be nil,
+ # and the exception info will be available in raised:
#
- # object [{:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}]
+ # raised {:inspect => 'wrong number of arguments (0 for 2)', :class => 'ArgumentError'}
+ #
+ # object {:inspect => '#<MyClass:0x003457>', :class => 'MyClass'}
#
raise NotImplementedError.new("You are supposed to subclass Handler")
end
@@ -52,7 +57,14 @@ def handlers
end
end
-# Automatically load all handlers
-Dir[File.dirname(File.join(File.dirname(__FILE__), 'handlers', '**', '*.rb'))].entries.each do |handler|
+# Automatically load all handlers in the following paths:
+#
+# ./.hijacker/**/*.rb
+# ~/.hijacker/**/*.rb
+# lib/handlers/**/*.rb
+#
+(Dir[File.dirname(File.join(Dir.pwd, '.hijacker', '**', '*.rb'))] + \
+Dir[File.dirname(File.expand_path(File.join('~', '.hijacker', '**', '*.rb')))] + \
+Dir[File.dirname(File.join(File.dirname(__FILE__), 'handlers', '**', '*.rb'))]).entries.each do |handler|
require(handler) && Hijacker::Handler.register_handler(handler)
end
@@ -18,7 +18,7 @@ def self.cli_options
:CYAN=>"\e[36m", :LCYAN=>"\e[1;36m",
:WHITE=>"\e[37m"}
- def handle(method, args, retval, object)
+ def handle(method, args, retval, raised, object)
out = []
out << ANSI[:BOLD] + ANSI[:UNDERLINE] + "#{Time.now}" unless opts[:without_timestamps]
out << ANSI[:CYAN] + object[:inspect]
@@ -32,10 +32,17 @@ def handle(method, args, retval, object)
ANSI[:RESET]
end.join(', ')
end
- out << "and returned"
- out << ANSI[:BLUE] + retval[:inspect]
- out << ANSI[:LBLUE] + "(#{retval[:class]})" unless opts[:without_classes]
- out << ANSI[:RESET] + "\n"
+ if raised
+ out << "and raised"
+ out << ANSI[:BLUE] + raised[:inspect]
+ out << ANSI[:LBLUE] + "(#{raised[:class]})" unless opts[:without_classes]
+ out << ANSI[:RESET] + "\n"
+ else
+ out << "and returned"
+ out << ANSI[:BLUE] + retval[:inspect]
+ out << ANSI[:LBLUE] + "(#{retval[:class]})" unless opts[:without_classes]
+ out << ANSI[:RESET] + "\n"
+ end
stdout.print out.join("#{ANSI[:RESET]} ")
end
@@ -0,0 +1,27 @@
+module Hijacker
+ module MethodDefiner
+
+ def define_hijacked(methods, receiver, uri)
+ methods.each do |met|
+ receiver.send(:alias_method, :"__original_#{met}", :"#{met}")
+ receiver.send(:undef_method, :"#{met}")
+ writer = (met =~ /=$/)
+ receiver.class_eval <<EOS
+ def #{met}(#{writer ? 'arg' : '*args, &blk'})
+ _args = #{writer ? '[arg]' : 'args'}
+ _args += [blk] if block_given?
+ begin
+ __original_#{met}(#{writer ? 'arg' : '*args, &blk'}).tap do |retval|
+ Hijacker.register :#{met}, _args, retval, nil, self, #{uri.inspect}
+ end
+ rescue=>error
+ Hijacker.register :#{met}, _args, nil, error, self, #{uri.inspect}
+ raise error
+ end
+ end
+EOS
+ end
+ end
+
+ end
+end
Oops, something went wrong.

0 comments on commit 3d04e2f

Please sign in to comment.