activerecord 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

@@ -16,11 +16,14 @@
16
16
  # license please contact me.
17
17
 
18
18
  require 'irb'
19
- # require 'binding_of_caller' <- Needs this
19
+ require File.dirname(__FILE__) + '/binding_of_caller'
20
20
  require 'drb'
21
21
  require 'drb/acl'
22
22
 
23
23
  module Breakpoint
24
+ id = %q$Id: breakpoint.rb 41 2005-01-22 20:22:10Z flgr $
25
+ Version = id.split(" ")[2].to_i
26
+
24
27
  extend self
25
28
 
26
29
  # This will pop up an interactive ruby session at a
@@ -114,10 +117,10 @@ module Breakpoint
114
117
  end
115
118
  end
116
119
 
117
- module CommandBundle #:nodoc:
120
+ module CommandBundle
118
121
  # Proxy to a Breakpoint client. Lets you directly execute code
119
122
  # in the context of the client.
120
- class Client#:nodoc:
123
+ class Client
121
124
  def initialize(eval_handler) # :nodoc:
122
125
  @eval_handler = eval_handler
123
126
  end
@@ -133,15 +136,23 @@ module Breakpoint
133
136
  end
134
137
 
135
138
  # Will execute the specified statement at the client.
136
- def method_missing(method, *args)
137
- if args.empty?
138
- result = eval("#{method}")
139
+ def method_missing(method, *args, &block)
140
+ if args.empty? and not block
141
+ result = eval "#{method}"
139
142
  else
140
- result = eval("#{method}(*Marshal.load(#{Marshal.dump(args).inspect}))")
141
- end
142
-
143
- unless [true, false, nil].include?(result)
144
- result.extend(DRbUndumped) if result
143
+ # This is a bit ugly. The alternative would be using an
144
+ # eval context instead of an eval handler for executing
145
+ # the code at the client. The problem with that approach
146
+ # is that we would have to handle special expressions
147
+ # like "self", "nil" or constants ourself which is hard.
148
+ remote = eval %{
149
+ result = lambda { |block, *args| #{method}(*args, &block) }
150
+ def result.call_with_block(*args, &block)
151
+ call(block, *args)
152
+ end
153
+ result
154
+ }
155
+ remote.call_with_block(*args, &block)
145
156
  end
146
157
 
147
158
  return result
@@ -175,6 +186,7 @@ module Breakpoint
175
186
  # client.File.open("temp.txt", "w") { |f| f.puts "Hello" }
176
187
  def client()
177
188
  if Breakpoint.use_drb? then
189
+ sleep(0.5) until Breakpoint.drb_service.eval_handler
178
190
  Client.new(Breakpoint.drb_service.eval_handler)
179
191
  else
180
192
  Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
@@ -205,7 +217,7 @@ module Breakpoint
205
217
  # These exceptions will be raised on failed asserts
206
218
  # if Breakpoint.asserts_cause_exceptions is set to
207
219
  # true.
208
- class FailedAssertError < RuntimeError#:nodoc:
220
+ class FailedAssertError < RuntimeError
209
221
  end
210
222
 
211
223
  # This asserts that the block evaluates to true.
@@ -279,7 +291,7 @@ module Breakpoint
279
291
  @collision_handler.call
280
292
  end
281
293
 
282
- def ping; end
294
+ def ping() end
283
295
 
284
296
  def add_breakpoint(context, message)
285
297
  workspace = IRB::WorkSpace.new(context)
@@ -290,31 +302,7 @@ module Breakpoint
290
302
  @handler.call(workspace, message)
291
303
  end
292
304
 
293
- def register_handler(&block)
294
- @handler = block
295
- end
296
-
297
- def unregister_handler
298
- @handler = nil
299
- end
300
-
301
- attr_reader :eval_handler
302
-
303
- def register_eval_handler(&block)
304
- @eval_handler = block
305
- end
306
-
307
- def unregister_eval_handler
308
- @eval_handler = lambda { }
309
- end
310
-
311
- def register_collision_handler(&block)
312
- @collision_handler = block
313
- end
314
-
315
- def unregister_collision_handler
316
- @collision_handler = lambda { }
317
- end
305
+ attr_accessor :handler, :eval_handler, :collision_handler
318
306
  end
319
307
 
320
308
  # Will run Breakpoint in DRb mode. This will spawn a server
@@ -359,7 +347,8 @@ module Breakpoint
359
347
  #
360
348
  # Detailed information about running DRb through firewalls is
361
349
  # available at http://www.rubygarden.org/ruby?DrbTutorial
362
- def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'], ignore_collisions = false) #:nodoc:
350
+ def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'],
351
+ ignore_collisions = false)
363
352
 
364
353
  return false if @use_drb
365
354
 
@@ -402,7 +391,7 @@ module Breakpoint
402
391
  end
