drx 0.4.2 → 0.4.3

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,44 @@
1
+ require 'rubygems'
2
+ require 'activerecord'
3
+
4
+ #
5
+ # This is part of a blogging website. Users write posts. A post
6
+ # belongs to a user.
7
+ #
8
+
9
+ ActiveRecord::Base.logger = Logger.new(STDERR)
10
+ ActiveRecord::Base.colorize_logging = false
11
+
12
+ ActiveRecord::Base.establish_connection(
13
+ :adapter => 'sqlite3',
14
+ :database => ':memory:'
15
+ )
16
+
17
+ ActiveRecord::Schema.define do
18
+ create_table :users do |table|
19
+ table.column :name, :string
20
+ table.column :mail, :string
21
+ end
22
+ create_table :posts do |table|
23
+ table.column :user_id, :integer
24
+ table.column :title, :string
25
+ table.column :body, :string
26
+ end
27
+ end
28
+
29
+ class User < ActiveRecord::Base
30
+ has_many :posts
31
+ end
32
+
33
+ class Post < ActiveRecord::Base
34
+ belongs_to :users
35
+ end
36
+
37
+ david = User.create(:name => 'David')
38
+ david.posts.create(:title => 'Lies')
39
+ david.posts.create(:title => 'Truths')
40
+
41
+ post = User.find(1).posts.first
42
+
43
+ require 'drx'
44
+ post.see
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'sequel'
3
+
4
+ #
5
+ # This is part of a blogging website. Users write posts. A post
6
+ # belongs to a user.
7
+ #
8
+
9
+ DB = Sequel.sqlite(':memory:')
10
+
11
+ DB.create_table :posts do
12
+ primary_key :id
13
+ Integer :user_id
14
+ String :title
15
+ String :body
16
+ end
17
+
18
+ DB.create_table :users do
19
+ primary_key :id
20
+ String :name
21
+ String :email
22
+ end
23
+
24
+ class Post < Sequel::Model
25
+ many_to_one :user
26
+ end
27
+
28
+ class User < Sequel::Model
29
+ one_to_many :posts
30
+ end
31
+
32
+ post = Post.create(:title => 'Lies', :user => User.create(:name => 'David'))
33
+
34
+ require 'drx'
35
+ post.see
@@ -0,0 +1,103 @@
1
+ # Adds method arguments detection to ObjInfo
2
+
3
+ module Drx
4
+
5
+ class ObjInfo
6
+
7
+ class << self
8
+ # Whether to use the 'arguments' gem, if present.
9
+ # This isn't on by default because it's slow.
10
+ attr_accessor :use_arguments_gem
11
+ end
12
+
13
+ # Returns a Ruby 1.9.2-compatible array describing the arguments a method expects.
14
+ def method_arguments(method_name)
15
+ if ObjInfo.use_arguments_gem
16
+ _method_arguments__by_arguments_gem(method_name) || _method_arguments__by_arity(method_name)
17
+ else
18
+ _method_arguments__by_methopara(method_name) || _method_arguments__by_arity(method_name)
19
+ end
20
+ end
21
+
22
+ # Strategy: use the 'arguments' gem, which, in turn, uses either ParseTree (Ruby 1.8)
23
+ # or RubyParser (Ruby 1.9)
24
+ #
25
+ # pros: shows default values; works for 1.8 too.
26
+ # cons: very slow.
27
+ def _method_arguments__by_arguments_gem(method_name)
28
+ @@once__arguments ||= begin
29
+ begin
30
+ require 'arguments'
31
+ rescue LoadError
32
+ # Not installed.
33
+ end
34
+ 1
35
+ end
36
+ return nil if not defined? Arguments
37
+ args = Arguments.names(the_object, method_name, false)
38
+ # Convert this to a Ruby 1.9.2 format:
39
+ return args.map do |arg|
40
+ if arg.size == 2
41
+ [:opt, arg[0], arg[1]]
42
+ else
43
+ name = arg[0].to_s
44
+ case name[0,1]
45
+ when '*' then [:rest, name[1..-1]]
46
+ when '&' then [:block, name[1..-1]]
47
+ else [:req, name]
48
+ end
49
+ end
50
+ end
51
+ rescue SyntaxError => e
52
+ # We could just return nil here, to continue to the next strategy,
53
+ # but we want to inform the user of the suckiness of RubyParser.
54
+ raise
55
+ rescue Exception
56
+ nil
57
+ end
58
+
59
+ # Strategy: use Method#parameters (for ruby 1.9 only).
60
+ #
61
+ # pros: fast.
62
+ # cons: doesn't show default values.
63
+ def _method_arguments__by_methopara(method_name)
64
+ @@once__methopara ||= begin
65
+ # For ruby 1.9.0 and 1.9.1, we need to use a gem.
66
+ begin
67
+ require 'methopara'
68
+ rescue LoadError
69
+ # Not installed.
70
+ end
71
+ 1
72
+ end
73
+ method = the_object.instance_method(method_name)
74
+ if method.respond_to? :parameters
75
+ return method.parameters
76
+ end
77
+ rescue NotImplementedError
78
+ # For some methods #parameters raises an exception. We return nil
79
+ # to move on to the next strategy.
80
+ return nil
81
+ end
82
+
83
+ # Strategy: simulation via Method#arity.
84
+ #
85
+ # This is used as a fallback if any of the other strategies fail.
86
+ #
87
+ # pros: fast; work without any gems.
88
+ # cons: doesn't show argument names.
89
+ def _method_arguments__by_arity(method_name)
90
+ method = the_object.instance_method(method_name)
91
+ ary, rest = method.arity, false
92
+ if ary < 0
93
+ ary = -ary - 1
94
+ rest = true
95
+ end
96
+ args = [[:req]] * ary
97
+ args << [:rest] if rest
98
+ return args
99
+ end
100
+
101
+ end
102
+
103
+ end
data/lib/drx/graphviz.rb CHANGED
@@ -8,7 +8,8 @@ module Drx
8
8
  # - Windows' CMD.EXE too supports "2>&1"
