glue 0.13.0 → 0.14.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/CHANGELOG +19 -0
- data/README +1 -1
- data/Rakefile +1 -1
- data/doc/RELEASES +4 -0
- data/lib/glue.rb +6 -2
- data/lib/glue/attribute.rb +3 -0
- data/lib/glue/inflector.rb +1 -1
- data/lib/glue/logger.rb +29 -4
- data/lib/glue/property.rb +50 -46
- data/test/glue/tc_property.rb +8 -1
- data/vendor/README +11 -0
- data/vendor/binding_of_caller.rb +81 -0
- data/vendor/blankslate.rb +53 -0
- data/vendor/breakpoint.rb +523 -0
- data/vendor/breakpoint_client.rb +196 -0
- data/vendor/extensions/_base.rb +153 -0
- data/vendor/extensions/_template.rb +36 -0
- data/vendor/extensions/all.rb +21 -0
- data/vendor/extensions/array.rb +68 -0
- data/vendor/extensions/binding.rb +224 -0
- data/vendor/extensions/class.rb +50 -0
- data/vendor/extensions/continuation.rb +71 -0
- data/vendor/extensions/enumerable.rb +250 -0
- data/vendor/extensions/hash.rb +23 -0
- data/vendor/extensions/io.rb +58 -0
- data/vendor/extensions/kernel.rb +42 -0
- data/vendor/extensions/module.rb +114 -0
- data/vendor/extensions/numeric.rb +230 -0
- data/vendor/extensions/object.rb +164 -0
- data/vendor/extensions/ostruct.rb +41 -0
- data/vendor/extensions/string.rb +316 -0
- data/vendor/extensions/symbol.rb +28 -0
- metadata +26 -3
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'breakpoint'
|
2
|
+
require 'optparse'
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
Options = {
|
6
|
+
:ClientURI => nil,
|
7
|
+
:ServerURI => "druby://localhost:42531",
|
8
|
+
:RetryDelay => 2,
|
9
|
+
:Permanent => true,
|
10
|
+
:Verbose => false
|
11
|
+
}
|
12
|
+
|
13
|
+
ARGV.options do |opts|
|
14
|
+
script_name = File.basename($0)
|
15
|
+
opts.banner = [
|
16
|
+
"Usage: ruby #{script_name} [Options] [server uri]",
|
17
|
+
"",
|
18
|
+
"This tool lets you connect to a breakpoint service ",
|
19
|
+
"which was started via Breakpoint.activate_drb.",
|
20
|
+
"",
|
21
|
+
"The server uri defaults to druby://localhost:42531"
|
22
|
+
].join("\n")
|
23
|
+
|
24
|
+
opts.separator ""
|
25
|
+
|
26
|
+
opts.on("-c", "--client-uri=uri",
|
27
|
+
"Run the client on the specified uri.",
|
28
|
+
"This can be used to specify the port",
|
29
|
+
"that the client uses to allow for back",
|
30
|
+
"connections from the server.",
|
31
|
+
"Default: Find a good URI automatically.",
|
32
|
+
"Example: -c druby://localhost:12345"
|
33
|
+
) { |Options[:ClientURI]| }
|
34
|
+
|
35
|
+
opts.on("-s", "--server-uri=uri",
|
36
|
+
"Connect to the server specified at the",
|
37
|
+
"specified uri.",
|
38
|
+
"Default: druby://localhost:42531"
|
39
|
+
) { |Options[:ServerURI]| }
|
40
|
+
|
41
|
+
opts.on("-R", "--retry-delay=delay", Integer,
|
42
|
+
"Automatically try to reconnect to the",
|
43
|
+
"server after delay seconds when the",
|
44
|
+
"connection failed or timed out.",
|
45
|
+
"A value of 0 disables automatical",
|
46
|
+
"reconnecting completely.",
|
47
|
+
"Default: 10"
|
48
|
+
) { |Options[:RetryDelay]| }
|
49
|
+
|
50
|
+
opts.on("-P", "--[no-]permanent",
|
51
|
+
"Run the breakpoint client in permanent mode.",
|
52
|
+
"This means that the client will keep continue",
|
53
|
+
"running even after the server has closed the",
|
54
|
+
"connection. Useful for example in Rails."
|
55
|
+
) { |Options[:Permanent]| }
|
56
|
+
|
57
|
+
opts.on("-V", "--[no-]verbose",
|
58
|
+
"Run the breakpoint client in verbose mode.",
|
59
|
+
"Will produce more messages, for example between",
|
60
|
+
"individual breakpoints. This might help in seeing",
|
61
|
+
"that the breakpoint client is still alive, but adds",
|
62
|
+
"quite a bit of clutter."
|
63
|
+
) { |Options[:Verbose]| }
|
64
|
+
|
65
|
+
opts.separator ""
|
66
|
+
|
67
|
+
opts.on("-h", "--help",
|
68
|
+
"Show this help message."
|
69
|
+
) { puts opts; exit }
|
70
|
+
opts.on("-v", "--version",
|
71
|
+
"Display the version information."
|
72
|
+
) do
|
73
|
+
id = %q$Id: breakpoint_client.rb 91 2005-02-04 22:34:08Z flgr $
|
74
|
+
puts id.sub("Id: ", "")
|
75
|
+
puts "(Breakpoint::Version = #{Breakpoint::Version})"
|
76
|
+
exit
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.parse!
|
80
|
+
end
|
81
|
+
|
82
|
+
Options[:ServerURI] = ARGV[0] if ARGV[0]
|
83
|
+
|
84
|
+
module Handlers
|
85
|
+
extend self
|
86
|
+
|
87
|
+
def breakpoint_handler(workspace, message)
|
88
|
+
puts message
|
89
|
+
IRB.start(nil, nil, workspace)
|
90
|
+
|
91
|
+
puts ""
|
92
|
+
if Options[:Verbose] then
|
93
|
+
puts "Resumed execution. Waiting for next breakpoint...", ""
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def eval_handler(code)
|
98
|
+
result = eval(code, TOPLEVEL_BINDING)
|
99
|
+
if result then
|
100
|
+
DRbObject.new(result)
|
101
|
+
else
|
102
|
+
result
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def collision_handler()
|
107
|
+
msg = [
|
108
|
+
" *** Breakpoint service collision ***",
|
109
|
+
" Another Breakpoint service tried to use the",
|
110
|
+
" port already occupied by this one. It will",
|
111
|
+
" keep waiting until this Breakpoint service",
|
112
|
+
" is shut down.",
|
113
|
+
" ",
|
114
|
+
" If you are using the Breakpoint library for",
|
115
|
+
" debugging a Rails or other CGI application",
|
116
|
+
" this likely means that this Breakpoint",
|
117
|
+
" session belongs to an earlier, outdated",
|
118
|
+
" request and should be shut down via 'exit'."
|
119
|
+
].join("\n")
|
120
|
+
|
121
|
+
if RUBY_PLATFORM["win"] then
|
122
|
+
# This sucks. Sorry, I'm not doing this because
|
123
|
+
# I like funky message boxes -- I need to do this
|
124
|
+
# because on Windows I have no way of displaying
|
125
|
+
# my notification via puts() when gets() is still
|
126
|
+
# being performed on STDIN. I have not found a
|
127
|
+
# better solution.
|
128
|
+
begin
|
129
|
+
require 'tk'
|
130
|
+
root = TkRoot.new { withdraw }
|
131
|
+
Tk.messageBox('message' => msg, 'type' => 'ok')
|
132
|
+
root.destroy
|
133
|
+
rescue Exception
|
134
|
+
puts "", msg, ""
|
135
|
+
end
|
136
|
+
else
|
137
|
+
puts "", msg, ""
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Used for checking whether we are currently in the reconnecting loop.
|
143
|
+
reconnecting = false
|
144
|
+
|
145
|
+
loop do
|
146
|
+
DRb.start_service(Options[:ClientURI])
|
147
|
+
|
148
|
+
begin
|
149
|
+
service = DRbObject.new(nil, Options[:ServerURI])
|
150
|
+
|
151
|
+
begin
|
152
|
+
ehandler = Handlers.method(:eval_handler)
|
153
|
+
chandler = Handlers.method(:collision_handler)
|
154
|
+
handler = Handlers.method(:breakpoint_handler)
|
155
|
+
service.eval_handler = ehandler
|
156
|
+
service.collision_handler = chandler
|
157
|
+
service.handler = handler
|
158
|
+
|
159
|
+
reconnecting = false
|
160
|
+
if Options[:Verbose] then
|
161
|
+
puts "Connection established. Waiting for breakpoint...", ""
|
162
|
+
end
|
163
|
+
|
164
|
+
loop do
|
165
|
+
begin
|
166
|
+
service.ping
|
167
|
+
rescue DRb::DRbConnError => error
|
168
|
+
puts "Server exited. Closing connection...", ""
|
169
|
+
exit! unless Options[:Permanent]
|
170
|
+
break
|
171
|
+
end
|
172
|
+
|
173
|
+
sleep(0.5)
|
174
|
+
end
|
175
|
+
ensure
|
176
|
+
service.eval_handler = nil
|
177
|
+
service.collision_handler = nil
|
178
|
+
service.handler = nil
|
179
|
+
end
|
180
|
+
rescue Exception => error
|
181
|
+
if Options[:RetryDelay] > 0 then
|
182
|
+
if not reconnecting then
|
183
|
+
reconnecting = true
|
184
|
+
puts "No connection to breakpoint service at #{Options[:ServerURI]} " +
|
185
|
+
"(#{error.class})"
|
186
|
+
puts error.backtrace if $DEBUG
|
187
|
+
puts "Tries to connect will be made every #{Options[:RetryDelay]} seconds..."
|
188
|
+
end
|
189
|
+
|
190
|
+
sleep Options[:RetryDelay]
|
191
|
+
retry
|
192
|
+
else
|
193
|
+
raise
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# This file is 'required' by all files that implement standard class
|
4
|
+
# extensions as part of the "Ruby/Extensions" project.
|
5
|
+
#
|
6
|
+
# The "Extensions" project requires 1.8.0 or greater to run, as it is too
|
7
|
+
# much hassle at the moment to consider supporting older versions. That may
|
8
|
+
# one day be implemented if demand is there. One option would be to require
|
9
|
+
# "shim", so that we can assume all 1.8 library methods are implemented.
|
10
|
+
#
|
11
|
+
# This file is only of interest to developers of the package, so no detailed
|
12
|
+
# documentation is included here. However, by way of introduction, this is what
|
13
|
+
# it's all about. Each method that is implemented as part of this package is
|
14
|
+
# done so through a framework implemented in this file. Take the following
|
15
|
+
# simple example:
|
16
|
+
#
|
17
|
+
# ExtensionsProject.implement(Integer, :even?, :instance) do
|
18
|
+
# class Integer
|
19
|
+
# #
|
20
|
+
# # RDoc comments.
|
21
|
+
# #
|
22
|
+
# def even?
|
23
|
+
# self % 2 == 0
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# This purposes of this are as follows:
|
29
|
+
# - if the intended method (in this case IO.write) is already defined,
|
30
|
+
# we don't want to overwrite it (we issue a warning and move on)
|
31
|
+
# - if the intended method is _not_ implemented as a result of the block,
|
32
|
+
# we have not done as we said, and an error is raised
|
33
|
+
# - the ExtensionsProject class gathers information on which methods have
|
34
|
+
# been implemented, making for a very handy command-line reference (+rbxtm+)
|
35
|
+
#
|
36
|
+
# The <tt>ExtensionsProject.implement</tt> method is responsible for ensuring
|
37
|
+
# these are so. It gives us documentation, and some assurance that the
|
38
|
+
# extensions are doing what we say they are doing.
|
39
|
+
#
|
40
|
+
|
41
|
+
# :enddoc:
|
42
|
+
|
43
|
+
#
|
44
|
+
# For what reason does Ruby define Module#methods, Module#instance_methods,
|
45
|
+
# and Module#method_defined?, but not Module#instance_method_defined? ?
|
46
|
+
#
|
47
|
+
# No matter, extending standard classes is the name of the game here.
|
48
|
+
#
|
49
|
+
class Module
|
50
|
+
if Module.method_defined?(:instance_method_defined?)
|
51
|
+
STDERR.puts "Warning: Module#instance_method_defined? already defined; not overwriting"
|
52
|
+
else
|
53
|
+
def instance_method_defined?(_method)
|
54
|
+
instance_methods(true).find { |m| m == _method.to_s }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if Module.method_defined?(:module_method_defined?)
|
59
|
+
STDERR.puts "Warning: Module#module_method_defined? already defined; not overwriting"
|
60
|
+
else
|
61
|
+
def module_method_defined?(_method)
|
62
|
+
singleton_methods(true).find { |m| m == _method.to_s }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
class ExtensionsProject
|
69
|
+
|
70
|
+
class << ExtensionsProject
|
71
|
+
@@extension_methods = []
|
72
|
+
|
73
|
+
#
|
74
|
+
# The list of methods implemented in this project.
|
75
|
+
#
|
76
|
+
def extension_methods
|
77
|
+
@@extension_methods
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Return the name of the project. To be used in error messages, etc., for
|
82
|
+
# consistency.
|
83
|
+
#
|
84
|
+
def project_name
|
85
|
+
"Ruby/Extensions"
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Wraps around the implementation of a method, emitting a warning if the
|
90
|
+
# method is already defined. Returns true to indicate - false to indicate
|
91
|
+
# failure (i.e. method is already defined). Raises an error if the
|
92
|
+
# specified method is not actually implemented by the block.
|
93
|
+
#
|
94
|
+
def implement(_module, _method, _type=:instance)
|
95
|
+
raise "Internal error: #{__FILE__}:#{__LINE__}" unless
|
96
|
+
_module.is_a? Module and
|
97
|
+
_method.is_a? Symbol and
|
98
|
+
_type == :instance or _type == :class or _type == :module
|
99
|
+
|
100
|
+
fullname = _module.to_s + string_rep(_type) + _method.to_s
|
101
|
+
|
102
|
+
if _defined?(_module, _method, _type)
|
103
|
+
STDERR.puts "#{project_name}: #{fullname} is already defined; not overwriting"
|
104
|
+
return false
|
105
|
+
else
|
106
|
+
yield # Perform the block; presumably a method implementation.
|
107
|
+
if _method == :initialize and _type == :instance
|
108
|
+
# Special case; we can't verify this.
|
109
|
+
@@extension_methods<< "#{_module}::new"
|
110
|
+
else
|
111
|
+
unless _defined?(_module, _method, _type)
|
112
|
+
raise "#{project_name}: internal error: was supposed to implement " +
|
113
|
+
"#{fullname}, but it didn't!"
|
114
|
+
end
|
115
|
+
@@extension_methods << fullname
|
116
|
+
end
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# See whether the given module implements the given method, taking account
|
123
|
+
# of the type (class/instance) required.
|
124
|
+
def _defined?(_module, _method, _type)
|
125
|
+
case _type
|
126
|
+
when :instance
|
127
|
+
_module.instance_method_defined?(_method) # See definition above.
|
128
|
+
when :class, :module
|
129
|
+
_module.module_method_defined?(_method) # See definition above.
|
130
|
+
end
|
131
|
+
end
|
132
|
+
private :_defined?
|
133
|
+
|
134
|
+
|
135
|
+
# Return the string representation of the given method type.
|
136
|
+
def string_rep(method_type)
|
137
|
+
case method_type
|
138
|
+
when :instance then "#"
|
139
|
+
when :class then "."
|
140
|
+
when :module then "."
|
141
|
+
else
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
private :string_rep
|
146
|
+
end
|
147
|
+
end # class ExtensionsProject
|
148
|
+
|
149
|
+
|
150
|
+
if VERSION < "1.8.0"
|
151
|
+
raise "#{ExtensionsProject.project_name} requires Ruby 1.8.0 at least (for now)"
|
152
|
+
end
|
153
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
# A template for new files in the project; of no interest to end users. An
|
3
|
+
# error will be raised if you +require+ it.
|
4
|
+
#--
|
5
|
+
# :enddoc:
|
6
|
+
#
|
7
|
+
# == extensions/XXX.rb
|
8
|
+
#
|
9
|
+
# Adds methods to the builtin XXX class.
|
10
|
+
#
|
11
|
+
|
12
|
+
raise "Do not load this file!"
|
13
|
+
|
14
|
+
require "extensions/_base"
|
15
|
+
|
16
|
+
#
|
17
|
+
# * Enumerable#build_hash
|
18
|
+
#
|
19
|
+
ExtensionsProject.implement(Enumerable, :build_hash) do
|
20
|
+
module Enumerable
|
21
|
+
#
|
22
|
+
# Like #map/#collect, but it generates a Hash.
|
23
|
+
#
|
24
|
+
# [1,5,11].build_hash { |x| [x, x**2] }
|
25
|
+
# => { 1 => 2, 5 => 25, 11 => 121 }
|
26
|
+
#
|
27
|
+
def build_hash
|
28
|
+
result = {}
|
29
|
+
self.each do |elt|
|
30
|
+
key, value = yield elt
|
31
|
+
result[key] = value
|
32
|
+
end
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# == extensions/all.rb
|
3
|
+
#
|
4
|
+
# Require this file in order to access all of the standard class extensions
|
5
|
+
# available, or require individual extension files to narrow the selection.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'extensions/array.rb'
|
9
|
+
require 'extensions/binding.rb'
|
10
|
+
require 'extensions/class.rb'
|
11
|
+
require 'extensions/continuation.rb'
|
12
|
+
require 'extensions/enumerable.rb'
|
13
|
+
require 'extensions/hash.rb'
|
14
|
+
require 'extensions/io.rb'
|
15
|
+
require 'extensions/kernel.rb'
|
16
|
+
require 'extensions/module.rb'
|
17
|
+
require 'extensions/numeric.rb'
|
18
|
+
require 'extensions/object.rb'
|
19
|
+
require 'extensions/ostruct.rb'
|
20
|
+
require 'extensions/string.rb'
|
21
|
+
require 'extensions/symbol.rb'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
#
|
3
|
+
# == extensions/array.rb
|
4
|
+
#
|
5
|
+
# Adds methods to the builtin Array class.
|
6
|
+
#
|
7
|
+
|
8
|
+
require "extensions/_base"
|
9
|
+
|
10
|
+
#
|
11
|
+
# * Array#select!
|
12
|
+
#
|
13
|
+
ExtensionsProject.implement(Array, :select!) do
|
14
|
+
class Array
|
15
|
+
#
|
16
|
+
# In-place version of Array#select. (Counterpart to, and opposite of, the
|
17
|
+
# built-in #reject!)
|
18
|
+
#
|
19
|
+
def select!
|
20
|
+
reject! { |e| not yield(e) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
#
|
27
|
+
# * Array#only
|
28
|
+
#
|
29
|
+
ExtensionsProject.implement(Array, :only) do
|
30
|
+
class Array
|
31
|
+
#
|
32
|
+
# Returns the _only_ element in the array. Raises an IndexError if the array's size is not
|
33
|
+
# 1.
|
34
|
+
#
|
35
|
+
# [5].only # -> 5
|
36
|
+
# [1,2,3].only # -> IndexError
|
37
|
+
# [].only # -> IndexError
|
38
|
+
#
|
39
|
+
def only
|
40
|
+
unless size == 1
|
41
|
+
raise IndexError, "Array#only called on non-single-element array"
|
42
|
+
end
|
43
|
+
first
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# * Array#rand
|
50
|
+
#
|
51
|
+
ExtensionsProject.implement(Array, :rand) do
|
52
|
+
class Array
|
53
|
+
#
|
54
|
+
# Return a randomly-chosen (using Kernel.rand) element from the array.
|
55
|
+
#
|
56
|
+
# arr = [48, 71, 3, 39, 15]
|
57
|
+
# arr.rand # -> 71
|
58
|
+
# arr.rand # -> 39
|
59
|
+
# arr.rand # -> 48
|
60
|
+
# # etc.
|
61
|
+
#
|
62
|
+
def rand
|
63
|
+
idx = Kernel.rand(size)
|
64
|
+
at(idx)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|