ruby-breakpoint 0.5.0 → 0.5.1
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/Manifest +38 -35
- data/NEWS +14 -0
- data/README +4 -4
- data/TODO +4 -0
- data/bin/breakpoint_client +1 -212
- data/doc/classes/Binding.html +237 -220
- data/doc/classes/Breakpoint.html +552 -539
- data/doc/classes/Breakpoint/CommandBundle.html +206 -206
- data/doc/classes/Breakpoint/CommandBundle/Client.html +232 -200
- data/doc/classes/Breakpoint/FailedAssertError.html +117 -117
- data/doc/classes/Handlers.html +230 -0
- data/doc/created.rid +1 -1
- data/doc/files/COPYING.html +162 -162
- data/doc/files/NEWS.html +168 -134
- data/doc/files/README.html +154 -153
- data/doc/files/TODO.html +166 -161
- data/doc/files/lib/binding_of_caller_rb.html +100 -100
- data/doc/files/lib/breakpoint_client_rb.html +131 -0
- data/doc/files/lib/breakpoint_rb.html +201 -201
- data/doc/fr_class_index.html +31 -30
- data/doc/fr_file_index.html +32 -31
- data/doc/fr_method_index.html +41 -37
- data/doc/index.html +23 -23
- data/doc/rdoc-style.css +207 -207
- data/lib/binding_of_caller.rb +16 -2
- data/lib/breakpoint.rb +34 -7
- data/lib/breakpoint_client.rb +214 -0
- metadata +63 -57
data/Manifest
CHANGED
@@ -1,35 +1,38 @@
|
|
1
|
-
bin
|
2
|
-
COPYING
|
3
|
-
doc
|
4
|
-
GPL
|
5
|
-
lib
|
6
|
-
Manifest
|
7
|
-
NEWS
|
8
|
-
README
|
9
|
-
setup.rb
|
10
|
-
TODO
|
11
|
-
bin/breakpoint_client
|
12
|
-
doc/classes
|
13
|
-
doc/created.rid
|
14
|
-
doc/files
|
15
|
-
doc/fr_class_index.html
|
16
|
-
doc/fr_file_index.html
|
17
|
-
doc/fr_method_index.html
|
18
|
-
doc/index.html
|
19
|
-
doc/rdoc-style.css
|
20
|
-
doc/classes/Binding.html
|
21
|
-
doc/classes/Breakpoint
|
22
|
-
doc/classes/Breakpoint.html
|
23
|
-
doc/classes/
|
24
|
-
doc/classes/Breakpoint/CommandBundle
|
25
|
-
doc/classes/Breakpoint/
|
26
|
-
doc/classes/Breakpoint/
|
27
|
-
doc/
|
28
|
-
doc/files/
|
29
|
-
doc/files/
|
30
|
-
doc/files/
|
31
|
-
doc/files/
|
32
|
-
doc/files/
|
33
|
-
doc/files/lib/
|
34
|
-
lib/
|
35
|
-
lib/
|
1
|
+
bin
|
2
|
+
COPYING
|
3
|
+
doc
|
4
|
+
GPL
|
5
|
+
lib
|
6
|
+
Manifest
|
7
|
+
NEWS
|
8
|
+
README
|
9
|
+
setup.rb
|
10
|
+
TODO
|
11
|
+
bin/breakpoint_client
|
12
|
+
doc/classes
|
13
|
+
doc/created.rid
|
14
|
+
doc/files
|
15
|
+
doc/fr_class_index.html
|
16
|
+
doc/fr_file_index.html
|
17
|
+
doc/fr_method_index.html
|
18
|
+
doc/index.html
|
19
|
+
doc/rdoc-style.css
|
20
|
+
doc/classes/Binding.html
|
21
|
+
doc/classes/Breakpoint
|
22
|
+
doc/classes/Breakpoint.html
|
23
|
+
doc/classes/Handlers.html
|
24
|
+
doc/classes/Breakpoint/CommandBundle
|
25
|
+
doc/classes/Breakpoint/CommandBundle.html
|
26
|
+
doc/classes/Breakpoint/FailedAssertError.html
|
27
|
+
doc/classes/Breakpoint/CommandBundle/Client.html
|
28
|
+
doc/files/COPYING.html
|
29
|
+
doc/files/lib
|
30
|
+
doc/files/NEWS.html
|
31
|
+
doc/files/README.html
|
32
|
+
doc/files/TODO.html
|
33
|
+
doc/files/lib/binding_of_caller_rb.html
|
34
|
+
doc/files/lib/breakpoint_client_rb.html
|
35
|
+
doc/files/lib/breakpoint_rb.html
|
36
|
+
lib/binding_of_caller.rb
|
37
|
+
lib/breakpoint.rb
|
38
|
+
lib/breakpoint_client.rb
|
data/NEWS
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
|
3
3
|
This file sums up important changes that happened between releases.
|
4
4
|
|
5
|
+
== ruby-breakpoint 0.5.1
|
6
|
+
* Moved functionality of bin/breakpoint_client to lib/breakpoint_client.rb and
|
7
|
+
changed it so that it will respect previously set Options. (Should make it
|
8
|
+
easier for other libraries to integrate ruby-breakpoint with custom options.)
|
9
|
+
* Fixed trouble with .irbrc on remote breakpoint server when calling
|
10
|
+
DRb.activate_drb (see http://dev.rubyonrails.com/ticket/803)
|
11
|
+
* Fixed client.y not working (Need to undef DRbObject#to_yaml)
|
12
|
+
* Fixed client << 5 and similar not working
|
13
|
+
* Fixed client.require not working with some RubyGems versions
|
14
|
+
* WorkSpace#evaluate no longer extends strings and numerics with DRbUndumped
|
15
|
+
(Works around "DRb::DRbObject#to_str should return String" style bugs)
|
16
|
+
* Documented bug in Binding.of_caller() that causes Breakpoint.breakpoint()
|
17
|
+
to have a wrong object context. breakpoint() works correctly.
|
18
|
+
|
5
19
|
== ruby-breakpoint 0.5.0
|
6
20
|
* breakpoint_client has better logic for guessing the client-uri automatically.
|
7
21
|
This ought to fix connection errors that were happening because the client
|
data/README
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
= ruby-breakpoint 0.5.
|
1
|
+
= ruby-breakpoint 0.5.1 README
|
2
2
|
|
3
3
|
ruby-breakpoint lets you inspect and modify state at run time. This allows you
|
4
|
-
to diagnose bugs, patch
|
5
4
|
applications and more all via IRB by simply doing a
|
5
|
+
to diagnose bugs, patch applications and more all via IRB by simply doing a
|
6
6
|
method call at the place you want to investigate.
|
7
7
|
|
8
8
|
ruby-breakpoint is integrated into the popular RubyOnRails and Nitro web
|
@@ -28,9 +28,9 @@ De-compress archive and enter its top directory. Then type:
|
|
28
28
|
($ su)
|
29
29
|
# ruby setup.rb
|
30
30
|
|
31
|
-
|
31
|
+
This simple step installs this program under the default location of Ruby
|
32
32
|
libraries. You can also install files into your favorite directory by supplying
|
33
|
-
setup.rb some options. Try "ruby setup.rb --help".
|
33
|
+
setup.rb with some options. Try "ruby setup.rb --help".
|
34
34
|
|
35
35
|
|
36
36
|
== License
|
data/TODO
CHANGED
@@ -5,6 +5,10 @@
|
|
5
5
|
when DRb is not available. (E.g. on Debian)
|
6
6
|
|
7
7
|
= Done
|
8
|
+
|
9
|
+
* breakpoint_client ought to handle the case that Options is already defined
|
10
|
+
so that RubyOnRails and other frameworks that might want to ship
|
11
|
+
ruby-breakpoint directly can overwrite the default options easily.
|
8
12
|
|
9
13
|
* Do further research on the write SecurityError.
|
10
14
|
See ruby-core for more information.
|
data/bin/breakpoint_client
CHANGED
@@ -1,214 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'optparse'
|
5
|
-
require 'timeout'
|
6
|
-
require 'tmpdir'
|
7
|
-
|
8
|
-
Options = {
|
9
|
-
:ClientURI => nil,
|
10
|
-
:ServerURI => "druby://localhost:42531",
|
11
|
-
:RetryDelay => 3,
|
12
|
-
:Permanent => false,
|
13
|
-
:Verbose => false
|
14
|
-
}
|
15
|
-
|
16
|
-
ARGV.options do |opts|
|
17
|
-
script_name = File.basename($0)
|
18
|
-
opts.banner = [
|
19
|
-
"Usage: ruby #{script_name} [Options] [server uri]",
|
20
|
-
"",
|
21
|
-
"This tool lets you connect to a breakpoint service ",
|
22
|
-
"which was started via Breakpoint.activate_drb.",
|
23
|
-
"",
|
24
|
-
"The server uri defaults to druby://localhost:42531",
|
25
|
-
"",
|
26
|
-
"Having trouble or need help?",
|
27
|
-
"* Homepage: http://ruby-breakpoint.rubyforge.org/ (has FAQ!)",
|
28
|
-
"* Author: Florian Gross, flgr@ccan.de (Read homepage first!)"
|
29
|
-
].join("\n")
|
30
|
-
|
31
|
-
opts.separator ""
|
32
|
-
|
33
|
-
opts.on("-c", "--client-uri=uri",
|
34
|
-
"Run the client on the specified uri.",
|
35
|
-
"This can be used to specify the port",
|
36
|
-
"that the client uses to allow for back",
|
37
|
-
"connections from the server.",
|
38
|
-
"Default: Find a good URI automatically.",
|
39
|
-
"Example: -c druby://localhost:12345"
|
40
|
-
) { |Options[:ClientURI]| }
|
41
|
-
|
42
|
-
opts.on("-s", "--server-uri=uri",
|
43
|
-
"Connect to the server specified at the",
|
44
|
-
"specified uri.",
|
45
|
-
"Default: druby://localhost:42531"
|
46
|
-
) { |Options[:ServerURI]| }
|
47
|
-
|
48
|
-
opts.on("-R", "--retry-delay=delay", Integer,
|
49
|
-
"Automatically try to reconnect to the",
|
50
|
-
"server after delay seconds when the",
|
51
|
-
"connection failed or timed out.",
|
52
|
-
"A value of 0 disables automatical",
|
53
|
-
"reconnecting completely.",
|
54
|
-
"Default: 10"
|
55
|
-
) { |Options[:RetryDelay]| }
|
56
|
-
|
57
|
-
opts.on("-P", "--[no-]permanent",
|
58
|
-
"Run the breakpoint client in permanent mode.",
|
59
|
-
"This means that the client will keep continue",
|
60
|
-
"running even after the server has closed the",
|
61
|
-
"connection. Useful for example in Rails.",
|
62
|
-
"Default: non-permanent"
|
63
|
-
) { |Options[:Permanent]| }
|
64
|
-
|
65
|
-
opts.on("-V", "--[no-]verbose",
|
66
|
-
"Run the breakpoint client in verbose mode.",
|
67
|
-
"Will produce more messages, for example between",
|
68
|
-
"individual breakpoints. This might help in seeing",
|
69
|
-
"that the breakpoint client is still alive, but adds",
|
70
|
-
"quite a bit of clutter.",
|
71
|
-
"Default: non-verbose"
|
72
|
-
) { |Options[:Verbose]| }
|
73
|
-
|
74
|
-
opts.separator ""
|
75
|
-
|
76
|
-
opts.on("-h", "--help",
|
77
|
-
"Show this help message."
|
78
|
-
) { puts opts; exit }
|
79
|
-
opts.on("-v", "--version",
|
80
|
-
"Display the version information."
|
81
|
-
) do
|
82
|
-
id = %q$Id: breakpoint_client 50 2005-02-26 19:31:51Z flgr $
|
83
|
-
puts id.sub("Id: ", "")
|
84
|
-
puts "(Breakpoint::Version = #{Breakpoint::Version})"
|
85
|
-
exit
|
86
|
-
end
|
87
|
-
|
88
|
-
opts.parse!
|
89
|
-
end
|
90
|
-
|
91
|
-
Options[:ServerURI] = ARGV[0] if ARGV[0]
|
92
|
-
Options[:ClientURI] ||= case Options[:ServerURI]
|
93
|
-
when /^drbunix:(.+)$/i then
|
94
|
-
"drbunix:" << File.join(Dir.tmpdir, $1.gsub(/\W/, "_")) << ".breakpoint_client"
|
95
|
-
when %r{^druby://(localhost|127\.0\.0\.1|::1):(\d+)$}i then
|
96
|
-
"druby://" << $1 << ":" << $2.succ
|
97
|
-
end
|
98
|
-
|
99
|
-
puts "ClientURI is #{Options[:ClientURI] || "unspecified"}" if Options[:Verbose]
|
100
|
-
|
101
|
-
module Handlers
|
102
|
-
extend self
|
103
|
-
|
104
|
-
def breakpoint_handler(workspace, message)
|
105
|
-
puts message
|
106
|
-
IRB.start(nil, nil, workspace)
|
107
|
-
|
108
|
-
puts ""
|
109
|
-
if Options[:Verbose] then
|
110
|
-
puts "Resumed execution. Waiting for next breakpoint...", ""
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def eval_handler(code)
|
115
|
-
result = eval(code, TOPLEVEL_BINDING)
|
116
|
-
if result then
|
117
|
-
DRbObject.new(result)
|
118
|
-
else
|
119
|
-
result
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def collision_handler()
|
124
|
-
msg = [
|
125
|
-
" *** Breakpoint service collision ***",
|
126
|
-
" Another Breakpoint service tried to use the",
|
127
|
-
" port already occupied by this one. It will",
|
128
|
-
" keep waiting until this Breakpoint service",
|
129
|
-
" is shut down.",
|
130
|
-
" ",
|
131
|
-
" If you are using the Breakpoint library for",
|
132
|
-
" debugging a Rails or other CGI application",
|
133
|
-
" this likely means that this Breakpoint",
|
134
|
-
" session belongs to an earlier, outdated",
|
135
|
-
" request and should be shut down via 'exit'."
|
136
|
-
].join("\n")
|
137
|
-
|
138
|
-
if RUBY_PLATFORM["win"] then
|
139
|
-
# This sucks. Sorry, I'm not doing this because
|
140
|
-
# I like funky message boxes -- I need to do this
|
141
|
-
# because on Windows I have no way of displaying
|
142
|
-
# my notification via puts() when gets() is still
|
143
|
-
# being performed on STDIN. I have not found a
|
144
|
-
# better solution.
|
145
|
-
begin
|
146
|
-
require 'tk'
|
147
|
-
root = TkRoot.new { withdraw }
|
148
|
-
Tk.messageBox('message' => msg, 'type' => 'ok')
|
149
|
-
root.destroy
|
150
|
-
rescue Exception
|
151
|
-
puts "", msg, ""
|
152
|
-
end
|
153
|
-
else
|
154
|
-
puts "", msg, ""
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
# Used for checking whether we are currently in the reconnecting loop.
|
160
|
-
reconnecting = false
|
161
|
-
|
162
|
-
loop do
|
163
|
-
DRb.start_service(Options[:ClientURI])
|
164
|
-
|
165
|
-
begin
|
166
|
-
service = DRbObject.new(nil, Options[:ServerURI])
|
167
|
-
|
168
|
-
begin
|
169
|
-
ehandler = Handlers.method(:eval_handler)
|
170
|
-
chandler = Handlers.method(:collision_handler)
|
171
|
-
handler = Handlers.method(:breakpoint_handler)
|
172
|
-
service.eval_handler = ehandler
|
173
|
-
service.collision_handler = chandler
|
174
|
-
service.handler = handler
|
175
|
-
|
176
|
-
reconnecting = false
|
177
|
-
if Options[:Verbose] then
|
178
|
-
puts "Connection established. Waiting for breakpoint...", ""
|
179
|
-
end
|
180
|
-
|
181
|
-
loop do
|
182
|
-
begin
|
183
|
-
service.ping
|
184
|
-
rescue DRb::DRbConnError => error
|
185
|
-
puts "Server exited. Closing connection...", ""
|
186
|
-
DRb.stop_service
|
187
|
-
exit! unless Options[:Permanent]
|
188
|
-
break
|
189
|
-
end
|
190
|
-
|
191
|
-
sleep(0.5)
|
192
|
-
end
|
193
|
-
ensure
|
194
|
-
service.eval_handler = nil
|
195
|
-
service.collision_handler = nil
|
196
|
-
service.handler = nil
|
197
|
-
end
|
198
|
-
rescue Exception => error
|
199
|
-
if Options[:RetryDelay] > 0 then
|
200
|
-
if not reconnecting then
|
201
|
-
reconnecting = true
|
202
|
-
puts "No connection to breakpoint service at #{Options[:ServerURI]} " +
|
203
|
-
"(#{error.class})"
|
204
|
-
puts error.backtrace if $DEBUG
|
205
|
-
puts "Tries to connect will be made every #{Options[:RetryDelay]} seconds..."
|
206
|
-
end
|
207
|
-
|
208
|
-
sleep Options[:RetryDelay]
|
209
|
-
retry
|
210
|
-
else
|
211
|
-
raise
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
3
|
+
require 'breakpoint_client'
|
data/doc/classes/Binding.html
CHANGED
@@ -1,221 +1,238 @@
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
-
<!DOCTYPE html
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5
|
-
|
6
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
7
|
-
<head>
|
8
|
-
<title>Class: Binding</title>
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
10
|
-
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
11
|
-
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
|
12
|
-
<script type="text/javascript">
|
13
|
-
// <![CDATA[
|
14
|
-
|
15
|
-
function popupCode( url ) {
|
16
|
-
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
|
17
|
-
}
|
18
|
-
|
19
|
-
function toggleCode( id ) {
|
20
|
-
if ( document.getElementById )
|
21
|
-
elem = document.getElementById( id );
|
22
|
-
else if ( document.all )
|
23
|
-
elem = eval( "document.all." + id );
|
24
|
-
else
|
25
|
-
return false;
|
26
|
-
|
27
|
-
elemStyle = elem.style;
|
28
|
-
|
29
|
-
if ( elemStyle.display != "block" ) {
|
30
|
-
elemStyle.display = "block"
|
31
|
-
} else {
|
32
|
-
elemStyle.display = "none"
|
33
|
-
}
|
34
|
-
|
35
|
-
return true;
|
36
|
-
}
|
37
|
-
|
38
|
-
// Make codeblocks hidden by default
|
39
|
-
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
|
40
|
-
|
41
|
-
// ]]>
|
42
|
-
</script>
|
43
|
-
|
44
|
-
</head>
|
45
|
-
<body>
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
<div id="classHeader">
|
50
|
-
<table class="header-table">
|
51
|
-
<tr class="top-aligned-row">
|
52
|
-
<td><strong>Class</strong></td>
|
53
|
-
<td class="class-name-in-header">Binding</td>
|
54
|
-
</tr>
|
55
|
-
<tr class="top-aligned-row">
|
56
|
-
<td><strong>In:</strong></td>
|
57
|
-
<td>
|
58
|
-
<a href="../files/lib/binding_of_caller_rb.html">
|
59
|
-
lib/binding_of_caller.rb
|
60
|
-
</a>
|
61
|
-
<br />
|
62
|
-
</td>
|
63
|
-
</tr>
|
64
|
-
|
65
|
-
<tr class="top-aligned-row">
|
66
|
-
<td><strong>Parent:</strong></td>
|
67
|
-
<td>
|
68
|
-
Object
|
69
|
-
</td>
|
70
|
-
</tr>
|
71
|
-
</table>
|
72
|
-
</div>
|
73
|
-
<!-- banner header -->
|
74
|
-
|
75
|
-
<div id="bodyContent">
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
<div id="contextContent">
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
</div>
|
84
|
-
|
85
|
-
<div id="method-list">
|
86
|
-
<h3 class="section-bar">Methods</h3>
|
87
|
-
|
88
|
-
<div class="name-list">
|
89
|
-
<a href="#M000003">of_caller</a>
|
90
|
-
</div>
|
91
|
-
</div>
|
92
|
-
|
93
|
-
</div>
|
94
|
-
|
95
|
-
|
96
|
-
<!-- if includes -->
|
97
|
-
|
98
|
-
<div id="section">
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
<!-- if method_list -->
|
108
|
-
<div id="methods">
|
109
|
-
<h3 class="section-bar">Public Class methods</h3>
|
110
|
-
|
111
|
-
<div id="method-M000003" class="method-detail">
|
112
|
-
<a name="M000003"></a>
|
113
|
-
|
114
|
-
<div class="method-heading">
|
115
|
-
<a href="#M000003" class="method-signature">
|
116
|
-
<span class="method-name">of_caller</span><span class="method-args">() {|result| ...}</span>
|
117
|
-
</a>
|
118
|
-
</div>
|
119
|
-
|
120
|
-
<div class="method-description">
|
121
|
-
<p>
|
122
|
-
This method returns the binding of the method that called your method. It
|
123
|
-
will raise an Exception when you’re not inside a method.
|
124
|
-
</p>
|
125
|
-
<p>
|
126
|
-
It’s used like this:
|
127
|
-
</p>
|
128
|
-
<pre>
|
129
|
-
def inc_counter(amount = 1)
|
130
|
-
Binding.of_caller do |binding|
|
131
|
-
# Create a lambda that will increase the variable 'counter'
|
132
|
-
# in the caller of this method when called.
|
133
|
-
inc = eval("lambda { |arg| counter += arg }", binding)
|
134
|
-
# We can refer to amount from inside this block safely.
|
135
|
-
inc.call(amount)
|
136
|
-
end
|
137
|
-
# No other statements can go here. Put them inside the block.
|
138
|
-
end
|
139
|
-
counter = 0
|
140
|
-
2.times { inc_counter }
|
141
|
-
counter # => 2
|
142
|
-
</pre>
|
143
|
-
<p>
|
144
|
-
<a href="Binding.html#M000003">Binding.of_caller</a> must be the last
|
145
|
-
statement in the method. This means that you will have to put everything
|
146
|
-
you want to do after the call to <a
|
147
|
-
href="Binding.html#M000003">Binding.of_caller</a> into the block of it.
|
148
|
-
This should be no problem however, because Ruby has closures. If you
|
149
|
-
don’t do this an Exception will be raised. Because of the way that <a
|
150
|
-
href="Binding.html#M000003">Binding.of_caller</a> is implemented it has to
|
151
|
-
be done this way.
|
152
|
-
</p>
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
</
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
<
|
217
|
-
|
218
|
-
</
|
219
|
-
|
220
|
-
</
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5
|
+
|
6
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
7
|
+
<head>
|
8
|
+
<title>Class: Binding</title>
|
9
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
10
|
+
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
11
|
+
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
|
12
|
+
<script type="text/javascript">
|
13
|
+
// <![CDATA[
|
14
|
+
|
15
|
+
function popupCode( url ) {
|
16
|
+
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
|
17
|
+
}
|
18
|
+
|
19
|
+
function toggleCode( id ) {
|
20
|
+
if ( document.getElementById )
|
21
|
+
elem = document.getElementById( id );
|
22
|
+
else if ( document.all )
|
23
|
+
elem = eval( "document.all." + id );
|
24
|
+
else
|
25
|
+
return false;
|
26
|
+
|
27
|
+
elemStyle = elem.style;
|
28
|
+
|
29
|
+
if ( elemStyle.display != "block" ) {
|
30
|
+
elemStyle.display = "block"
|
31
|
+
} else {
|
32
|
+
elemStyle.display = "none"
|
33
|
+
}
|
34
|
+
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
|
38
|
+
// Make codeblocks hidden by default
|
39
|
+
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
|
40
|
+
|
41
|
+
// ]]>
|
42
|
+
</script>
|
43
|
+
|
44
|
+
</head>
|
45
|
+
<body>
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
<div id="classHeader">
|
50
|
+
<table class="header-table">
|
51
|
+
<tr class="top-aligned-row">
|
52
|
+
<td><strong>Class</strong></td>
|
53
|
+
<td class="class-name-in-header">Binding</td>
|
54
|
+
</tr>
|
55
|
+
<tr class="top-aligned-row">
|
56
|
+
<td><strong>In:</strong></td>
|
57
|
+
<td>
|
58
|
+
<a href="../files/lib/binding_of_caller_rb.html">
|
59
|
+
lib/binding_of_caller.rb
|
60
|
+
</a>
|
61
|
+
<br />
|
62
|
+
</td>
|
63
|
+
</tr>
|
64
|
+
|
65
|
+
<tr class="top-aligned-row">
|
66
|
+
<td><strong>Parent:</strong></td>
|
67
|
+
<td>
|
68
|
+
Object
|
69
|
+
</td>
|
70
|
+
</tr>
|
71
|
+
</table>
|
72
|
+
</div>
|
73
|
+
<!-- banner header -->
|
74
|
+
|
75
|
+
<div id="bodyContent">
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
<div id="contextContent">
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
</div>
|
84
|
+
|
85
|
+
<div id="method-list">
|
86
|
+
<h3 class="section-bar">Methods</h3>
|
87
|
+
|
88
|
+
<div class="name-list">
|
89
|
+
<a href="#M000003">of_caller</a>
|
90
|
+
</div>
|
91
|
+
</div>
|
92
|
+
|
93
|
+
</div>
|
94
|
+
|
95
|
+
|
96
|
+
<!-- if includes -->
|
97
|
+
|
98
|
+
<div id="section">
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
<!-- if method_list -->
|
108
|
+
<div id="methods">
|
109
|
+
<h3 class="section-bar">Public Class methods</h3>
|
110
|
+
|
111
|
+
<div id="method-M000003" class="method-detail">
|
112
|
+
<a name="M000003"></a>
|
113
|
+
|
114
|
+
<div class="method-heading">
|
115
|
+
<a href="#M000003" class="method-signature">
|
116
|
+
<span class="method-name">of_caller</span><span class="method-args">() {|result| ...}</span>
|
117
|
+
</a>
|
118
|
+
</div>
|
119
|
+
|
120
|
+
<div class="method-description">
|
121
|
+
<p>
|
122
|
+
This method returns the binding of the method that called your method. It
|
123
|
+
will raise an Exception when you’re not inside a method.
|
124
|
+
</p>
|
125
|
+
<p>
|
126
|
+
It’s used like this:
|
127
|
+
</p>
|
128
|
+
<pre>
|
129
|
+
def inc_counter(amount = 1)
|
130
|
+
Binding.of_caller do |binding|
|
131
|
+
# Create a lambda that will increase the variable 'counter'
|
132
|
+
# in the caller of this method when called.
|
133
|
+
inc = eval("lambda { |arg| counter += arg }", binding)
|
134
|
+
# We can refer to amount from inside this block safely.
|
135
|
+
inc.call(amount)
|
136
|
+
end
|
137
|
+
# No other statements can go here. Put them inside the block.
|
138
|
+
end
|
139
|
+
counter = 0
|
140
|
+
2.times { inc_counter }
|
141
|
+
counter # => 2
|
142
|
+
</pre>
|
143
|
+
<p>
|
144
|
+
<a href="Binding.html#M000003">Binding.of_caller</a> must be the last
|
145
|
+
statement in the method. This means that you will have to put everything
|
146
|
+
you want to do after the call to <a
|
147
|
+
href="Binding.html#M000003">Binding.of_caller</a> into the block of it.
|
148
|
+
This should be no problem however, because Ruby has closures. If you
|
149
|
+
don’t do this an Exception will be raised. Because of the way that <a
|
150
|
+
href="Binding.html#M000003">Binding.of_caller</a> is implemented it has to
|
151
|
+
be done this way.
|
152
|
+
</p>
|
153
|
+
<p>
|
154
|
+
Please note that currently bindings returned by <a
|
155
|
+
href="Binding.html#M000003">Binding.of_caller</a>() will have a wrong self
|
156
|
+
context which means you can not call methods, access instance variables and
|
157
|
+
so on on the calling object. You can work around this by defining the
|
158
|
+
method which uses the binding on all objects and telling your users to use
|
159
|
+
them without a receiver. This is how ruby-breakpoint works around the
|
160
|
+
problem.
|
161
|
+
</p>
|
162
|
+
<p>
|
163
|
+
This is believed to be a bug in Ruby and has been reported to ruby-core.
|
164
|
+
See <a
|
165
|
+
href="http://www.ruby-forum.com/topic/67255">www.ruby-forum.com/topic/67255</a>
|
166
|
+
</p>
|
167
|
+
<p><a class="source-toggle" href="#"
|
168
|
+
onclick="toggleCode('M000003-source');return false;">[Source]</a></p>
|
169
|
+
<div class="method-source-code" id="M000003-source">
|
170
|
+
<pre>
|
171
|
+
<span class="ruby-comment cmt"># File lib/binding_of_caller.rb, line 46</span>
|
172
|
+
46: <span class="ruby-keyword kw">def</span> <span class="ruby-constant">Binding</span>.<span class="ruby-identifier">of_caller</span>(<span class="ruby-operator">&</span><span class="ruby-identifier">block</span>)
|
173
|
+
47: <span class="ruby-identifier">old_critical</span> = <span class="ruby-constant">Thread</span>.<span class="ruby-identifier">critical</span>
|
174
|
+
48: <span class="ruby-constant">Thread</span>.<span class="ruby-identifier">critical</span> = <span class="ruby-keyword kw">true</span>
|
175
|
+
49: <span class="ruby-identifier">count</span> = <span class="ruby-value">0</span>
|
176
|
+
50: <span class="ruby-identifier">cc</span>, <span class="ruby-identifier">result</span>, <span class="ruby-identifier">error</span>, <span class="ruby-identifier">extra_data</span> = <span class="ruby-constant">Continuation</span>.<span class="ruby-identifier">create</span>(<span class="ruby-keyword kw">nil</span>, <span class="ruby-keyword kw">nil</span>)
|
177
|
+
51: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">error</span> <span class="ruby-keyword kw">then</span>
|
178
|
+
52: <span class="ruby-constant">Thread</span>.<span class="ruby-identifier">critical</span> = <span class="ruby-identifier">old_critical</span>
|
179
|
+
53: <span class="ruby-identifier">error</span>.<span class="ruby-identifier">call</span>
|
180
|
+
54: <span class="ruby-keyword kw">end</span>
|
181
|
+
55:
|
182
|
+
56: <span class="ruby-identifier">tracer</span> = <span class="ruby-identifier">lambda</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-operator">*</span><span class="ruby-identifier">args</span><span class="ruby-operator">|</span>
|
183
|
+
57: <span class="ruby-identifier">type</span>, <span class="ruby-identifier">context</span>, <span class="ruby-identifier">extra_data</span> = <span class="ruby-identifier">args</span>[<span class="ruby-value">0</span>], <span class="ruby-identifier">args</span>[<span class="ruby-value">4</span>], <span class="ruby-identifier">args</span>
|
184
|
+
58: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">type</span> <span class="ruby-operator">==</span> <span class="ruby-value str">"return"</span>
|
185
|
+
59: <span class="ruby-identifier">count</span> <span class="ruby-operator">+=</span> <span class="ruby-value">1</span>
|
186
|
+
60: <span class="ruby-comment cmt"># First this method and then calling one will return --
|
187
|
+
61: <span class="ruby-comment cmt"># the trace event of the second event gets the context
|
188
|
+
62: <span class="ruby-comment cmt"># of the method which called the method that called this
|
189
|
+
63: <span class="ruby-comment cmt"># method.
|
190
|
+
64: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">count</span> <span class="ruby-operator">==</span> <span class="ruby-value">2</span>
|
191
|
+
65: <span class="ruby-comment cmt"># It would be nice if we could restore the trace_func
|
192
|
+
66: <span class="ruby-comment cmt"># that was set before we swapped in our own one, but
|
193
|
+
67: <span class="ruby-comment cmt"># this is impossible without overloading set_trace_func
|
194
|
+
68: <span class="ruby-comment cmt"># in current Ruby.
|
195
|
+
69: <span class="ruby-identifier">set_trace_func</span>(<span class="ruby-keyword kw">nil</span>)
|
196
|
+
70: <span class="ruby-identifier">cc</span>.<span class="ruby-identifier">call</span>(<span class="ruby-identifier">context</span>, <span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">extra_data</span>)
|
197
|
+
71: <span class="ruby-keyword kw">end</span>
|
198
|
+
72: <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">type</span> <span class="ruby-operator">==</span> <span class="ruby-value str">"line"</span> <span class="ruby-keyword kw">then</span>
|
199
|
+
73: <span class="ruby-keyword kw">nil</span>
|
200
|
+
74: <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">type</span> <span class="ruby-operator">==</span> <span class="ruby-value str">"c-return"</span> <span class="ruby-keyword kw">and</span> <span class="ruby-identifier">extra_data</span>[<span class="ruby-value">3</span>] <span class="ruby-operator">==</span> <span class="ruby-identifier">:set_trace_func</span> <span class="ruby-keyword kw">then</span>
|
201
|
+
75: <span class="ruby-keyword kw">nil</span>
|
202
|
+
76: <span class="ruby-keyword kw">else</span>
|
203
|
+
77: <span class="ruby-identifier">set_trace_func</span>(<span class="ruby-keyword kw">nil</span>)
|
204
|
+
78: <span class="ruby-identifier">error_msg</span> = <span class="ruby-value str">"Binding.of_caller used in non-method context or "</span> <span class="ruby-operator">+</span>
|
205
|
+
79: <span class="ruby-value str">"trailing statements of method using it aren't in the block."</span>
|
206
|
+
80: <span class="ruby-identifier">cc</span>.<span class="ruby-identifier">call</span>(<span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">lambda</span> { <span class="ruby-identifier">raise</span>(<span class="ruby-constant">ArgumentError</span>, <span class="ruby-identifier">error_msg</span>) }, <span class="ruby-keyword kw">nil</span>)
|
207
|
+
81: <span class="ruby-keyword kw">end</span>
|
208
|
+
82: <span class="ruby-keyword kw">end</span>
|
209
|
+
83:
|
210
|
+
84: <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">result</span>
|
211
|
+
85: <span class="ruby-identifier">set_trace_func</span>(<span class="ruby-identifier">tracer</span>)
|
212
|
+
86: <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">nil</span>
|
213
|
+
87: <span class="ruby-keyword kw">else</span>
|
214
|
+
88: <span class="ruby-constant">Thread</span>.<span class="ruby-identifier">critical</span> = <span class="ruby-identifier">old_critical</span>
|
215
|
+
89: <span class="ruby-keyword kw">case</span> <span class="ruby-identifier">block</span>.<span class="ruby-identifier">arity</span>
|
216
|
+
90: <span class="ruby-keyword kw">when</span> <span class="ruby-value">1</span> <span class="ruby-keyword kw">then</span> <span class="ruby-keyword kw">yield</span>(<span class="ruby-identifier">result</span>)
|
217
|
+
91: <span class="ruby-keyword kw">else</span> <span class="ruby-keyword kw">yield</span>(<span class="ruby-identifier">result</span>, <span class="ruby-identifier">extra_data</span>)
|
218
|
+
92: <span class="ruby-keyword kw">end</span>
|
219
|
+
93: <span class="ruby-keyword kw">end</span>
|
220
|
+
94: <span class="ruby-keyword kw">end</span>
|
221
|
+
</pre>
|
222
|
+
</div>
|
223
|
+
</div>
|
224
|
+
</div>
|
225
|
+
|
226
|
+
|
227
|
+
</div>
|
228
|
+
|
229
|
+
|
230
|
+
</div>
|
231
|
+
|
232
|
+
|
233
|
+
<div id="validator-badges">
|
234
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
235
|
+
</div>
|
236
|
+
|
237
|
+
</body>
|
221
238
|
</html>
|