403
392
 
404
393
  # Deactivates a running Breakpoint service.
405
- def deactivate_drb #:nodoc:
394
+ def deactivate_drb
406
395
  @service.stop_service unless @service.nil?
407
396
  @service = nil
408
397
  @use_drb = false
@@ -411,14 +400,12 @@ module Breakpoint
411
400
 
412
401
  # Returns true when Breakpoints are used over DRb.
413
402
  # Breakpoint.activate_drb causes this to be true.
414
- def use_drb? #:nodoc:
403
+ def use_drb?
415
404
  @use_drb == true
416
405
  end
417
406
  end
418
407
 
419
408
  module IRB # :nodoc:
420
- def IRB.parse_opts() end
421
-
422
409
  class << self; remove_method :start; end
423
410
  def self.start(ap_path = nil, main_context = nil, workspace = nil)
424
411
  $0 = File::basename(ap_path, ".rb") if ap_path
@@ -442,7 +429,11 @@ module IRB # :nodoc:
442
429
  @CONF[:MAIN_CONTEXT] = irb.context
443
430
 
444
431
  old_sigint = trap("SIGINT") do
445
- irb.signal_handle
432
+ begin
433
+ irb.signal_handle
434
+ rescue RubyLex::TerminateLineInput
435
+ # ignored
436
+ end
446
437
  end
447
438
 
448
439
  catch(:IRB_EXIT) do
@@ -466,7 +457,7 @@ module IRB # :nodoc:
466
457
  end
467
458
  end
468
459
 
469
- class Context#:nodoc:
460
+ class Context
470
461
  alias :old_evaluate :evaluate
471
462
  def evaluate(line, line_no)
472
463
  if line.chomp == "exit" then
@@ -477,7 +468,7 @@ module IRB # :nodoc:
477
468
  end
478
469
  end
479
470
 
480
- class WorkSpace#:nodoc:
471
+ class WorkSpace
481
472
  alias :old_evaluate :evaluate
482
473
 
483
474
  def evaluate(*args)
@@ -495,7 +486,7 @@ module IRB # :nodoc:
495
486
  end
496
487
  end
497
488
 
498
- module InputCompletor#:nodoc:
489
+ module InputCompletor
499
490
  def self.eval(code, context, *more)
500
491
  # Big hack, this assumes that InputCompletor
501
492
  # will only call eval() when it wants code
@@ -506,9 +497,9 @@ module IRB # :nodoc:
506
497
  end
507
498
 
508
499
  module DRb # :nodoc:
509
- class DRbObject#:nodoc:
510
- undef :inspect
511
- undef :clone
500
+ class DRbObject
501
+ undef :inspect if method_defined?(:inspect)
502
+ undef :clone if method_defined?(:clone)
512
503
  end
513
504
  end
514
505
 
@@ -524,4 +515,4 @@ def assert(&block)
524
515
  Binding.of_caller do |context|
525
516
  Breakpoint.assert(context, &block)
526
517
  end
527
- end
518
+ end
@@ -0,0 +1,24 @@
1
+ class Object #:nodoc:
2
+ def remove_subclasses_of(superclass)
3
+ subclasses_of(superclass).each { |subclass| Object.send(:remove_const, subclass) rescue nil }
4
+ end
5
+
6
+ def subclasses_of(superclass)
7
+ subclasses = []
8
+ ObjectSpace.each_object(Class) do |k|
9
+ next if !k.ancestors.include?(superclass) || superclass == k || k.to_s.include?("::") || subclasses.include?(k.to_s)
10
+ subclasses << k.to_s
11
+ end
12
+ subclasses
13
+ end
14
+ end
15
+
16
+ class Class #:nodoc:
17
+ def remove_subclasses
18
+ Object.remove_subclasses_of(self)
19
+ end
20
+
21
+ def subclasses
22
+ Object.subclasses_of(self)
23
+ end
24
+ end
@@ -9,14 +9,19 @@ module Dependencies
9
9
  @@mechanism = :load
10
10
  mattr_accessor :mechanism
11
11
 
12
+ def load?
13
+ mechanism == :load
14
+ end
15
+
12
16
  def depend_on(file_name, swallow_load_errors = false)
13
17
  if !loaded.include?(file_name)
14
18
  loaded << file_name
15
-
16
19
  begin
17
20
  require_or_load(file_name)
18
21
  rescue LoadError
19
22
  raise unless swallow_load_errors
23
+ rescue Object => e
24
+ raise ScriptError, "#{e.message}"
20
25
  end
21
26
  end
22
27
  end
@@ -29,12 +34,16 @@ module Dependencies
29
34
  self.loaded = [ ]
30
35
  end
31
36
 