9
9
  # - We're generating GIF, not PNG, because that's a format Tk
10
10
  # supports out of the box.
11
- GRAPHVIZ_COMMAND = 'dot "%s" -Tgif -o "%s" -Tcmapx -o "%s" 2>&1'
11
+ # - Each {extension} token is replaced by the filepath with that extension.
12
+ GRAPHVIZ_COMMAND = 'dot "{dot}" -Tgif -o "{gif}" -Tcmapx -o "{map}" 2>&1'
12
13
 
13
14
  @@sizes = {
14
15
  '100%' => "
@@ -128,7 +129,7 @@ module Drx
128
129
  out
129
130
  end
130
131
 
131
- def dot_fragment(opts = {}, &block) # :yield:
132
+ def dot_fragment(opts = {}, ancestors = [], &block) # :yield:
132
133
  out = ''
133
134
  # Note: since 'obj' may be a T_ICLASS, it doesn't respond to many methods,
134
135
  # including is_a?. So when we're querying things we're using Drx calls
@@ -147,9 +148,9 @@ module Drx
147
148
  return '' if seen
148
149
 
149
150
  if class_like?
150
- if spr = self.super and display_super?(spr)
151
- out << spr.dot_fragment(opts, &block)
152
- if insignificant_super_arrow?(opts)
151
+ if spr = self.super and display_super?(spr, ancestors)
152
+ out << spr.dot_fragment(opts, ancestors + [self], &block)
153
+ if insignificant_super_arrow?(opts, ancestors)
153
154
  # We don't want these relatively insignificant lines to clutter the display,
154
155
  # so we paint them lightly and tell DOT they aren't to affect the layout (width=0).
155
156
  out << "#{dot_id} -> #{spr.dot_id} [color=gray85, weight=0];" "\n"
@@ -172,6 +173,12 @@ module Drx
172
173
  # (To see the effect of this, set the weight unconditionally to '0' and
173
174
  # see the graph for DataMapper.)
174
175
  weight = t_iclass? ? 1 : 0
176
+
177
+ # However, here's a special case. DOT seems to have a bug: it sometimes
178
+ # doesn't draw the arrows going out of Class and Module (to their
179
+ # singletons). Making their weight 1 makes DOT draw them.
180
+ weight = 1 if self == _Class or self == _Module
181
+
175
182
  out << "#{dot_id} -> #{kls.dot_id} [style=dotted, weight=#{weight}];" "\n"
176
183
  out << "{ rank=same; #{dot_id}; #{kls.dot_id}; }" "\n"
177
184
  end
@@ -187,11 +194,13 @@ module Drx
187
194
  # following method is to break the cycle. Normally we break the cycle at
188
195
  # Module (and its singleton). When the user is examining a module, we
189
196
  # instead break the cycle at Class (and its singleton).
190
- def insignificant_super_arrow?(opts)
197
+ def insignificant_super_arrow?(opts, my_ancestors)
191
198
  if opts[:base].t_module?
192
- [Class, ObjInfo.new(Class).klass.the_object].include? the_object
199
+ self == _ClassS or
200
+ (self.super == _Module and (my_ancestors + [self]).include? _Class)
193
201
  else
194
- [Module, ObjInfo.new(Module).klass.the_object].include? the_object
202
+ self == _ModuleS or
203
+ (self.super == _Object and (my_ancestors + [self]).include? _Module)
195
204
  end
196
205
  end
197
206
 
@@ -203,7 +212,17 @@ module Drx
203
212
  # Usually this means that the ICLASS has a singleton (see "Singletons
204
213
  # of included modules" in display_super?()). We want to see this
205
214
  # singleton.
206
- return Module != kls.the_object
215
+
216
+ # Unfortunately, here is a special treatment for the 'arguments' gem,
217
+ # which our GUI uses. That gem includes the 'Arguments' module in both
218
+ # Class and Module (this is redundant!) and having the singleton twice
219
+ # in our graph may break its nice rectangular structure. So we don't
220
+ # show its singleton.
221
+ if defined? ::Arguments
222
+ return false if ::Arguments == klass.the_object
223
+ end
224
+
225
+ return kls != _Module
207
226
  else
208
227
  # Displaying a singleton's klass is confusing and usually unneeded.
209
228
  return !singleton?
@@ -211,16 +230,19 @@ module Drx
211
230
  end
212
231
 
213
232
  # Whether to display the super.
214
- def display_super?(spr)
215
- if (singleton? or t_iclass?) and Module == spr.the_object
216
- # Singletons of included modules, and modules included in them,
217
- # have their chain eventually reach Module. To prevent clutter,
218
- # we don't show this final link.
219
- #
220
- # "Singletons of included modules" often exist only for their
221
- # #included method. For example, DataMapper#Resource have
222
- # such a singleton.
223
- return false
233
+ def display_super?(spr, my_ancestors)
234
+ if spr == _Module
235
+ # Many objects have Module as their super (e.g., singletones
236
+ # of included modules, or modules included in them). To prevent
237
+ # clutter we print the arrow to Module only if it comes from
238
+ # Class (or a module included in it).
239
+ return (my_ancestors + [self]).include? _Class
240
+ #
241
+ # A somewhat irrelevant note (I don't have a better place to put it):
242
+ #
243
+ # "Singletons of included modules" often exist solely for their
244
+ # #included method. For example, DataMapper#Resource has
245
+ # such a singleton.
224
246
  end
225
247
  return true
226
248
  end
@@ -237,8 +259,19 @@ module Drx
237
259
  end
238
260
  end
239
261
 
262
+ # Shortcuts for some specific objects. An "S" suffix
263
+ # denotes a singleton.
264
+ protected
265
+ def _Module; ObjInfo.new(Module); end
266
+ def _ModuleS; ObjInfo.new(Module).klass; end
267
+ def _Object; ObjInfo.new(Object); end
268
+ def _ObjectS; ObjInfo.new(Object).klass; end
269
+ def _Class; ObjInfo.new(Class); end
270
+ def _ClassS; ObjInfo.new(Class).klass; end
271
+ public
272
+
240
273
  # Generates a diagram of the inheritance hierarchy. It accepts a hash
241
- # pointing to pathnames to write the result to. A Tempfiles hash
274
+ # pointing to filepaths to write the result to. A Tempfiles hash
242
275
  # can be used instead.
243
276
  #
244
277
  # the_object = "some object"
@@ -250,7 +283,8 @@ module Drx
250
283
  def generate_diagram(files, opts = {}, &block)
251
284
  source = self.dot_source(opts, &block)
252
285
  File.open(files['dot'], 'w') { |f| f.write(source) }
253
- command = GRAPHVIZ_COMMAND % [files['dot'], files['gif'], files['map']]
286
+ # Replace {extension} tokens with their corresponding filepaths:
287
+ command = GRAPHVIZ_COMMAND.gsub(/\{([a-z]+)\}/) { files[$1] }
254
288
  message = Kernel.`(command) # `
255
289
  if $? != 0
256
290
  error = <<-EOS % [command, message]
data/lib/drx/objinfo.rb CHANGED
@@ -19,6 +19,10 @@ module Drx
19
19
  Core::get_address(@obj)
20
20
  end
21
21
 
22
+ def ==(other)
23
+ other.is_a?(ObjInfo) and address == other.address
24
+ end
25
+
22
26
  def the_object
23
27
  @obj
24
28
  end
@@ -70,8 +74,9 @@ module Drx
70
74
  Core::get_iv_tbl(@obj)
71
75
  end
72
76
 
73
- # @todo: this could be nicer. perhaps define an [] accessor.
74
- def __get_ivar(name)
77
+ # Returns the value of an instance variable. Actually, of any sort
78
+ # of variable that's recorded in the variable-table.
79
+ def get_ivar(name)
75
80
  if class_like? and name.to_s =~ /^[A-Z]/
76
81
  # If it's a constant, it may be 'autoloaded'. We
77
82
  # trigger the loading by calling const_get().
@@ -120,7 +125,7 @@ module Drx
120
125
  if t_iclass?
121
126
  'include ' + klass.repr
122
127
  elsif singleton?
123
- attached = __get_ivar('__attached__') || self
128
+ attached = get_ivar('__attached__') || self
124
129
  attached.inspect + " 'S"
125
130
  else
126
131
  @obj.inspect
data/lib/drx/tk/app.rb CHANGED
@@ -11,8 +11,23 @@ module Drx
11
11
 
12
12
  class Application
13
13
 
14
+ # Loads ~/.drxrc.
15
+ #
16
+ # @see Application#user_customizations
17
+ def self.load_rc
18
+ @rc_loaded ||= begin
19
+ rc = File.join(ENV['HOME'] || Dir.pwd, '.drxrc')
20
+ load rc if File.exist? rc
21
+ 1
22
+ end
23
+ end
24
+
25
+ # Returns the top-level frame in which to show ourselves.
14
26
  def toplevel
15
- @toplevel ||= TkRoot.new
27
+ @toplevel ||= begin
28
+ # We're showing ourselves inside a TkRoot, unless one already exists.
29
+ Application.first_window? ? TkRoot.new : TkToplevel.new
30
+ end
16
31
  end
17
32
 
18
33
  def initialize
@@ -56,12 +71,16 @@ module Drx
56
71
  show 'headings'
57
72
  }
