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.
@@ -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
+