32
- private
33
- def require_or_load(file_name)
34
- mechanism == :load ? silence_warnings { load("#{file_name}.rb") } : require(file_name)
35
- end
37
+ def require_or_load(file_name)
38
+ load? ? load("#{file_name}.rb") : require(file_name)
39
+ end
40
+
41
+ def remove_subclasses_for(*classes)
42
+ classes.each { |klass| klass.remove_subclasses }
43
+ end
36
44
  end
37
45
 
46
+ Object.send(:define_method, :require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
38
47
  Object.send(:define_method, :require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
39
48
  Object.send(:define_method, :require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
40
49
 
@@ -42,16 +51,12 @@ class Object #:nodoc:
42
51
  class << self
43
52
  # Use const_missing to autoload associations so we don't have to
44
53
  # require_association when using single-table inheritance.
45
- unless respond_to?(:pre_dependency_const_missing)
46
- alias_method :pre_dependency_const_missing, :const_missing
47
-
48
- def const_missing(class_id)
49
- begin
50
- require_dependency(Inflector.underscore(Inflector.demodulize(class_id.to_s)))
51
- return Object.const_get(class_id) if Object.const_defined?(class_id)
52
- rescue LoadError
53
- pre_dependency_const_missing(class_id)
54
- end
54
+ def const_missing(class_id)
55
+ begin
56
+ require_or_load(class_id.to_s.demodulize.underscore)
57
+ if Object.const_defined?(class_id) then return Object.const_get(class_id) else raise LoadError end
58
+ rescue LoadError
59
+ raise NameError, "uninitialized constant #{class_id}"
55
60
  end
56
61
  end
57
62
  end
@@ -4,6 +4,7 @@ module ActiveRecord
4
4
  # automatically included, so you don't need to do that manually.
5
5
  #
6
6
  # This behavior can be turned off by setting <tt>ActiveRecord::Base.record_timestamps = false</tt>.
7
+ # This behavior can use GMT by setting <tt>ActiveRecord::Base.timestamps_gmt = true</tt>
7
8
  module Timestamp
8
9
  def self.append_features(base) # :nodoc:
9
10
  super
@@ -18,18 +19,20 @@ module ActiveRecord
18
19
  end
19
20
 
20
21
  def create_with_timestamps
21
- write_attribute("created_at", Time.now) if record_timestamps && respond_to?(:created_at) && created_at.nil?
22
- write_attribute("created_on", Time.now) if record_timestamps && respond_to?(:created_on) && created_on.nil?
22
+ t = timestamps_gmt ? Time.now.gmtime : Time.now
23
+ write_attribute("created_at", t) if record_timestamps && respond_to?(:created_at) && created_at.nil?
24
+ write_attribute("created_on", t) if record_timestamps && respond_to?(:created_on) && created_on.nil?
23
25
 
24
- write_attribute("updated_at", Time.now) if record_timestamps && respond_to?(:updated_at)
25
- write_attribute("updated_on", Time.now) if record_timestamps && respond_to?(:updated_on)
26
+ write_attribute("updated_at", t) if record_timestamps && respond_to?(:updated_at)
27
+ write_attribute("updated_on", t) if record_timestamps && respond_to?(:updated_on)
26
28
 
27
29
  create_without_timestamps
28
30
  end
29
31
 
30
32
  def update_with_timestamps
31
- write_attribute("updated_at", Time.now) if record_timestamps && respond_to?(:updated_at)
32
- write_attribute("updated_on", Time.now) if record_timestamps && respond_to?(:updated_on)
33
+ t = timestamps_gmt ? Time.now.gmtime : Time.now
34
+ write_attribute("updated_at", t) if record_timestamps && respond_to?(:updated_at)
35
+ write_attribute("updated_on", t) if record_timestamps && respond_to?(:updated_on)
33
36
 
34
37
  update_without_timestamps
35
38
  end
@@ -41,5 +44,7 @@ module ActiveRecord
41
44
  # if the table has columns of either of these names. This feature is turned on by default.
42
45
  @@record_timestamps = true
43
46
  cattr_accessor :record_timestamps
47
+ @@timestamps_gmt = false
48
+ cattr_accessor :timestamps_gmt
44
49
  end
45
- end
50
+ end
@@ -254,7 +254,7 @@ module ActiveRecord
254
254
  # Configuration options:
255
255
  # * <tt>in</tt> - An enumerable object of available items
256
256
  # * <tt>message</tt> - Specifieds a customer error message (default is: "is not included in the list")
257
- # * <tt>allows_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
257
+ # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
258
258
  def validates_inclusion_of(*attr_names)
259
259
  configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save }
260
260
  configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
@@ -372,9 +372,9 @@ module ActiveRecord
372
372
  validations = self.class.read_inheritable_attribute(validation_method.to_s)
373
373
  if validations.nil? then return end
374
374
  validations.each do |validation|
375
- if Symbol === validation
375
+ if validation.is_a?(Symbol)
376
376
  self.send(validation)
377
- elsif String === validation
377
+ elsif validation.is_a?(String)
378
378
  eval(validation, binding)
379
379
  elsif validation_block?(validation)
380
380
  validation.call(self)
@@ -255,7 +255,7 @@ class Mysql
255
255
  def_value = f[7]
256
256
  max_length = 0
257
257
 
258
- ret << Field::new(table_name, table_name, column_name, length, type, flags, decimals, def_value, max_length)
258
+ ret << Field::new(table_name, table_name, column_name_alias, length, type, flags, decimals, def_value, max_length)
259
259
  end
260
260
  ret
261
261
  end
data/rakefile CHANGED
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
8
8
 
9
9
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
10
10
  PKG_NAME = 'activerecord'
11
- PKG_VERSION = '1.5.1' + PKG_BUILD
11
+ PKG_VERSION = '1.6.0' + PKG_BUILD
12
12
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
13
13
 
14
14
  PKG_FILES = FileList[
@@ -0,0 +1,14 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/company'
3
+
4
+ class AssociationInheritanceReloadTest < Test::Unit::TestCase
5
+ fixtures :companies
6
+
7
+ def test_set_attributes
8
+ assert_equal ["errors.add_on_empty('name', \"can't be empty\")"], Firm.read_inheritable_attribute("validate"), "Second run"
9
+ # ActiveRecord::Base.reset_column_information_and_inheritable_attributes_for_all_subclasses
10
+ remove_subclass_of(ActiveRecord::Base)
11
+ load 'fixtures/company.rb'
12
+ assert_equal ["errors.add_on_empty('name', \"can't be empty\")"], Firm.read_inheritable_attribute("validate"), "Second run"
13
+ end
14
+ end
@@ -74,6 +74,10 @@ class HasOneAssociationsTest < Test::Unit::TestCase
74
74
  assert_equal Account.find(1).credit_limit, @signals37.account.credit_limit
75
75
  end
76
76
 
77
+ def test_triple_equality
78
+ assert Account === @signals37.account
79
+ end
80
+
77
81
  def test_type_mismatch
78
82
  assert_raises(ActiveRecord::AssociationTypeMismatch) { @signals37.account = 1 }
79
83
  assert_raises(ActiveRecord::AssociationTypeMismatch) { @signals37.account = Project.find(1) }
@@ -382,6 +386,14 @@ class HasManyAssociationsTest < Test::Unit::TestCase
382
386
  assert_equal 2, @signals37.clients_of_firm(true).size
383
387
  end
384
388
 
389
+ def test_build_many
390
+ new_clients = @signals37.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}])
391
+ assert_equal 2, new_clients.size
392
+
393
+ assert @signals37.save
394
+ assert_equal 3, @signals37.clients_of_firm(true).size
395
+ end
396
+
385
397
  def test_invalid_build