58
73
  @methodsbox = Tk::Tile::Treeview.new(toplevel) {
59
- columns 'name location'
74
+ columns 'name arguments location'
60
75
  heading_configure('name', :text => 'Name')
76
+ heading_configure('arguments', :text => 'Arguments')
61
77
  heading_configure('location', :text => 'Location')
62
78
  column_configure('name', :stretch => false )
79
+ column_configure('arguments', :stretch => false )
63
80
  column_configure('location', :stretch => false )
64
81
  show 'headings'
82
+ # We want the layout manager to allocate space for two columns only:
83
+ displaycolumns 'name location'
65
84
  }
66
85
 
67
86
  @graph_size_menu = Tk::Tile::Combobox.new(toplevel) {
@@ -83,6 +102,15 @@ module Drx
83
102
  save_graph tip
84
103
  }
85
104
 
105
+ @show_arguments_chk = TkCheckbutton.new(toplevel) {
106
+ text 'Show arguments'
107
+ variable TkVariable.new(0)
108
+ }
109
+ @use_arguments_gem_chk = TkCheckbutton.new(toplevel) {
110
+ text "Use the 'arguments' gem (slower)"
111
+ variable TkVariable.new(0)
112
+ }
113
+
86
114
  layout
87
115
 
88
116
  @varsbox.bind('<TreeviewSelect>') {
@@ -141,30 +169,45 @@ module Drx
141
169
  @graph_opts[:style] = @graph_style_menu.get
142
170
  refresh
143
171
  }
