adaptation 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -27,3 +27,7 @@
27
27
  placed in ApplicationAdaptor (app/adaptors/application.rb)
28
28
  - if a message is not implemented in the adaptor, ApplicationAdaptor process method will be called
29
29
  with that message as a parameter (wich will be an instance of Adaptation::Message)
30
+ * 0.1.1
31
+ - added method 'maps_xml' to Adaptation::Message (and 'mapped_xml')
32
+ - removed 'check' method from Adaptation::Message (using valid? instead)
33
+ - removed breakpoint.rb library
@@ -31,6 +31,10 @@ module Adaptation
31
31
  end
32
32
  end
33
33
 
34
+ def self.get_class_object(adaptor_class) # nodoc
35
+ Object.const_get(adaptor_class) rescue nil
36
+ end
37
+
34
38
  end
35
39
 
36
40
  end
@@ -62,28 +62,17 @@ module Adaptation
62
62
  message_type = xml_message[1..(xml_message.index(/(>| |\/)/) - 1)]
63
63
  adaptor = message = nil
64
64
 
65
- begin
66
- message_class = get_class_object(message_type.capitalize)
67
- message = message_class.to_object(xml_message)
68
- rescue
69
- # message class not implemented in this adaptor
70
- #
71
- # TODO: the xml is returned as a String; in future versions
72
- # Adaptation may build a valid Adaptation::Message even
73
- # without implementation for this type of message
74
- message = xml_message # Adaptation::Message.to_object(xml_message)
75
- end
76
-
77
- begin
78
- adaptor_class = get_class_object("#{message_type.capitalize}Adaptor")
79
- adaptor = adaptor_class.new
80
- rescue
81
- # adaptor class not implemented in this adaptor
82
- adaptor = ApplicationAdaptor.new
83
- end
84
-
85
- unless message.is_a?(String) # TODO: remove when feature explained in line 70 implemented
86
- unless message.check
65
+ message_class = Adaptation::Message.get_class_object(message_type.capitalize)
66
+ message = message_class.nil? ? xml_message : message_class.to_object(xml_message)
67
+ # TODO: the xml is returned as a String if a class to map it is not found;
68
+ # in future versions Adaptation may build a valid Adaptation::Message even
69
+ # without implementation for this type of message
70
+
71
+ adaptor_class = Adaptation::Adaptor.get_class_object("#{message_type.capitalize}Adaptor")
72
+ adaptor = adaptor_class.nil? ? ApplicationAdaptor.new : adaptor_class.new
73
+
74
+ unless message.is_a?(String) # TODO: remove when feature explained in line 67 implemented
75
+ unless message.valid?
87
76
  @@logger.info "WARNING:Message doesn't validate!"
88
77
  return
89
78
  end
@@ -92,10 +81,6 @@ module Adaptation
92
81
  adaptor.process message
93
82
  end
94
83
 
95
- def get_class_object(searched_class)
96
- Object.const_get searched_class
97
- end
98
-
99
84
  end
100
85
 
101
86
  end
@@ -153,12 +153,13 @@ module Adaptation
153
153
  @objects = [] if @objects.nil?
154
154
  unless @objects.include?(symbols[1])
155
155
  @objects << symbols[1]
156
- begin
157
- klass = get_class_object(symbols[1].to_s.capitalize)
158
- rescue Exception => e
156
+
157
+ klass = get_class_object(symbols[1])
158
+ if klass.nil?
159
159
  require "#{ADAPTOR_ROOT}/app/messages/_#{symbols[1].to_s}.rb"
160
- klass = get_class_object(symbols[1].to_s.capitalize)
160
+ klass = get_class_object(symbols[1])
161
161
  end
162
+
162
163
  xml_object symbols[1], klass
163
164
  validates_associated symbols[1]
164
165
  end
@@ -271,10 +272,55 @@ module Adaptation
271
272
  end
272
273
  end
273
274
 
