remi-add_hook 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/README.rdoc +1 -0
- data/Rakefile +66 -0
- data/VERSION.yml +4 -0
- data/lib/add_hook.rb +68 -0
- data/spec/add_hook_spec.rb +45 -0
- data/spec/spec.opts +3 -0
- metadata +59 -0
data/README.rdoc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
see Object#add_hook
|
data/Rakefile
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |s|
|
9
|
+
s.name = 'add_hook'
|
10
|
+
s.summary = 'Easily add callbacks to any method'
|
11
|
+
s.email = 'remi@remitaylor.com'
|
12
|
+
s.homepage = 'http://github.com/remi/add_hook'
|
13
|
+
s.description = 'Easily add callbacks to any method'
|
14
|
+
s.authors = %w( remi )
|
15
|
+
s.files = FileList['[A-Z]*', '{lib,spec,bin,examples}/**/*']
|
16
|
+
# s.add_dependency 'person-gemname'
|
17
|
+
# s.executables << 'script'
|
18
|
+
# s.rubyforge_project = 'gemname'
|
19
|
+
# s.extra_rdoc_files = %w( README.rdoc )
|
20
|
+
end
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
23
|
+
end
|
24
|
+
|
25
|
+
Spec::Rake::SpecTask.new do |t|
|
26
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Run all examples with RCov"
|
30
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
31
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
32
|
+
t.rcov = true
|
33
|
+
end
|
34
|
+
|
35
|
+
# require 'hanna'
|
36
|
+
# require 'darkfish-rdoc'
|
37
|
+
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
rdoc.rdoc_dir = 'rdoc'
|
40
|
+
rdoc.title = 'add_hook'
|
41
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
42
|
+
# rdoc.options += ["--template=#{`allison --path`}"] # sudo gem install allison
|
43
|
+
# rdoc.options += %w( -f darkfish ) # sudo gem install darkfish-rdoc
|
44
|
+
# rdoc.options += %w( -T hanna ) # sudo gem install mislav-hanna
|
45
|
+
rdoc.options += %w( -m README.rdoc ) # the initial page displayed
|
46
|
+
rdoc.rdoc_files.include('README.rdoc')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'Confirm that gemspec is $SAFE'
|
51
|
+
task :safe do
|
52
|
+
require 'yaml'
|
53
|
+
require 'rubygems/specification'
|
54
|
+
data = File.read('add_hook.gemspec')
|
55
|
+
spec = nil
|
56
|
+
if data !~ %r{!ruby/object:Gem::Specification}
|
57
|
+
Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
|
58
|
+
else
|
59
|
+
spec = YAML.load(data)
|
60
|
+
end
|
61
|
+
spec.validate
|
62
|
+
puts spec
|
63
|
+
puts "OK"
|
64
|
+
end
|
65
|
+
|
66
|
+
task :default => :spec
|
data/VERSION.yml
ADDED
data/lib/add_hook.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
# Add as a callback to an instance method
|
4
|
+
#
|
5
|
+
# ==== Usage
|
6
|
+
#
|
7
|
+
# >> x = [1, 2]
|
8
|
+
# => [1, 2]
|
9
|
+
# >> x.add_hook(:<<){|the_array, *args| puts "called #{ the_array.inspect } << #{ args.inspect }" }
|
10
|
+
# => nil
|
11
|
+
# >> x << 'foo'
|
12
|
+
# called [1, 2] << ["foo"]
|
13
|
+
# => [1, 2, "foo"]
|
14
|
+
#
|
15
|
+
# ==== Parameters
|
16
|
+
# method_name<~to_s>::
|
17
|
+
# The name of the method to add a hook to
|
18
|
+
#
|
19
|
+
# &block::
|
20
|
+
# A block to run everytime the method gets called.
|
21
|
+
# The block is passed multiple arguments.
|
22
|
+
# The first argument is self, the instance that the method is being called on.
|
23
|
+
# The rest of the arguments are the arguments that were passed to the method.
|
24
|
+
#
|
25
|
+
def add_hook method_name, &block
|
26
|
+
|
27
|
+
# protect against infinite looping
|
28
|
+
return if method_name.to_s == 'add_hook'
|
29
|
+
|
30
|
+
# if we haven't hooked into any methods on this instance yet
|
31
|
+
# then we need to add a way to persist our hooked methods and callbacks
|
32
|
+
unless self.respond_to? :hooked_methods
|
33
|
+
|
34
|
+
# add some things to this particular object
|
35
|
+
class << self
|
36
|
+
attr_accessor :hooked_methods, :hooked_method_hooks
|
37
|
+
end
|
38
|
+
|
39
|
+
# initalize attributes
|
40
|
+
self.hooked_methods ||= { }
|
41
|
+
self.hooked_method_hooks ||= { }
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
# for now, assume this is an *instance method* that we're hooking
|
46
|
+
method = self.class.instance_method(method_name.to_s)
|
47
|
+
method_key = method_name.to_s + Time.now.to_s
|
48
|
+
|
49
|
+
if method
|
50
|
+
|
51
|
+
self.hooked_methods[ method_key ] = method # store the original method
|
52
|
+
self.hooked_method_hooks[ method_key ] = block # store the block to call
|
53
|
+
|
54
|
+
# using eval because define_method can't create
|
55
|
+
# a method that accepts a block
|
56
|
+
eval %{
|
57
|
+
def self.#{ method_name } *args #, &block
|
58
|
+
self.hooked_method_hooks[#{ method_key.inspect }].call(self, *args)
|
59
|
+
self.hooked_methods[#{ method_key.inspect }].bind(self).call(*args) # add block
|
60
|
+
end
|
61
|
+
}
|
62
|
+
|
63
|
+
else
|
64
|
+
raise "Cannot find method #{ method_name.inspect } to add hook to"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/add_hook'
|
2
|
+
|
3
|
+
def main_method first_arg, second_arg, *splat_of_args
|
4
|
+
end
|
5
|
+
|
6
|
+
describe Object, '#add_hook' do
|
7
|
+
|
8
|
+
it 'should be able to add a hook to an object in the main scope' do
|
9
|
+
times_called = 0
|
10
|
+
|
11
|
+
main_method 1, 2, 3, 4, 5
|
12
|
+
times_called.should == 0
|
13
|
+
|
14
|
+
add_hook(:main_method) do |obj, *args|
|
15
|
+
# puts "called main_method on #{ obj } with args: #{ args.inspect }"
|
16
|
+
times_called += 1
|
17
|
+
end
|
18
|
+
|
19
|
+
times_called.should == 0
|
20
|
+
main_method 1, 2, 3, 4, 5
|
21
|
+
times_called.should == 1
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should be able to add a hook to objects' do
|
25
|
+
object = []
|
26
|
+
times_called = 0
|
27
|
+
|
28
|
+
object << 'x'
|
29
|
+
times_called.should == 0
|
30
|
+
|
31
|
+
object.add_hook(:<<){|obj, *args| times_called += 1 }
|
32
|
+
|
33
|
+
object << 'x'
|
34
|
+
times_called.should == 1
|
35
|
+
|
36
|
+
object << 'x'
|
37
|
+
times_called.should == 2
|
38
|
+
|
39
|
+
# should not effect other arrays
|
40
|
+
object = []
|
41
|
+
object << 'x'
|
42
|
+
times_called.should == 2 # should still be 2
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/spec/spec.opts
ADDED
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: remi-add_hook
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- remi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-06 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Easily add callbacks to any method
|
17
|
+
email: remi@remitaylor.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- VERSION.yml
|
27
|
+
- README.rdoc
|
28
|
+
- lib/add_hook.rb
|
29
|
+
- spec/add_hook_spec.rb
|
30
|
+
- spec/spec.opts
|
31
|
+
has_rdoc: true
|
32
|
+
homepage: http://github.com/remi/add_hook
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options:
|
35
|
+
- --inline-source
|
36
|
+
- --charset=UTF-8
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.2.0
|
55
|
+
signing_key:
|
56
|
+
specification_version: 2
|
57
|
+
summary: Easily add callbacks to any method
|
58
|
+
test_files: []
|
59
|
+
|