172
+ @show_arguments_chk.variable.trace('w') do |value,|
173
+ if value == 1
174
+ @use_arguments_gem_chk.raise
175
+ @methodsbox.displaycolumns 'name arguments location'
176
+ display_methods(current_object)
177
+ else
178
+ @use_arguments_gem_chk.lower
179
+ @methodsbox.displaycolumns 'name location'
180
+ end
181
+ end
182
+ @use_arguments_gem_chk.variable.trace('w') do |value,|
183
+ ObjInfo.use_arguments_gem = (value == 1)
184
+ display_methods(current_object)
185
+ end
186
+ @show_arguments_chk.variable.value = @show_arguments_chk.variable.value # Trigger the trace handler.
144
187
 
145
188
  output "Please visit the homepage, http://drx.rubyforge.org/, for usage instructions.\n", 'info'
146
189
 
147
- one_time_initialization
190
+ Application.load_rc
191
+ system_customizations
148
192
  user_customizations
149
193
  end
150
194
 
151
- def one_time_initialization
152
- @@one_time_initialization ||= begin
195
+ # Users may redefine this method in their ~/.drxrc
196
+ # to fine-tune the app.
197
+ def user_customizations
198
+ end
199
+
200
+ # The following are default customizations. They are subjective in
201
+ # nature and users may knock them out in their ~/.drxrc.
202
+ def system_customizations
203
+ if Application.first_window?
153
204
  # Try to make the Unixy GUI less ugly.