274
- def self.get_class_object(searched_class) #:nodoc:
275
- Object.const_get searched_class
275
+ # Defines the xml element that this class is mapping. This is useful to avoid class
276
+ # name collisions:
277
+ #
278
+ # Example:
279
+ #
280
+ # We already have a database table called 'things' and we
281
+ # interoperate with it with an ActiveRecord subclass called
282
+ # 'Thing':
283
+ #
284
+ # class Thing < ActiveRecord::Base
285
+ # ...
286
+ # end
287
+ #
288
+ # But in the same Adaptation application we want to parse the
289
+ # following xml:
290
+ #
291
+ # <thing>...</thing>
292
+ #
293
+ # Defining another class Thing would produce a class name
294
+ # collision, but we can do:
295
+ #
296
+ # class XmlThing < Adaptation::Message
297
+ # maps_xml :thing
298
+ # ...
299
+ # end
300
+ #
301
+ # and store it in a file called app/messages/thing.rb
302
+ #
303
+ def self.maps_xml element
304
+ @mapped_xml = element
305
+ xml_name element.to_s
276
306
  end
277
-
307
+
308
+ # Returns the xml element this class is mapping
309
+ def self.mapped_xml
310
+ @mapped_xml || self.to_s.downcase.gsub("::","_").to_sym
311
+ end
312
+
313
+ def self.get_class_object(mapped_xml) #:nodoc:
314
+ # TODO: reimplement this as read in ruby-talk (using 'inherited' method)
315
+ mapped_xml = mapped_xml.downcase.to_sym if mapped_xml.is_a?(String)
316
+ klass = nil
317
+ ObjectSpace.each_object(Class) do |c|
318
+ next unless c.ancestors.include?(Adaptation::Message) and (c != self) and (c != Adaptation::Message)
319
+ (klass = c and break) if c.mapped_xml == mapped_xml rescue next
320
+ end
321
+ klass
322
+ end
323
+
278
324
  # This is the constructor. Instead of <em>Adaptation::Message#new</em>, an <em>Adaptation::Message</em>
279
325
  # instance is created like this:
280
326
  #
@@ -284,13 +330,6 @@ module Adaptation
284
330
  parse xml_message
285
331
  end
286
332
 
287
- # Checks if an Adaptation::Message object passes all validations.
288
- #
289
- # It is an alias for <em>Adaptation::Message#valid?</em>
290
- def check
291
- valid?
292
- end
293
-
294
333
  end
295
334
 
296
335
  end
@@ -3,11 +3,6 @@ $environment = "test"
3
3
 
4
4
  Adaptation::Initializer.run
5
5
 
6
- # for adaptations that require models from a rails application, sometimes
7
- # rails needs to load the environment.rb from the rails app. When this happens
8
- # the following variable must be set.
9
- ENV['RAILS_ENV'] = "test"
10
-
11
6
  if File.exists?("config/database.yml")
12
7
  begin
13
8
  require 'active_record/fixtures'
@@ -71,7 +66,7 @@ class Test::Unit::TestCase
71
66
  message_symbol.to_s
72
67
  message_object.clear_errors
73
68
  assert_block error do
74
- message_object.check
69
+ message_object.valid?
75
70
  end
76
71
  end
77
72
 
@@ -84,7 +79,7 @@ class Test::Unit::TestCase
84
79
  "? message shouldn't validate",
85
80
  message_symbol.to_s
86
81
  assert_block error do
87
- !message_object.check
82
+ !message_object.valid?
88
83
  end
89
84
  end
90
85
 
@@ -100,7 +95,7 @@ class Test::Unit::TestCase
100
95
  if message_object.is_a?(String)
101
96
  # build Message object with xml_data
102
97
  message_type = xml_message[1..(xml_message.index(/(>| )/) - 1)]
103
- message_class = get_class_object(message_type.capitalize)
98
+ message_class = Adaptation::Message.get_class_object(message_type.capitalize)
104
99
  message_object = message_class.to_object(xml_message)
105
100
  end
106
101
 
@@ -199,6 +194,7 @@ class Test::Unit::TestCase
199
194
 
200
195
  end
201
196
 
197
+ # Asserts a file exists
202
198
  def assert_file_present file
203
199
  error = build_message error,
204
200
  "? not found",
@@ -208,6 +204,7 @@ class Test::Unit::TestCase
208
204
  end
209
205
  end
210
206
 
207
+ # Asserts a file doesn't exist
211
208
  def assert_file_not_present file
212
209
  error = build_message error,
213
210
  "? shouldn't exist",
@@ -262,16 +259,11 @@ class Test::Unit::TestCase
262
259
  def load_message_fixture fixture_symbol #:nodoc:
