activerecord 1.4.0 → 1.5.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.

Files changed (55) hide show
  1. data/CHANGELOG +98 -0
  2. data/install.rb +1 -0
  3. data/lib/active_record.rb +1 -0
  4. data/lib/active_record/acts/list.rb +19 -16
  5. data/lib/active_record/associations.rb +164 -164
  6. data/lib/active_record/associations/association_collection.rb +44 -71
  7. data/lib/active_record/associations/association_proxy.rb +76 -0
  8. data/lib/active_record/associations/belongs_to_association.rb +74 -0
  9. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +34 -21
  10. data/lib/active_record/associations/has_many_association.rb +34 -30
  11. data/lib/active_record/associations/has_one_association.rb +48 -0
  12. data/lib/active_record/base.rb +62 -18
  13. data/lib/active_record/callbacks.rb +17 -8
  14. data/lib/active_record/connection_adapters/abstract_adapter.rb +11 -10
  15. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/postgresql_adapter.rb +29 -1
  17. data/lib/active_record/connection_adapters/sqlite_adapter.rb +94 -73
  18. data/lib/active_record/deprecated_associations.rb +46 -8
  19. data/lib/active_record/fixtures.rb +1 -1
  20. data/lib/active_record/observer.rb +5 -1
  21. data/lib/active_record/support/binding_of_caller.rb +72 -68
  22. data/lib/active_record/support/breakpoint.rb +526 -524
  23. data/lib/active_record/support/class_inheritable_attributes.rb +105 -29
  24. data/lib/active_record/support/core_ext.rb +1 -0
  25. data/lib/active_record/support/core_ext/hash.rb +5 -0
  26. data/lib/active_record/support/core_ext/hash/keys.rb +35 -0
  27. data/lib/active_record/support/core_ext/numeric.rb +7 -0
  28. data/lib/active_record/support/core_ext/numeric/bytes.rb +33 -0
  29. data/lib/active_record/support/core_ext/numeric/time.rb +59 -0
  30. data/lib/active_record/support/core_ext/string.rb +5 -0
  31. data/lib/active_record/support/core_ext/string/inflections.rb +41 -0
  32. data/lib/active_record/support/dependencies.rb +1 -14
  33. data/lib/active_record/support/inflector.rb +6 -6
  34. data/lib/active_record/support/misc.rb +0 -24
  35. data/lib/active_record/validations.rb +34 -1
  36. data/lib/active_record/vendor/mysql411.rb +305 -0
  37. data/rakefile +11 -2
  38. data/test/abstract_unit.rb +1 -2
  39. data/test/associations_test.rb +234 -23
  40. data/test/base_test.rb +50 -1
  41. data/test/callbacks_test.rb +16 -0
  42. data/test/connections/native_mysql/connection.rb +2 -2
  43. data/test/connections/native_sqlite3/connection.rb +34 -0
  44. data/test/deprecated_associations_test.rb +36 -2
  45. data/test/fixtures/company.rb +2 -0
  46. data/test/fixtures/computer.rb +3 -0
  47. data/test/fixtures/computers.yml +3 -0
  48. data/test/fixtures/db_definitions/db2.sql +5 -0
  49. data/test/fixtures/db_definitions/mysql.sql +5 -0
  50. data/test/fixtures/db_definitions/postgresql.sql +5 -0
  51. data/test/fixtures/db_definitions/sqlite.sql +5 -0
  52. data/test/fixtures/db_definitions/sqlserver.sql +5 -1
  53. data/test/fixtures/fixture_database.sqlite +0 -0
  54. data/test/validations_test.rb +21 -0
  55. metadata +22 -2
@@ -1,41 +1,117 @@
1
+ # Retain for backward compatibility. Methods are now included in Class.
2
+ module ClassInheritableAttributes # :nodoc:
3
+ end
4
+
1
5
  # Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
2
6
  # their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
3
7
  # to, for example, an array without those additions being shared with either their parent, siblings, or
4
8
  # children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