154
205
  if Tk.windowingsystem == 'x11' and Ttk.themes.include? 'clam'
155
206
  Ttk.set_theme 'clam'
156
207
  end
157
- rc = File.join(ENV['HOME'] || Dir.pwd, '.drxrc')
158
- load rc if File.exist? rc
159
- 1
160
208
  end
161
209
  end
162
210
 
163
- # Users may redefine this method in their ~/.drxrc
164
- # to fine-tune the app.
165
- def user_customizations
166
- end
167
-
168
211
  def vbox(*args); VBox.new(toplevel, args); end
169
212
  def hbox(*args); HBox.new(toplevel, args); end
170
213
  def separator; TkLabel.new(toplevel, :text => ' '); end
@@ -204,7 +247,8 @@ module Drx
204
247
  ), :weight => 50
205
248
  panes.add vbox(
206
249
  TkLabel.new(toplevel, :text => 'Methods (m_tbl):', :anchor => 'w'),
207
- [Scrolled.new(toplevel, @methodsbox), { :expand => true, :fill => 'both' } ]
250
+ [Scrolled.new(toplevel, @methodsbox), { :expand => true, :fill => 'both' } ],
251
+ hbox(@show_arguments_chk, separator, @use_arguments_gem_chk)
208
252
  ), :weight => 10