263
260
  data = get_message_fixture(fixture_symbol.to_s)
264
261
  class_name = data[1..(data.index(/(>| )/) - 1)].capitalize
265
- message_class = get_class_object(class_name) rescue Adaptation::Message
266
- message_object = message_class.to_object(data)
262
+ message_class = Adaptation::Message.get_class_object(class_name)
263
+ message_object = message_class.nil? ? data : message_class.to_object(data)
267
264
  [data, message_object]
268
265
  end
269
266
 
270
- # TODO: this method is repeated in different parts of the code... module?
271
- def get_class_object(searched_class) #:nodoc:
272
- Object.const_get searched_class
273
- end
274
-
275
267
  def compare_xml_elements element1, element2 #:nodoc:
276
268
  if element1.has_attributes?
277
269
  if !element2.has_attributes?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adaptation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xavi Vila Morell
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-05 00:00:00 +01:00
12
+ date: 2009-01-08 00:00:00 +01:00
13
13
  default_executable: adaptation
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -50,7 +50,6 @@ files:
50
50
  - bin/generate
51
51
  - bin/console
52
52
  - bin/mom
53
- - lib/breakpoint.rb
54
53
  - lib/adaptation
55
54
  - lib/adaptation/base.rb
56
55
  - lib/adaptation/console
@@ -118,7 +117,6 @@ files:
118
117
  - lib/commands/subscribe.rb
119
118
  - lib/commands/destroy.rb
120
119
  - lib/commands/generate.rb
121
- - lib/breakpoint_client.rb
122
120
  - helpers/application.rb
123
121
  - helpers/test.rb
124
122
  - helpers/publish.rb
