event_hook 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +3 -0
- data/.autotest +23 -0
- data/History.txt +6 -0
- data/Manifest.txt +9 -0
- data/README.txt +64 -0
- data/Rakefile +15 -0
- data/bin/event_hook +3 -0
- data/demo.rb +58 -0
- data/lib/event_hook.rb +109 -0
- data/test/test_event_hook.rb +51 -0
- metadata +118 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
= event_hook
|
2
|
+
|
3
|
+
* http://rubyforge.org/projects/seattlerb
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Wraps rb_add_event_hook so you can write fast ruby event hook
|
8
|
+
processors w/o the speed penalty that comes with set_trace_func (sooo
|
9
|
+
sloooow!). Calls back into ruby so you don't have to write C.
|
10
|
+
|
11
|
+
% ruby demo.rb
|
12
|
+
# of iterations = 1000000
|
13
|
+
user system total real
|
14
|
+
null_time 0.120000 0.000000 0.120000 ( 0.125279)
|
15
|
+
ruby time 0.560000 0.000000 0.560000 ( 0.562834)
|
16
|
+
event hook 3.160000 0.010000 3.170000 ( 3.175361)
|
17
|
+
set_trace_func 34.530000 0.100000 34.630000 ( 34.942785)
|
18
|
+
|
19
|
+
== FEATURES/PROBLEMS:
|
20
|
+
|
21
|
+
* Simple subclass design. Override ::process and you're off.
|
22
|
+
* Filters on calls/returns to not bog down on extraneous events.
|
23
|
+
* Not sure why process needs to be a class method. Will fix eventually.
|
24
|
+
|
25
|
+
== SYNOPSIS:
|
26
|
+
|
27
|
+
class StupidTracer < EventHook
|
28
|
+
self.process(*args)
|
29
|
+
p args
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
== REQUIREMENTS:
|
34
|
+
|
35
|
+
* RubyInline
|
36
|
+
|
37
|
+
== INSTALL:
|
38
|
+
|
39
|
+
* sudo gem install event_hook
|
40
|
+
|
41
|
+
== LICENSE:
|
42
|
+
|
43
|
+
(The MIT License)
|
44
|
+
|
45
|
+
Copyright (c) 2009 Ryan Davis, Seattle.rb
|
46
|
+
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
48
|
+
a copy of this software and associated documentation files (the
|
49
|
+
'Software'), to deal in the Software without restriction, including
|
50
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
51
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
52
|
+
permit persons to whom the Software is furnished to do so, subject to
|
53
|
+
the following conditions:
|
54
|
+
|
55
|
+
The above copyright notice and this permission notice shall be
|
56
|
+
included in all copies or substantial portions of the Software.
|
57
|
+
|
58
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
59
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
61
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
62
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
63
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
64
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/event_hook.rb'
|
6
|
+
|
7
|
+
Hoe.new('event_hook', EventHook::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'seattlerb'
|
9
|
+
|
10
|
+
p.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
|
11
|
+
|
12
|
+
p.extra_deps << 'RubyInline'
|
13
|
+
end
|
14
|
+
|
15
|
+
# vim: syntax=Ruby
|
data/bin/event_hook
ADDED
data/demo.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
$: << 'lib'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'event_hook'
|
8
|
+
|
9
|
+
class Demo < EventHook
|
10
|
+
def self.process(*ignore)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call_a_method
|
14
|
+
a_method
|
15
|
+
end
|
16
|
+
|
17
|
+
def a_method
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
SET_TRACE_FUNC_PROC = proc { |e, f, l, m, b, c|
|
22
|
+
# do nothing
|
23
|
+
}
|
24
|
+
|
25
|
+
max = (ARGV.shift || 1_000_000).to_i
|
26
|
+
|
27
|
+
demo = Demo.instance
|
28
|
+
|
29
|
+
puts "# of iterations = #{max}"
|
30
|
+
Benchmark::bm(20) do |x|
|
31
|
+
x.report("null_time") do
|
32
|
+
for i in 0..max do
|
33
|
+
# do nothing
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
x.report("ruby time") do
|
38
|
+
for i in 0..max do
|
39
|
+
demo.call_a_method
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Demo.start_hook
|
44
|
+
x.report("event hook") do
|
45
|
+
for i in 0..max do
|
46
|
+
demo.call_a_method
|
47
|
+
end
|
48
|
+
end
|
49
|
+
Demo.stop_hook
|
50
|
+
|
51
|
+
set_trace_func SET_TRACE_FUNC_PROC
|
52
|
+
x.report("set_trace_func") do
|
53
|
+
for i in 0..max do
|
54
|
+
demo.call_a_method
|
55
|
+
end
|
56
|
+
end
|
57
|
+
set_trace_func nil
|
58
|
+
end
|
data/lib/event_hook.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'inline'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
class EventHook
|
5
|
+
VERSION = '1.0.0'
|
6
|
+
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
NONE = 0x00
|
10
|
+
LINE = 0x01
|
11
|
+
CLASS = 0x02
|
12
|
+
NND = 0x04
|
13
|
+
CALL = 0x08
|
14
|
+
RETURN = 0x10
|
15
|
+
CCALL = 0x20
|
16
|
+
CRETURN = 0x40
|
17
|
+
RAISE = 0x80
|
18
|
+
ALL = 0xff
|
19
|
+
|
20
|
+
##
|
21
|
+
# Ruby events that EventHook notifies you about.
|
22
|
+
|
23
|
+
EVENTS = {
|
24
|
+
LINE => :line,
|
25
|
+
CLASS => :class,
|
26
|
+
NND => :end,
|
27
|
+
CALL => :call,
|
28
|
+
RETURN => :return,
|
29
|
+
CCALL => :ccall,
|
30
|
+
CRETURN => :creturn,
|
31
|
+
RAISE => :raise,
|
32
|
+
}
|
33
|
+
|
34
|
+
def self.start_hook
|
35
|
+
self.instance.add_event_hook
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.stop_hook
|
39
|
+
self.instance.remove_event_hook
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Redefine me in a subclass. +args+ is [event_id, self, method, class].
|
44
|
+
|
45
|
+
def self.process(*args)
|
46
|
+
raise NotImplementedError, "subclass responsibility"
|
47
|
+
end
|
48
|
+
|
49
|
+
inline(:C) do |builder|
|
50
|
+
builder.add_type_converter("rb_event_t", '', '')
|
51
|
+
builder.add_type_converter("ID", '', '')
|
52
|
+
builder.add_type_converter("NODE *", '', '')
|
53
|
+
|
54
|
+
builder.include '<time.h>'
|
55
|
+
builder.include '"ruby.h"'
|
56
|
+
builder.include '"node.h"'
|
57
|
+
|
58
|
+
builder.prefix <<-'EOF'
|
59
|
+
static VALUE event_hook_klass = Qnil;
|
60
|
+
static ID method = 0;
|
61
|
+
static int in_event_hook = 0;
|
62
|
+
static VALUE argv[4];
|
63
|
+
EOF
|
64
|
+
|
65
|
+
builder.c_raw <<-'EOF'
|
66
|
+
static void
|
67
|
+
event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass) {
|
68
|
+
if (in_event_hook) return;
|
69
|
+
if (mid == ID_ALLOCATOR) return;
|
70
|
+
|
71
|
+
in_event_hook++;
|
72
|
+
|
73
|
+
if (NIL_P(event_hook_klass)) event_hook_klass = self;
|
74
|
+
if (method == 0) method = rb_intern("process");
|
75
|
+
|
76
|
+
if (klass) {
|
77
|
+
if (TYPE(klass) == T_ICLASS) {
|
78
|
+
klass = RBASIC(klass)->klass;
|
79
|
+
} else if (FL_TEST(klass, FL_SINGLETON)) {
|
80
|
+
klass = self;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
argv[0] = UINT2NUM(event);
|
85
|
+
argv[1] = self;
|
86
|
+
argv[2] = ID2SYM(mid);
|
87
|
+
argv[3] = klass;
|
88
|
+
|
89
|
+
rb_funcall2(event_hook_klass, method, 4, argv);
|
90
|
+
|
91
|
+
in_event_hook--;
|
92
|
+
}
|
93
|
+
EOF
|
94
|
+
|
95
|
+
builder.c <<-'EOF'
|
96
|
+
void add_event_hook() {
|
97
|
+
rb_add_event_hook(event_hook, RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
|
98
|
+
RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN);
|
99
|
+
}
|
100
|
+
EOF
|
101
|
+
|
102
|
+
builder.c <<-'EOF'
|
103
|
+
void remove_event_hook() {
|
104
|
+
rb_remove_event_hook(event_hook);
|
105
|
+
event_hook_klass = Qnil;
|
106
|
+
}
|
107
|
+
EOF
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "event_hook"
|
3
|
+
|
4
|
+
class Stupid < EventHook
|
5
|
+
@@log = []
|
6
|
+
|
7
|
+
def self.log
|
8
|
+
@@log
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.process(*a)
|
12
|
+
@@log << a
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestEventHook < Test::Unit::TestCase
|
17
|
+
def method_1
|
18
|
+
method_2
|
19
|
+
end
|
20
|
+
|
21
|
+
def method_2
|
22
|
+
method_3
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_3
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_sanity
|
29
|
+
Stupid.start_hook
|
30
|
+
method_1
|
31
|
+
Stupid.stop_hook
|
32
|
+
|
33
|
+
actual = Stupid.log.map { |id, obj, meth, klass|
|
34
|
+
[EventHook::EVENTS[id], klass, meth]
|
35
|
+
}
|
36
|
+
|
37
|
+
expected = [[:return, Stupid, :start_hook],
|
38
|
+
[:call, TestEventHook, :method_1],
|
39
|
+
[:call, TestEventHook, :method_2],
|
40
|
+
[:call, TestEventHook, :method_3],
|
41
|
+
[:return, TestEventHook, :method_3],
|
42
|
+
[:return, TestEventHook, :method_2],
|
43
|
+
[:return, TestEventHook, :method_1],
|
44
|
+
[:call, Stupid, :stop_hook],
|
45
|
+
[:call, Stupid, :instance],
|
46
|
+
[:return, Stupid, :instance],
|
47
|
+
[:ccall, EventHook, :remove_event_hook]]
|
48
|
+
|
49
|
+
assert_equal expected, actual
|
50
|
+
end
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: event_hook
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Davis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDPjCCAiagAwIBAgIBADANBgkqhkiG9w0BAQUFADBFMRMwEQYDVQQDDApyeWFu
|
14
|
+
ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
|
15
|
+
GRYDY29tMB4XDTA5MDMwNjE4NTMxNVoXDTEwMDMwNjE4NTMxNVowRTETMBEGA1UE
|
16
|
+
AwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS
|
17
|
+
JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda
|
18
|
+
b9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx
|
19
|
+
taCPaLmfYIaFcHHCSY4hYDJijRQkLxPeB3xbOfzfLoBDbjvx5JxgJxUjmGa7xhcT
|
20
|
+
oOvjtt5P8+GSK9zLzxQP0gVLS/D0FmoE44XuDr3iQkVS2ujU5zZL84mMNqNB1znh
|
21
|
+
GiadM9GHRaDiaxuX0cIUBj19T01mVE2iymf9I6bEsiayK/n6QujtyCbTWsAS9Rqt
|
22
|
+
qhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV
|
23
|
+
gBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
|
24
|
+
HQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBBQUAA4IB
|
25
|
+
AQAY59gYvDxqSqgC92nAP9P8dnGgfZgLxP237xS6XxFGJSghdz/nI6pusfCWKM8m
|
26
|
+
vzjjH2wUMSSf3tNudQ3rCGLf2epkcU13/rguI88wO6MrE0wi4ZqLQX+eZQFskJb/
|
27
|
+
w6x9W1ur8eR01s397LSMexySDBrJOh34cm2AlfKr/jokKCTwcM0OvVZnAutaovC0
|
28
|
+
l1SVZ0ecg88bsWHA0Yhh7NFxK1utWoIhtB6AFC/+trM0FQEB/jZkIS8SaNzn96Rl
|
29
|
+
n0sZEf77FLf5peR8TP/PtmIg7Cyqz23sLM4mCOoTGIy5OcZ8TdyiyINUHtb5ej/T
|
30
|
+
FBHgymkyj/AOSqKRIpXPhjC6
|
31
|
+
-----END CERTIFICATE-----
|
32
|
+
|
33
|
+
date: 2009-05-20 00:00:00 -07:00
|
34
|
+
default_executable:
|
35
|
+
dependencies:
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: RubyInline
|
38
|
+
type: :runtime
|
39
|
+
version_requirement:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
version:
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: hoe
|
48
|
+
type: :development
|
49
|
+
version_requirement:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.12.2
|
55
|
+
version:
|
56
|
+
description: |-
|
57
|
+
Wraps rb_add_event_hook so you can write fast ruby event hook
|
58
|
+
processors w/o the speed penalty that comes with set_trace_func (sooo
|
59
|
+
sloooow!). Calls back into ruby so you don't have to write C.
|
60
|
+
|
61
|
+
% ruby demo.rb
|
62
|
+
# of iterations = 1000000
|
63
|
+
user system total real
|
64
|
+
null_time 0.120000 0.000000 0.120000 ( 0.125279)
|
65
|
+
ruby time 0.560000 0.000000 0.560000 ( 0.562834)
|
66
|
+
event hook 3.160000 0.010000 3.170000 ( 3.175361)
|
67
|
+
set_trace_func 34.530000 0.100000 34.630000 ( 34.942785)
|
68
|
+
email:
|
69
|
+
- ryand-ruby@zenspider.com
|
70
|
+
executables:
|
71
|
+
- event_hook
|
72
|
+
extensions: []
|
73
|
+
|
74
|
+
extra_rdoc_files:
|
75
|
+
- History.txt
|
76
|
+
- Manifest.txt
|
77
|
+
- README.txt
|
78
|
+
files:
|
79
|
+
- .autotest
|
80
|
+
- History.txt
|
81
|
+
- Manifest.txt
|
82
|
+
- README.txt
|
83
|
+
- Rakefile
|
84
|
+
- bin/event_hook
|
85
|
+
- demo.rb
|
86
|
+
- lib/event_hook.rb
|
87
|
+
- test/test_event_hook.rb
|
88
|
+
has_rdoc: true
|
89
|
+
homepage: http://rubyforge.org/projects/seattlerb
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options:
|
94
|
+
- --main
|
95
|
+
- README.txt
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: "0"
|
103
|
+
version:
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: "0"
|
109
|
+
version:
|
110
|
+
requirements: []
|
111
|
+
|
112
|
+
rubyforge_project: seattlerb
|
113
|
+
rubygems_version: 1.3.2
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Wraps rb_add_event_hook so you can write fast ruby event hook processors w/o the speed penalty that comes with set_trace_func (sooo sloooow!)
|
117
|
+
test_files:
|
118
|
+
- test/test_event_hook.rb
|
metadata.gz.sig
ADDED
Binary file
|