209
253
 
210
254
  main_frame.add(panes)
@@ -221,11 +265,10 @@ module Drx
221
265
  def open_up_editor(filename, lineno)
222
266
  command = sprintf(ENV['DRX_EDITOR_COMMAND'] || EDITOR_COMMAND, lineno, filename)
223
267
  output "Executing: #{command}...\n", 'info'
224
- if !fork
268
+ Thread.new do
225
269
  if !Kernel.system(command)
226
270
  output "Could not execute the command '#{command}'\n", 'error'
227
271
  end
228
- exit!
229
272
  end
230
273
  end
231
274
 
@@ -250,7 +293,7 @@ module Drx
250
293
  end
251
294
 
252
295
  def selected_var
253
- ObjInfo.new(current_object).__get_ivar(@varsbox.get_selection)
296
+ ObjInfo.new(current_object).get_ivar(@varsbox.get_selection)
254
297
  end
255
298
 
256
299
  def eval_code(code)
@@ -289,14 +332,20 @@ module Drx
289
332
  # Get rid of gazillions of Tk classes:
290
333
  vars = vars.reject { |v| v =~ /Tk|Ttk/ }
291
334
  vars.each do |name|
292
- value = if allowed_names.any? { |p| p === name }
293
- info.__get_ivar(name).inspect
294
- else
295
- # We don't want to inspect ruby's internal variables (because
296
- # they may not be Ruby values at all).
297
- ''
298
- end
299
- @varsbox.insert('', 'end', :text => name, :values => [ name, value ] )
335
+ begin
336
+ value = if allowed_names.any? { |p| p === name }
337
+ info.get_ivar(name).inspect
338
+ else
339
+ # We don't want to inspect ruby's internal variables (because
340
+ # they may not be Ruby values at all).
341
+ ''
342
+ end
343
+ @varsbox.insert('', 'end', :text => name, :values => [ name, value ] )
344
+ rescue NameError
345
+ # Referencing an autoloaded constant (in ObjInfo#get_ivar()) may
346
+ # raise a NameError. This happens when the source file autoloaded
347
+ # defines the moudle/class in the top-level. Example is Camping::Mab.
348
+ end
300
349
  end
301
350
  end
302
351
  end
@@ -321,6 +370,27 @@ module Drx
321
370
  end
322
371
  end
323
372
 
373
+ # Returns a string describing a method's arguments, for use in GUIs.
374
+ def pretty_arguments(info, name)
375
+ args = info.method_arguments(name)
376
+ return args.map do |arg|
377
+ case arg[0]
378
+ when :req; (arg[1] || 'arg').to_s
379
+ when :opt; (arg[1] || 'arg').to_s + '=' + (arg[2] || '?')
380
+ when :rest; '*' + (arg[1] || 'args').to_s
381
+ when :block; '&' + (arg[1] || 'arg').to_s
382
+ end
383
+ end.join ', '
384
+ rescue NameError
385
+ return '---'
386
+ rescue SyntaxError => e
387
+ 'SYNTAX ERROR: ' + e.to_s
388
+ end
389
+
390
+ def show_arguments?
391
+ @show_arguments_chk.variable == 1
392
+ end
393
+
324
394
  # Fills the methods listbox with a list of the object's methods.
325
395
  def display_methods(obj)
326
396
  @methodsbox.clear
@@ -328,7 +398,11 @@ module Drx
328
398
  if obj and info.class_like?
329
399
  methods = info.m_tbl.keys.map do |v| v.to_s end.sort
330
400
  methods.each do |name|