5
- module ClassInheritableAttributes # :nodoc:
6
- def self.append_features(base)
7
- super
8
- base.extend(ClassMethods)
9
- end
10
-
11
- module ClassMethods # :nodoc:
12
- @@classes ||= {}
13
-
14
- def inheritable_attributes
15
- @@classes[self] ||= {}
16
- end
17
-
18
- def write_inheritable_attribute(key, value)
19
- inheritable_attributes[key] = value
9
+ class Class # :nodoc:
10
+ def class_inheritable_reader(*syms)
11
+ syms.each do |sym|
12
+ class_eval <<-EOS
13
+ def self.#{sym}
14
+ read_inheritable_attribute(:#{sym})
15
+ end
16
+
17
+ def #{sym}
18
+ self.class.#{sym}
19
+ end
20
+ EOS
20
21
  end
21
-
22
- def write_inheritable_array(key, elements)
23
- write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
24
- write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
22
+ end
23
+
24
+ def class_inheritable_writer(*syms)
25
+ syms.each do |sym|
26
+ class_eval <<-EOS
27
+ def self.#{sym}=(obj)
28
+ write_inheritable_attribute(:#{sym}, obj)
29
+ end
30
+
31
+ def #{sym}=(obj)
32
+ self.class.#{sym} = obj
33
+ end
34
+ EOS
25
35
  end
36
+ end
37
+
38
+ def class_inheritable_array_writer(*syms)
39
+ syms.each do |sym|
40
+ class_eval <<-EOS
41
+ def self.#{sym}=(obj)
42
+ write_inheritable_array(:#{sym}, obj)
43
+ end
26
44
 
27
- def read_inheritable_attribute(key)
28
- inheritable_attributes[key]
45
+ def #{sym}=(obj)
46
+ self.class.#{sym} = obj
47
+ end
48
+ EOS
29
49
  end
30
-
31
- def reset_inheritable_attributes
32
- inheritable_attributes.clear
50
+ end
51
+
52
+ def class_inheritable_hash_writer(*syms)
53
+ syms.each do |sym|
54
+ class_eval <<-EOS
55
+ def self.#{sym}=(obj)
56
+ write_inheritable_hash(:#{sym}, obj)
57
+ end
58
+
59
+ def #{sym}=(obj)
60
+ self.class.#{sym} = obj
61
+ end
62
+ EOS
33
63
  end
64
+ end
65
+
66
+ def class_inheritable_accessor(*syms)
67
+ class_inheritable_reader(*syms)
68
+ class_inheritable_writer(*syms)
69
+ end
34
70
 
35
- private
36
- def inherited(child)
37
- @@classes[child] = inheritable_attributes.dup
38
- end
39
-
71
+ def class_inheritable_array(*syms)
72
+ class_inheritable_reader(*syms)
73
+ class_inheritable_array_writer(*syms)
40
74
  end
75
+
76
+ def class_inheritable_hash(*syms)
77
+ class_inheritable_reader(*syms)
78
+ class_inheritable_hash_writer(*syms)
79
+ end
80
+
81
+ def inheritable_attributes
82
+ @inheritable_attributes ||= {}
83
+ end
84
+
85
+ def write_inheritable_attribute(key, value)
86
+ inheritable_attributes[key] = value
87
+ end
88
+
89
+ def write_inheritable_array(key, elements)
90
+ write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
91
+ write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
92
+ end
93
+
94
+ def write_inheritable_hash(key, hash)
95
+ write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
96
+ write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
97
+ end
98
+
99
+ def read_inheritable_attribute(key)
100
+ inheritable_attributes[key]
101
+ end
102
+
103
+ def reset_inheritable_attributes
104
+ inheritable_attributes.clear
105
+ end
106
+
107
+ private
108
+ def inherited_with_inheritable_attributes(child)
109
+ inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
110
+ child.instance_variable_set('@inheritable_attributes', inheritable_attributes.dup)
111
+ end
112
+
113
+ if respond_to?(:inherited)
114
+ alias_method :inherited_without_inheritable_attributes, :inherited
115
+ end
116
+ alias_method :inherited, :inherited_with_inheritable_attributes
41
117
  end
@@ -0,0 +1 @@
1
+ Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each { |file| require(file) }
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/hash/keys'
2
+
3
+ class Hash #:nodoc:
4
+ include ActiveSupport::CoreExtensions::Hash::Keys
5
+ end
@@ -0,0 +1,35 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Hash #:nodoc:
4
+ module Keys
5
+
6
+ # Return a new hash with all keys converted to symbols.
7
+ def symbolize_keys
8
+ inject({}) do |options, (key, value)|
9
+ options[key.to_sym] = value
10
+ options
11
+ end
12
+ end
13
+
14
+ # Destructively convert all keys to symbols.
15
+ def symbolize_keys!
16
+ keys.each do |key|
17
+ unless key.is_a?(Symbol)
18
+ self[key.to_sym] = self[key]
19
+ delete(key)
20
+ end
21
+ end
22
+ self
23
+ end
24
+
25
+ alias_method :to_options, :symbolize_keys
26
+ alias_method :to_options!, :symbolize_keys!
27
+
28
+ def assert_valid_keys(valid_keys)
29
+ unknown_keys = keys - valid_keys
30
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/numeric/time'
2
+ require File.dirname(__FILE__) + '/numeric/bytes'
3
+
4
+ class Numeric #:nodoc:
5
+ include ActiveSupport::CoreExtensions::Numeric::Time
6
+ include ActiveSupport::CoreExtensions::Numeric::Bytes
7
+ end
@@ -0,0 +1,33 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Numeric #:nodoc:
4
+ # Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
5
+ module Bytes
6
+ def bytes
7
+ self
8
+ end
9
+ alias :byte :bytes
10
+
11
+ def kilobytes
12
+ self * 1024
13
+ end
14
+ alias :kilobyte :kilobytes
15
+
16
+ def megabytes
17
+ self * 1024.kilobytes
18
+ end
19
+ alias :megabyte :megabytes
20
+
21
+ def gigabytes
22
+ self * 1024.megabytes
23
+ end
24
+ alias :gigabyte :gigabytes
25
+
26
+ def terabytes
27
+ self * 1024.gigabytes
28
+ end
29
+ alias :terabyte :terabytes
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,59 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Numeric #:nodoc:
4
+ # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years
5
+ module Time
6
+ def minutes
7
+ self * 60
8
+ end
9
+ alias :minute :minutes
10
+
11
+ def hours
12
+ self * 60.minutes
13
+ end
14
+ alias :hour :hours
15
+
16
+ def days
17
+ self * 24.hours
18
+ end
19
+ alias :day :days
20
+
21
+ def weeks
22
+ self * 7.days
23
+ end
24
+ alias :week :weeks
25
+
26
+ def fortnights
27
+ self * 2.weeks
28
+ end
29
+ alias :fortnight :fortnights
30
+
31
+ def months
32
+ self * 30.days
33
+ end
34
+ alias :month :months
35
+
36
+ def years
37
+ self * 365.days
38
+ end
39
+ alias :year :years
40
+
41
+ # Reads best without arguments: 10.minutes.ago
42
+ def ago(time = ::Time.now)
43
+ time - self
44
+ end
45
+
46
+ # Reads best with argument: 10.minutes.until(time)
47
+ alias :until :ago
48
+
49
+ # Reads best with argument: 10.minutes.since(time)
50
+ def since(time = ::Time.now)
51
+ time + self
52
+ end
53
+
54
+ # Reads best without arguments: 10.minutes.from_now
55
+ alias :from_now :since
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/string/inflections'
2
+
3
+ class String #:nodoc:
4
+ include ActiveSupport::CoreExtensions::String::Inflections
5
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../../inflector'
2
+ module ActiveSupport #:nodoc:
3
+ module CoreExtensions #:nodoc:
4
+ module String #:nodoc:
5
+ # Makes it possible to do "posts".singularize that returns "post" and "MegaCoolClass".underscore that returns "mega_cool_class".
6
+ module Inflections
7
+ def pluralize
8
+ Inflector.pluralize(self)
9
+ end
10
+
11
+ def singularize
12
+ Inflector.singularize(self)
13
+ end
14
+
15
+ def camelize
16
+ Inflector.camelize(self)
17
+ end
18
+
19
+ def underscore
20
+ Inflector.underscore(self)
21
+ end
22
+
23
+ def demodulize
24
+ Inflector.demodulize(self)
25
+ end
26
+
27
+ def tableize
28
+ Inflector.tableize(self)
29
+ end
30
+
31
+ def classify
32
+ Inflector.classify(self)
33
+ end
34
+
35
+ def foreign_key(separate_class_name_and_id_with_underscore = true)
36
+ Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -24,19 +24,6 @@ module Dependencies
24
24
  def associate_with(file_name)
25
25
  depend_on(file_name, true)
26
26
  end
27
-
28
- def reload
29
- old_loaded = loaded
30
- clear
31
-
32
- old_loaded.each do |file_name|
33
- begin
34
- silence_warnings { load("#{file_name}.rb") }
35
- rescue LoadError
36
- # The association didn't reside in its own file, so we assume it was required by other means
37
- end
38
- end
39
- end
40
27
 
41
28
  def clear
42
29
  self.loaded = [ ]
@@ -51,7 +38,7 @@ end
51
38
  Object.send(:define_method, :require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
52
39
  Object.send(:define_method, :require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
53
40
 
54
- class Object
41
+ class Object #:nodoc:
55
42
  class << self
56
43
  # Use const_missing to autoload associations so we don't have to
57
44
  # require_association when using single-table inheritance.
@@ -4,7 +4,7 @@ module Inflector
4
4
  extend self
5
5
 
6
6
  def pluralize(word)
7
- result = word.dup
7
+ result = word.to_s.dup
8
8
  plural_rules.each do |(rule, replacement)|
9
9
  break if result.gsub!(rule, replacement)
10
10
  end
@@ -12,7 +12,7 @@ module Inflector
12
12
  end
13
13
 
14
14
  def singularize(word)
15
- result = word.dup
15
+ result = word.to_s.dup
16
16
  singular_rules.each do |(rule, replacement)|
17
17
  break if result.gsub!(rule, replacement)
18
18
  end
@@ -20,15 +20,15 @@ module Inflector
20
20
  end
21
21
 
22
22
  def camelize(lower_case_and_underscored_word)
23
- lower_case_and_underscored_word.gsub(/(^|_)(.)/){$2.upcase}
23
+ lower_case_and_underscored_word.to_s.gsub(/(^|_)(.)/){$2.upcase}
24
24
  end
25
25
 
26
26
  def underscore(camel_cased_word)
27
- camel_cased_word.gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
27
+ camel_cased_word.to_s.gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
28
28
  end
29
29
 
30
30
  def demodulize(class_name_in_module)
31
- class_name_in_module.gsub(/^.*::/, '')
31
+ class_name_in_module.to_s.gsub(/^.*::/, '')
32
32
  end
33
33
 
34
34
  def tableize(class_name)
@@ -47,7 +47,7 @@ module Inflector
47
47
  private
48
48
  def plural_rules #:doc:
49
49
  [
50
- [/(x|ch|ss)$/, '\1es'], # search, switch, fix, box, process, address
50
+ [/(x|ch|ss|sh)$/, '\1es'], # search, switch, fix, box, process, address
51
51
  [/([^aeiouy]|qu)ies$/, '\1y'],
52
52
  [/([^aeiouy]|qu)y$/, '\1ies'], # query, ability, agency
53
53
  [/(?:([^f])fe|([lr])f)$/, '\1\2ves'], # half, safe, wife
@@ -6,27 +6,3 @@ def silence_warnings
6
6
  $VERBOSE = old_verbose
7
7
  end
8
8
  end
9
-
10
- class Hash
11
- # Return a new hash with all keys converted to symbols.
12
- def symbolize_keys
13
- inject({}) do |options, (key, value)|
14
- options[key.to_sym] = value
15
- options
16
- end
17
- end
18
-
19
- # Destructively convert all keys to symbols.
20
- def symbolize_keys!
21
- keys.each do |key|
22
- unless key.is_a?(Symbol)
23
- self[key.to_sym] = self[key]
24
- delete(key)
25
- end
26
- end
27
- self
28
- end
29
-
30
- alias_method :to_options, :symbolize_keys
31
- alias_method :to_options!, :symbolize_keys!
32
- end