glue 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+