331
- @methodsbox.insert('', 'end', :text => name, :values => [ name, pretty_location(info, name) ] )
401
+ @methodsbox.insert('', 'end', :text => name, :values => [
402
+ name,
403
+ show_arguments? ? pretty_arguments(info, name) : '-',
404
+ pretty_location(info, name)
405
+ ])
332
406
  end
333
407
  end
334
408
  end
@@ -357,11 +431,19 @@ module Drx
357
431
  end
358
432
  end
359
433
 
434
+ # Updates the window title (usually shown in the taskbar).
435
+ def update_title(obj)
436
+ toplevel.title = 'Drx: ' + begin
437
+ obj.is_a?(Module) ? obj.name : obj.class.name
438
+ end.to_s # In case of singletons, #name returns nil, so to_s enforces a string.
439
+ end
440
+
360
441
  # Makes `obj` the primary object seen (the one which is the tip of the diagram).
361
442
  def navigate_to(obj)
362
443
  @current_object = obj
363
444
  @navigation_history << obj
364
445
  display_graph(obj)
446
+ update_title(obj)
365
447
  # Trigger the update of the variables and methods tables by selecting this object
366
448
  # in the imagemap.
367
449
  @im.active_url = @im.urls.first
@@ -391,9 +473,17 @@ module Drx
391
473
  navigate_to(current_object)
392
474
  end
393
475
 
476
+ class << self
477
+ attr_accessor :in_loop
478
+ def first_window?; !in_loop; end
479
+ end
480
+
394
481
  def run
395
- # @todo Skip this if Tk is already running.
482
+ return if Application.in_loop
483
+ # @todo Any other way to detect that Tk's mainloop is already running?
484
+ Application.in_loop = true
396
485
  Tk.mainloop
486
+ Application.in_loop = false
397
487
  Tk.restart # So that Tk doesn't complain 'can't invoke "frame" command: application has been destroyed' next time.
398
488
  end
399
489
  end
data/lib/drx.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'drx_core' # The C extension.
4
4
  require 'drx/objinfo'
5
+ require 'drx/arguments'
5
6
  require 'drx/graphviz'
6
7
 
7
8
  module Drx
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: drx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mooffie
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-04-02 00:00:00 +03:00
12
+ date: 2010-04-16 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -27,6 +27,7 @@ files:
27
27
  - lib/drx/tk/imagemap.rb
28
28
  - lib/drx/tk/app.rb
29
29
  - lib/drx/objinfo.rb
30
+ - lib/drx/arguments.rb
30
31
  - lib/drx/tempfiles.rb
31
32
  - lib/drx.rb
32
33
  - ext/extconf.rb
@@ -34,7 +35,8 @@ files:
34
35
  - examples/drx_datamapper.rb
35
36
  - examples/drx_date.rb
36
37
  - examples/drx_guitar.rb
37
- - examples/drx_datamapper19.rb
38
+ - examples/drx_activerecord.rb
39
+ - examples/drx_sequel.rb
38
40
  has_rdoc: true
39
41
  homepage: http://drx.rubyforge.org/
40
42
  licenses: []
@@ -1,35 +0,0 @@
1
- require 'rubygems'
2
- require 'dm-core'
3
- $: << File.join('/home/mooffie/_drx.git/lib')
4
- require 'drx'
5
-
6
-
7
-
8
- #
9
- # This is part of a blogging website. Users write posts. A post
10
- # belongs to a user.
11
- #
12
-
13
- class Post
14
- include DataMapper::Resource
15
-
16
- property :post_id, Serial
17
- property :title, String
18
- property :body, Text
19
-
20
- belongs_to :user
21
- end
22
-
23
- class User
24
- include DataMapper::Resource
25
-
26
- property :user_uid, Serial
27
- property :name, String
28
- property :mail, String
29
- end
30
-
31
- post = Post.new
32
-
33
- p post
34
- require 'drx'
35
- post.see