data/lib/breakpoint.rb DELETED
@@ -1,554 +0,0 @@
1
- # The Breakpoint library provides the convenience of
2
- # being able to inspect and modify state, diagnose
3
- # bugs all via IRB by simply setting breakpoints in
4
- # your applications by the call of a method.
5
- #
6
- # This library was written and is supported by me,
7
- # Florian Gross. I can be reached at flgr@ccan.de
8
- # and enjoy getting feedback about my libraries.
9
- #
10
- # The whole library (including breakpoint_client.rb
11
- # and binding_of_caller.rb) is licensed under the
12
- # same license that Ruby uses. (Which is currently
13
- # either the GNU General Public License or a custom
14
- # one that allows for commercial usage.) If you for
15
- # some good reason need to use this under another
16
- # license please contact me.
17
-
18
- require 'irb'
19
- if RUBY_VERSION == '1.8.5'
20
- puts "HOLA!"
21
- def Binding.of_caller(&block)
22
- raise "Breakpoints are not currently working with Ruby 1.8.5"
23
- end
24
- else
25
- require 'binding_of_caller'
26
- end
27
- require 'drb'
28
- require 'drb/acl'
29
-
30
- module Breakpoint
31
- id = %q$Id: breakpoint.rb 92 2005-02-04 22:35:53Z flgr $
32
- Version = id.split(" ")[2].to_i
33
-
34
- extend self
35
-
36
- # This will pop up an interactive ruby session at a
37
- # pre-defined break point in a Ruby application. In
38
- # this session you can examine the environment of
39
- # the break point.
40
- #
41
- # You can get a list of variables in the context using
42
- # local_variables via +local_variables+. You can then
43
- # examine their values by typing their names.
44
- #
45
- # You can have a look at the call stack via +caller+.
46
- #
47
- # The source code around the location where the breakpoint
48
- # was executed can be examined via +source_lines+. Its
49
- # argument specifies how much lines of context to display.
50
- # The default amount of context is 5 lines. Note that
51
- # the call to +source_lines+ can raise an exception when
52
- # it isn't able to read in the source code.
53
- #
54
- # breakpoints can also return a value. They will execute
55
- # a supplied block for getting a default return value.
56
- # A custom value can be returned from the session by doing
57
- # +throw(:debug_return, value)+.
58
- #
59
- # You can also give names to break points which will be
60
- # used in the message that is displayed upon execution
61
- # of them.
62
- #
63
- # Here's a sample of how breakpoints should be placed:
64
- #
65
- # class Person
66
- # def initialize(name, age)
67
- # @name, @age = name, age
68
- # breakpoint("Person#initialize")
69
- # end
70
- #
71
- # attr_reader :age
72
- # def name
73
- # breakpoint("Person#name") { @name }
74
- # end
75
- # end
76
- #
77
- # person = Person.new("Random Person", 23)
78
- # puts "Name: #{person.name}"
79
- #
80
- # And here is a sample debug session:
81
- #
82
- # Executing break point "Person#initialize" at file.rb:4 in `initialize'
83
- # irb(#<Person:0x292fbe8>):001:0> local_variables
84
- # => ["name", "age", "_", "__"]
85
- # irb(#<Person:0x292fbe8>):002:0> [name, age]
86
- # => ["Random Person", 23]
87
- # irb(#<Person:0x292fbe8>):003:0> [@name, @age]
88
- # => ["Random Person", 23]
89
- # irb(#<Person:0x292fbe8>):004:0> self
90
- # => #<Person:0x292fbe8 @age=23, @name="Random Person">
91
- # irb(#<Person:0x292fbe8>):005:0> @age += 1; self
92
- # => #<Person:0x292fbe8 @age=24, @name="Random Person">
93
- # irb(#<Person:0x292fbe8>):006:0> exit
94
- # Executing break point "Person#name" at file.rb:9 in `name'
95
- # irb(#<Person:0x292fbe8>):001:0> throw(:debug_return, "Overriden name")
96
- # Name: Overriden name
97
- #
98
- # Breakpoint sessions will automatically have a few
99
- # convenience methods available. See Breakpoint::CommandBundle
100
- # for a list of them.
101
- #
102
- # Breakpoints can also be used remotely over sockets.
103
- # This is implemented by running part of the IRB session
104
- # in the application and part of it in a special client.
105
- # You have to call Breakpoint.activate_drb to enable
106
- # support for remote breakpoints and then run
107
- # breakpoint_client.rb which is distributed with this
108
- # library. See the documentation of Breakpoint.activate_drb
109
- # for details.
110
- def breakpoint(id = nil, context = nil, &block)
111
- callstack = caller
112
- callstack.slice!(0, 3) if callstack.first["breakpoint"]
113
- file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
114
-
115
- message = "Executing break point " + (id ? "#{id.inspect} " : "") +
116
- "at #{file}:#{line}" + (method ? " in `#{method}'" : "")
117
-
118
- if context then
119
- return handle_breakpoint(context, message, file, line, &block)
120
- end
121
-
122
- Binding.of_caller do |binding_context|
123
- handle_breakpoint(binding_context, message, file, line, &block)
124
- end
125
- end
126
-
127
- module CommandBundle
128
- # Proxy to a Breakpoint client. Lets you directly execute code
129
- # in the context of the client.
130
- class Client
131
- def initialize(eval_handler) # :nodoc:
132
- eval_handler.untaint
133
- @eval_handler = eval_handler
134
- end
135
-
136
- instance_methods.each do |method|
137
- next if method[/^__.+__$/]
138
- undef_method method
139
- end
140
-
141
- # Executes the specified code at the client.
142
- def eval(code)
143
- @eval_handler.call(code)
144
- end
145
-
146
- # Will execute the specified statement at the client.
147
- def method_missing(method, *args, &block)
148
- if args.empty? and not block
149
- result = eval "#{method}"
150
- else
151
- # This is a bit ugly. The alternative would be using an
152
- # eval context instead of an eval handler for executing
153
- # the code at the client. The problem with that approach
154
- # is that we would have to handle special expressions
155
- # like "self", "nil" or constants ourself which is hard.
156
- remote = eval %{
157
- result = lambda { |block, *args| #{method}(*args, &block) }
158
- def result.call_with_block(*args, &block)
159
- call(block, *args)
160
- end
161
- result
162
- }
163
- remote.call_with_block(*args, &block)
164
- end
165
-
166
- return result
167
- end
168
- end
169
-
170
- # Returns the source code surrounding the location where the
171
- # breakpoint was issued.
172
- def source_lines(context = 5, return_line_numbers = false)
173
- lines = File.readlines(@__bp_file).map { |line| line.chomp }
174
-
175
- break_line = @__bp_line
176
- start_line = [break_line - context, 1].max
177
- end_line = break_line + context
178
-
179
- result = lines[(start_line - 1) .. (end_line - 1)]
180
-
181
- if return_line_numbers then
182
- return [start_line, break_line, result]
183
- else
184
- return result
185
- end
186
- end
187
-
188
- # Prints the source code surrounding the location where the
189
- # breakpoint was issued.
190
- def show_source_list(context = 5)
191
- start_line, break_line, result = source_lines(context, true)
192
- offset = [(break_line + context).to_s.length, 4].max
193
- result.each_with_index do |line, i|
194
- mark = (start_line + i == break_line ? '->' : ' ')
195
- client.puts("%0#{offset}d%s#{line}" % [start_line + i, mark])
196
- end
197
- Pathname.new(@__bp_file).cleanpath.to_s
198
- end
199
-
200
- # Prints the call stack.
201
- def show_call_stack(depth = 10)
202
- base = Pathname.new(RAILS_ROOT).cleanpath.to_s
203
- caller[1..depth].each do |line|
204
- line.sub!(/^[^:]*/) do |path|
205
- Pathname.new(path).cleanpath.to_s
206
- end
207
- client.puts(line.index(base) == 0 ? line[(base.length + 1)..-1] : line)
208
- end
209
- "#{Pathname.new(@__bp_file).cleanpath.to_s}:#{@__bp_line}"
210
- end
211
-
212
- # Lets an object that will forward method calls to the breakpoint
213
- # client. This is useful for outputting longer things at the client
214
- # and so on. You can for example do these things:
215
- #
216
- # client.puts "Hello" # outputs "Hello" at client console
217
- # # outputs "Hello" into the file temp.txt at the client
218
- # client.File.open("temp.txt", "w") { |f| f.puts "Hello" }
219
- def client()
220
- if Breakpoint.use_drb? then
221
- sleep(0.5) until Breakpoint.drb_service.eval_handler
222
- Client.new(Breakpoint.drb_service.eval_handler)
223
- else
224
- Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
225
- end
226
- end
227
- end
228
-
229
- def handle_breakpoint(context, message, file = "", line = "", &block) # :nodoc:
230
- catch(:debug_return) do |value|
231
- eval(%{
232
- @__bp_file = #{file.inspect}
233
- @__bp_line = #{line}
234
- extend Breakpoint::CommandBundle
235
- extend DRbUndumped if self
236
- }, context) rescue nil
237
-
238
- if not use_drb? then
239
- puts message
240
- IRB.start(nil, IRB::WorkSpace.new(context))
241
- else
242
- @drb_service.add_breakpoint(context, message)
243
- end
244
-
245
- block.call if block
246
- end
247
- end
248
-
249
- # These exceptions will be raised on failed asserts
250
- # if Breakpoint.asserts_cause_exceptions is set to
251
- # true.
252
- class FailedAssertError < RuntimeError
253
- end
254
-
255
- # This asserts that the block evaluates to true.
256
- # If it doesn't evaluate to true a breakpoint will
257
- # automatically be created at that execution point.
258
- #
259
- # You can disable assert checking in production
260
- # code by setting Breakpoint.optimize_asserts to
261
- # true. (It will still be enabled when Ruby is run
262
- # via the -d argument.)
263
- #
264
- # Example:
265
- # person_name = "Foobar"
266
- # assert { not person_name.nil? }
267
- #
268
- # Note: If you want to use this method from an
269
- # unit test, you will have to call it by its full
270
- # name, Breakpoint.assert.
271
- def assert(context = nil, &condition)
272
- return if Breakpoint.optimize_asserts and not $DEBUG
273
- return if yield
274
-
275
- callstack = caller
276
- callstack.slice!(0, 3) if callstack.first["assert"]
277
- file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
278
-
279
- message = "Assert failed at #{file}:#{line}#{" in `#{method}'" if method}."
280
-
281
- if Breakpoint.asserts_cause_exceptions and not $DEBUG then
282
- raise(Breakpoint::FailedAssertError, message)
283
- end
284
-
285
- message += " Executing implicit breakpoint."
286
-
287
- if context then
288
- return handle_breakpoint(context, message, file, line)
289
- end
290
-
291
- Binding.of_caller do |context|
292
- handle_breakpoint(context, message, file, line)
293
- end
294
- end
295
-
296
- # Whether asserts should be ignored if not in debug mode.
297
- # Debug mode can be enabled by running ruby with the -d
298
- # switch or by setting $DEBUG to true.
299
- attr_accessor :optimize_asserts
300
- self.optimize_asserts = false
301
-
302
- # Whether an Exception should be raised on failed asserts
303
- # in non-$DEBUG code or not. By default this is disabled.
304
- attr_accessor :asserts_cause_exceptions
305
- self.asserts_cause_exceptions = false
306
- @use_drb = false
307
-
308
- attr_reader :drb_service # :nodoc:
309
-
310
- class DRbService # :nodoc:
311
- include DRbUndumped
312
-
313
- def initialize
314
- @handler = @eval_handler = @collision_handler = nil
315
-
316
- IRB.instance_eval { @CONF[:RC] = true }
317
- IRB.run_config
318
- end
319
-
320
- def collision
321
- sleep(0.5) until @collision_handler
322
-
323
- @collision_handler.untaint
324
-
325
- @collision_handler.call
326
- end
327
-
328
- def ping() end
329
-
330
- def add_breakpoint(context, message)
331
- workspace = IRB::WorkSpace.new(context)
332
- workspace.extend(DRbUndumped)
333
-
334
- sleep(0.5) until @handler
335
-
336
- @handler.untaint
337
- @handler.call(workspace, message)
338
- end
339
-
340
- attr_accessor :handler, :eval_handler, :collision_handler
341
- end
342
-
343
- # Will run Breakpoint in DRb mode. This will spawn a server
344
- # that can be attached to via the breakpoint-client command
345
- # whenever a breakpoint is executed. This is useful when you
346
- # are debugging CGI applications or other applications where
347
- # you can't access debug sessions via the standard input and
348
- # output of your application.
349
- #
350
- # You can specify an URI where the DRb server will run at.
351
- # This way you can specify the port the server runs on. The
352
- # default URI is druby://localhost:42531.
353
- #
354
- # Please note that breakpoints will be skipped silently in
355
- # case the DRb server can not spawned. (This can happen if
356
- # the port is already used by another instance of your
357
- # application on CGI or another application.)
358
- #
359
- # Also note that by default this will only allow access
360
- # from localhost. You can however specify a list of
361
- # allowed hosts or nil (to allow access from everywhere).
362
- # But that will still not protect you from somebody
363
- # reading the data as it goes through the net.
364
- #
365
- # A good approach for getting security and remote access
366
- # is setting up an SSH tunnel between the DRb service
367
- # and the client. This is usually done like this:
368
- #
369
- # $ ssh -L20000:127.0.0.1:20000 -R10000:127.0.0.1:10000 example.com
370
- # (This will connect port 20000 at the client side to port
371
- # 20000 at the server side, and port 10000 at the server
372
- # side to port 10000 at the client side.)
373
- #
374
- # After that do this on the server side: (the code being debugged)
375
- # Breakpoint.activate_drb("druby://127.0.0.1:20000", "localhost")
376
- #
377
- # And at the client side:
378
- # ruby breakpoint_client.rb -c druby://127.0.0.1:10000 -s druby://127.0.0.1:20000
379
- #
380
- # Running through such a SSH proxy will also let you use
381
- # breakpoint.rb in case you are behind a firewall.
382
- #
383
- # Detailed information about running DRb through firewalls is
384
- # available at http://www.rubygarden.org/ruby?DrbTutorial
385
- def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'],
386
- ignore_collisions = false)
387
-
388
- return false if @use_drb
389
-
390
- uri ||= 'druby://localhost:42531'
391
-
392
- if allowed_hosts then
393
- acl = ["deny", "all"]
394
-
395
- Array(allowed_hosts).each do |host|
396
- acl += ["allow", host]
397
- end
398
-
399
- DRb.install_acl(ACL.new(acl))
400
- end
401
-
402
- @use_drb = true
403
- @drb_service = DRbService.new
404
- did_collision = false
405
- begin
406
- @service = DRb.start_service(uri, @drb_service)
407
- rescue Errno::EADDRINUSE
408
- if ignore_collisions then
409
- nil
410
- else
411
- # The port is already occupied by another
412
- # Breakpoint service. We will try to tell
413
- # the old service that we want its port.
414
- # It will then forward that request to the
415
- # user and retry.
416
- unless did_collision then
417
- DRbObject.new(nil, uri).collision
418
- did_collision = true
419
- end
420
- sleep(10)
421
- retry
422
- end
423
- end
424
-
425
- return true
426
- end
427
-
428
- # Deactivates a running Breakpoint service.
429
- def deactivate_drb
430
- @service.stop_service unless @service.nil?
431
- @service = nil
432
- @use_drb = false
433
- @drb_service = nil
434
- end
435
-
436
- # Returns true when Breakpoints are used over DRb.
437
- # Breakpoint.activate_drb causes this to be true.
438
- def use_drb?
439
- @use_drb == true
440
- end
441
- end
442
-
443
- module IRB # :nodoc:
444
- class << self; remove_method :start; end
445
- def self.start(ap_path = nil, main_context = nil, workspace = nil)
446
- $0 = File::basename(ap_path, ".rb") if ap_path
447
-
448
- # suppress some warnings about redefined constants
449
- old_verbose, $VERBOSE = $VERBOSE, nil
450
- IRB.setup(ap_path)
451
- $VERBOSE = old_verbose
452
-
453
- if @CONF[:SCRIPT] then
454
- irb = Irb.new(main_context, @CONF[:SCRIPT])
455
- else
456
- irb = Irb.new(main_context)
457
- end
458
-
459
- if workspace then
460
- irb.context.workspace = workspace
461
- end
462
-
463
- @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
464
- @CONF[:MAIN_CONTEXT] = irb.context
465
-
466
- old_sigint = trap("SIGINT") do
467
- begin
468
- irb.signal_handle
469
- rescue RubyLex::TerminateLineInput
470
- # ignored
471
- end
472
- end
473
-
474
- catch(:IRB_EXIT) do
475
- irb.eval_input
476
- end
477
- ensure
478
- trap("SIGINT", old_sigint)
479
- end
480
-
481
- class << self
482
- alias :old_CurrentContext :CurrentContext
483
- remove_method :CurrentContext
484
- end
485
- def IRB.CurrentContext
486
- if old_CurrentContext.nil? and Breakpoint.use_drb? then
487
- result = Object.new
488
- def result.last_value; end
489
- return result
490
- else
491
- old_CurrentContext
492
- end
493
- end
494
- def IRB.parse_opts() end
495
-
496
- class Context #:nodoc:
497
- alias :old_evaluate :evaluate
498
- def evaluate(line, line_no)
499
- if line.chomp == "exit" then
500
- exit
501
- else
502
- old_evaluate(line, line_no)
503
- end
504
- end
505
- end
506
-
507
- class WorkSpace #:nodoc:
508
- alias :old_evaluate :evaluate
509
-
510
- def evaluate(*args)
511
- if Breakpoint.use_drb? then
512
- result = old_evaluate(*args)
513
- if args[0] != :no_proxy and
514
- not [true, false, nil].include?(result)
515
- then
516
- result.extend(DRbUndumped) rescue nil
517
- end
518
- return result
519
- else
520
- old_evaluate(*args)
521
- end
522
- end
523
- end
524
-
525
- module InputCompletor #:nodoc:
526
- def self.eval(code, context, *more)
527
- # Big hack, this assumes that InputCompletor
528
- # will only call eval() when it wants code
529
- # to be executed in the IRB context.
530
- IRB.conf[:MAIN_CONTEXT].workspace.evaluate(:no_proxy, code, *more)
531
- end
532
- end
533
- end
534
-
535
- module DRb #:nodoc:
536
- class DRbObject #:nodoc:
537
- undef :inspect if method_defined?(:inspect)
538
- undef :clone if method_defined?(:clone)
539
- end
540
- end
541
-
542
- # See Breakpoint.breakpoint
543
- def breakpoint(id = nil, &block)
544
- Binding.of_caller do |context|
545
- Breakpoint.breakpoint(id, context, &block)
546
- end
547
- end
548
-
549
- # See Breakpoint.assert
550
- def assert(&block)
551
- Binding.of_caller do |context|
552
- Breakpoint.assert(context, &block)
553
- end
554
- end
@@ -1,196 +0,0 @@
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
- ) { |v| Options[:ClientURI] = v }
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
- ) { |v| Options[:ServerURI] = v }
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
- ) { |v| Options[:RetryDelay] = v }
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
- ) { |v| Options[:Permanent] = v }
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
- ) { |v| Options[:Verbose] = v }
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 #:nodoc:
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