adaptation 0.1.0 → 0.1.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/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