386
398
  new_client = @signals37.clients_of_firm.build
387
399
  assert new_client.new_record?
@@ -399,6 +411,11 @@ class HasManyAssociationsTest < Test::Unit::TestCase
399
411
  assert_equal new_client, @signals37.clients_of_firm.last
400
412
  assert_equal new_client, @signals37.clients_of_firm(true).last
401
413
  end
414
+
415
+ def test_create_many
416
+ @signals37.clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}])
417
+ assert_equal 3, @signals37.clients_of_firm(true).size
418
+ end
402
419
 
403
420
  def test_deleting
404
421
  force_signal37_to_load_all_clients_of_firm
@@ -720,6 +737,27 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
720
737
  assert_equal 2, aridridel.projects(true).size
721
738
  end
722
739
 
740
+ def test_habtm_adding_before_save_with_join_attributes
741
+ no_of_devels = Developer.count
742
+ no_of_projects = Project.count
743
+ now = Date.today
744
+ ken = Developer.new("name" => "Ken")
745
+ ken.projects.push_with_attributes( Project.find(1), :joined_on => now )
746
+ p = Project.new("name" => "Foomatic")
747
+ ken.projects.push_with_attributes( p, :joined_on => now )
748
+ assert ken.new_record?
749
+ assert p.new_record?
750
+ assert ken.save
751
+ assert !ken.new_record?
752
+ assert_equal no_of_devels+1, Developer.count
753
+ assert_equal no_of_projects+1, Project.count
754
+ assert_equal 2, ken.projects.size
755
+ assert_equal 2, ken.projects(true).size
756
+
757
+ kenReloaded = Developer.find_by_name 'Ken'
758
+ kenReloaded.projects.each { |prj| assert_equal(now.to_s, prj.joined_on.to_s) }
759
+ end
760
+
723
761
  def test_build
724
762
  devel = Developer.find(1)
725
763
  proj = devel.projects.build("name" => "Projekt")