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.
- data/CHANGELOG +34 -0
- data/install.rb +11 -1
- data/lib/active_record/associations.rb +3 -2
- data/lib/active_record/associations/association_collection.rb +7 -3
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +24 -13
- data/lib/active_record/associations/has_many_association.rb +10 -6
- data/lib/active_record/base.rb +62 -29
- data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -3
- data/lib/active_record/fixtures.rb +1 -1
- data/lib/active_record/support/binding_of_caller.rb +83 -85
- data/lib/active_record/support/breakpoint.rb +42 -51
- data/lib/active_record/support/core_ext/object_and_class.rb +24 -0
- data/lib/active_record/support/dependencies.rb +20 -15
- data/lib/active_record/timestamp.rb +12 -7
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/vendor/mysql411.rb +1 -1
- data/rakefile +1 -1
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations_test.rb +38 -0
- data/test/base_test.rb +57 -3
- data/test/column_alias_test.rb +12 -0
- data/test/finder_test.rb +32 -1
- data/test/fixtures/company.rb +2 -2
- data/test/fixtures/fixture_database.sqlite +0 -0
- metadata +5 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
*1.6.0* (January 25th, 2005)
|
2
|
+
|
3
|
+
* Added that has_many association build and create methods can take arrays of record data like Base#create and Base#build to build/create multiple records at once.
|
4
|
+
|
5
|
+
* Added that Base#delete and Base#destroy both can take an array of ids to delete/destroy #336
|
6
|
+
|
7
|
+
* Added the option of supplying an array of attributes to Base#create, so that multiple records can be created at once.
|
8
|
+
|
9
|
+
* Added the option of supplying an array of ids and attributes to Base#update, so that multiple records can be updated at once (inspired by #526/Duane Johnson). Example
|
10
|
+
|
11
|
+
people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
|
12
|
+
Person.update(people.keys, people.values)
|
13
|
+
|
14
|
+
* Added ActiveRecord::Base.timestamps_gmt that can be set to true to make the automated timestamping use GMT instead of local time #520 [Scott Baron]
|
15
|
+
|
16
|
+
* Added that update_all calls sanitize_sql on its updates argument, so stuff like MyRecord.update_all(['time = ?', Time.now]) works #519 [notahat]
|
17
|
+
|
18
|
+
* Fixed that the dynamic finders didn't treat nil as a "IS NULL" but rather "= NULL" case #515 [Demetrius]
|
19
|
+
|
20
|
+
* Added bind-named arrays for interpolating a group of ids or strings in conditions #528 [bitsweat]
|
21
|
+
|
22
|
+
* Added that has_and_belongs_to_many associations with additional attributes also can be created between unsaved objects and only committed to the database when Base#save is called on the associator #524 [Eric Anderson]
|
23
|
+
|
24
|
+
* Fixed that records fetched with piggy-back attributes or through rich has_and_belongs_to_many associations couldn't be saved due to the extra attributes not part of the table #522 [Eric Anderson]
|
25
|
+
|
26
|
+
* Added mass-assignment protection for the inheritance column -- regardless of a custom column is used or not
|
27
|
+
|
28
|
+
* Fixed that association proxies would fail === tests like PremiumSubscription === @account.subscription
|
29
|
+
|
30
|
+
* Fixed that column aliases didn't work as expected with the new MySql411 driver #507 [Demetrius]
|
31
|
+
|
32
|
+
* Fixed that find_all would produce invalid sql when called sequentialy #490 [Scott Baron]
|
33
|
+
|
34
|
+
|
1
35
|
*1.5.1* (January 18th, 2005)
|
2
36
|
|
3
37
|
* Fixed that the belongs_to and has_one proxy would fail a test like 'if project.manager' -- this unfortunately also means that you can't call methods like project.manager.build unless there already is a manager on the project #492 [Tim Bates]
|
data/install.rb
CHANGED
@@ -18,7 +18,7 @@ unless $sitedir
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
makedirs = %w{ active_record/associations active_record/connection_adapters active_record/support active_record/vendor active_record/acts }
|
21
|
+
makedirs = %w{ active_record/associations active_record/connection_adapters active_record/support active_record/vendor active_record/acts active_record/support/core_ext active_record/support/core_ext/hash active_record/support/core_ext/numeric active_record/support/core_ext/string }
|
22
22
|
makedirs.each {|f| File::makedirs(File.join($sitedir, *f.split(/\//)))}
|
23
23
|
|
24
24
|
# deprecated files that should be removed
|
@@ -50,8 +50,18 @@ files = %w-
|
|
50
50
|
active_record/support/class_attribute_accessors.rb
|
51
51
|
active_record/support/class_inheritable_attributes.rb
|
52
52
|
active_record/support/clean_logger.rb
|
53
|
+
active_record/support/core_ext/hash/keys.rb
|
54
|
+
active_record/support/core_ext/hash.rb
|
55
|
+
active_record/support/core_ext/object_and_class.rb
|
56
|
+
active_record/support/core_ext/numeric/bytes.rb
|
57
|
+
active_record/support/core_ext/numeric/time.rb
|
58
|
+
active_record/support/core_ext/numeric.rb
|
59
|
+
active_record/support/core_ext/string/inflections.rb
|
60
|
+
active_record/support/core_ext/string.rb
|
61
|
+
active_record/support/core_ext.rb
|
53
62
|
active_record/support/inflector.rb
|
54
63
|
active_record/support/misc.rb
|
64
|
+
active_record/support/module_attribute_accessors.rb
|
55
65
|
active_record/timestamp.rb
|
56
66
|
active_record/transactions.rb
|
57
67
|
active_record/validations.rb
|
@@ -35,7 +35,6 @@ module ActiveRecord
|
|
35
35
|
# The project class now has the following methods (and more) to ease the traversal and manipulation of its relationships:
|
36
36
|
# * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
|
37
37
|
# * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
|
38
|
-
# <tt>Project#project_manager.build, Project#project_manager.create</tt>
|
39
38
|
# * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
|
40
39
|
# <tt>Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.find_all(conditions),</tt>
|
41
40
|
# <tt>Project#milestones.build, Project#milestones.create</tt>
|
@@ -249,9 +248,11 @@ module ActiveRecord
|
|
249
248
|
# and saves the associate object.
|
250
249
|
# * <tt>association.nil?</tt> - returns true if there is no associated object.
|
251
250
|
# * <tt>association.build(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
|
252
|
-
# with +attributes+ and linked to this object through a foreign key but has not yet been saved.
|
251
|
+
# with +attributes+ and linked to this object through a foreign key but has not yet been saved. Note: This ONLY works if
|
252
|
+
# an association already exists. It will NOT work if the association is nil.
|
253
253
|
# * <tt>association.create(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
|
254
254
|
# with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation).
|
255
|
+
# Note: This ONLY works if an association already exists. It will NOT work if the association is nil.
|
255
256
|
#
|
256
257
|
# Example: An Account class declares <tt>has_one :beneficiary</tt>, which will add:
|
257
258
|
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.find_first "account_id = #{id}"</tt>)
|
@@ -53,9 +53,13 @@ module ActiveRecord
|
|
53
53
|
|
54
54
|
def create(attributes = {})
|
55
55
|
# Can't use Base.create since the foreign key may be a protected attribute.
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
if attributes.is_a?(Array)
|
57
|
+
attributes.collect { |attr| create(attr) }
|
58
|
+
else
|
59
|
+
record = build(attributes)
|
60
|
+
record.save unless @owner.new_record?
|
61
|
+
record
|
62
|
+
end
|
59
63
|
end
|
60
64
|
|
61
65
|
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
|
@@ -81,8 +81,8 @@ module ActiveRecord
|
|
81
81
|
|
82
82
|
def push_with_attributes(record, join_attributes = {})
|
83
83
|
raise_on_type_mismatch(record)
|
84
|
-
|
85
|
-
|
84
|
+
join_attributes.each { |key, value| record[key.to_s] = value }
|
85
|
+
insert_record(record) unless @owner.new_record?
|
86
86
|
@target << record
|
87
87
|
self
|
88
88
|
end
|
@@ -105,22 +105,33 @@ module ActiveRecord
|
|
105
105
|
|
106
106
|
def insert_record(record)
|
107
107
|
return false unless record.save
|
108
|
+
|
108
109
|
if @options[:insert_sql]
|
109
110
|
@owner.connection.execute(interpolate_sql(@options[:insert_sql], record))
|
110
111
|
else
|
111
|
-
|
112
|
-
|
112
|
+
columns = @owner.connection.columns(@join_table, "#{@join_table} Columns")
|
113
|
+
|
114
|
+
attributes = columns.inject({}) do |attributes, column|
|
115
|
+
case column.name
|
116
|
+
when @association_class_primary_key_name
|
117
|
+
attributes[column.name] = @owner.quoted_id
|
118
|
+
when @association_foreign_key
|
119
|
+
attributes[column.name] = record.quoted_id
|
120
|
+
else
|
121
|
+
value = record[column.name]
|
122
|
+
attributes[column.name] = value unless value.nil?
|
123
|
+
end
|
124
|
+
attributes
|
125
|
+
end
|
126
|
+
|
127
|
+
sql =
|
128
|
+
"INSERT INTO #{@join_table} (#{@owner.send(:quoted_column_names, attributes).join(', ')}) " +
|
129
|
+
"VALUES (#{attributes.values.collect { |value| @owner.send(:quote, value) }.join(', ')})"
|
130
|
+
|
113
131
|
@owner.connection.execute(sql)
|
114
132
|
end
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
def insert_record_with_join_attributes(record, join_attributes)
|
119
|
-
attributes = { @association_class_primary_key_name => @owner.id, @association_foreign_key => record.id }.update(join_attributes)
|
120
|
-
sql =
|
121
|
-
"INSERT INTO #{@join_table} (#{@owner.send(:quoted_column_names, attributes).join(', ')}) " +
|
122
|
-
"VALUES (#{attributes.values.collect { |value| @owner.send(:quote, value) }.join(', ')})"
|
123
|
-
@owner.connection.execute(sql)
|
133
|
+
|
134
|
+
return true
|
124
135
|
end
|
125
136
|
|
126
137
|
def delete_records(records)
|
@@ -9,18 +9,22 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def build(attributes = {})
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
if attributes.is_a?(Array)
|
13
|
+
attributes.collect { |attr| create(attr) }
|
14
|
+
else
|
15
|
+
load_target
|
16
|
+
record = @association_class.new(attributes)
|
17
|
+
record[@association_class_primary_key_name] = @owner.id unless @owner.new_record?
|
18
|
+
@target << record
|
19
|
+
record
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
def find_all(runtime_conditions = nil, orderings = nil, limit = nil, joins = nil)
|
20
24
|
if @options[:finder_sql]
|
21
25
|
records = @association_class.find_by_sql(@finder_sql)
|
22
26
|
else
|
23
|
-
sql = @finder_sql
|
27
|
+
sql = @finder_sql.dup
|
24
28
|
sql << " AND #{sanitize_sql(runtime_conditions)}" if runtime_conditions
|
25
29
|
orderings ||= @options[:order]
|
26
30
|
records = @association_class.find_all(sql, orderings, limit, joins)
|
data/lib/active_record/base.rb
CHANGED
@@ -124,11 +124,11 @@ module ActiveRecord #:nodoc:
|
|
124
124
|
# user = User.create("preferences" => { "background" => "black", "display" => large })
|
125
125
|
# User.find(user.id).preferences # => { "background" => "black", "display" => large }
|
126
126
|
#
|
127
|
-
# You can also specify an
|
127
|
+
# You can also specify an class option as the second parameter that'll raise an exception if a serialized object is retrieved as a
|
128
128
|
# descendent of a class not in the hierarchy. Example:
|
129
129
|
#
|
130
130
|
# class User < ActiveRecord::Base
|
131
|
-
# serialize :preferences,
|
131
|
+
# serialize :preferences, Hash
|
132
132
|
# end
|
133
133
|
#
|
134
134
|
# user = User.create("preferences" => %w( one two three ))
|
@@ -171,8 +171,7 @@ module ActiveRecord #:nodoc:
|
|
171
171
|
# * +AdapterNotSpecified+ -- the <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified an unexisting adapter
|
172
172
|
# (or a bad spelling of an existing one).
|
173
173
|
# * +AssociationTypeMismatch+ -- the object assigned to the association wasn't of the type specified in the association definition.
|
174
|
-
# * +SerializationTypeMismatch+ -- the object serialized wasn't of the class specified
|
175
|
-
# the serialize definition.
|
174
|
+
# * +SerializationTypeMismatch+ -- the object serialized wasn't of the class specified as the second parameter.
|
176
175
|
# * +ConnectionNotEstablished+ -- no connection has been established. Use <tt>establish_connection</tt> before querying.
|
177
176
|
# * +RecordNotFound+ -- no record responded to the find* method.
|
178
177
|
# Either the row with the given ID doesn't exist or the row didn't meet the additional restrictions.
|
@@ -289,7 +288,7 @@ module ActiveRecord #:nodoc:
|
|
289
288
|
if result.size == ids.size
|
290
289
|
result
|
291
290
|
else
|
292
|
-
raise RecordNotFound, "Couldn't find #{name} with
|
291
|
+
raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids_list})#{conditions}"
|
293
292
|
end
|
294
293
|
end
|
295
294
|
end
|
@@ -340,39 +339,49 @@ module ActiveRecord #:nodoc:
|
|
340
339
|
# Creates an object, instantly saves it as a record (if the validation permits it), and returns it. If the save
|
341
340
|
# fail under validations, the unsaved object is still returned.
|
342
341
|
def create(attributes = nil)
|
343
|
-
|
344
|
-
|
345
|
-
|
342
|
+
if attributes.is_a?(Array)
|
343
|
+
attributes.collect { |attr| create(attr) }
|
344
|
+
else
|
345
|
+
object = new(attributes)
|
346
|
+
object.save
|
347
|
+
object
|
348
|
+
end
|
346
349
|
end
|
347
350
|
|
348
351
|
# Finds the record from the passed +id+, instantly saves it with the passed +attributes+ (if the validation permits it),
|
349
352
|
# and returns it. If the save fail under validations, the unsaved object is still returned.
|
350
353
|
def update(id, attributes)
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
354
|
+
if id.is_a?(Array)
|
355
|
+
idx = -1
|
356
|
+
id.collect { |id| idx += 1; update(id, attributes[idx]) }
|
357
|
+
else
|
358
|
+
object = find(id)
|
359
|
+
object.update_attributes(attributes)
|
360
|
+
object
|
361
|
+
end
|
355
362
|
end
|
356
363
|
|
357
|
-
# Deletes the record with the given +id+ without instantiating an object first.
|
364
|
+
# Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them
|
365
|
+
# are deleted.
|
358
366
|
def delete(id)
|
359
|
-
delete_all([ "#{primary_key}
|
367
|
+
delete_all([ "#{primary_key} IN (?)", id ])
|
360
368
|
end
|
361
369
|
|
362
370
|
# Destroys the record with the given +id+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
|
371
|
+
# If an array of ids is provided, all of them are destroyed.
|
363
372
|
def destroy(id)
|
364
|
-
find(id).destroy
|
373
|
+
id.is_a?(Array) ? id.each { |id| destroy(id) } : find(id).destroy
|
365
374
|
end
|
366
375
|
|
367
376
|
# Updates all records with the SET-part of an SQL update statement in +updates+ and returns an integer with the number of rows updates.
|
368
377
|
# A subset of the records can be selected by specifying +conditions+. Example:
|
369
378
|
# Billing.update_all "category = 'authorized', approved = 1", "author = 'David'"
|
370
379
|
def update_all(updates, conditions = nil)
|
371
|
-
sql = "UPDATE #{table_name} SET #{updates} "
|
380
|
+
sql = "UPDATE #{table_name} SET #{sanitize_sql(updates)} "
|
372
381
|
add_conditions!(sql, conditions)
|
373
382
|
return connection.update(sql, "#{name} Update")
|
374
383
|
end
|
375
|
-
|
384
|
+
|
376
385
|
# Destroys the objects for all the records that matches the +condition+ by instantiating each object and calling
|
377
386
|
# the destroy method. Example:
|
378
387
|
# Person.destroy_all "last_login < '2004-04-04'"
|
@@ -598,6 +607,11 @@ module ActiveRecord #:nodoc:
|
|
598
607
|
return result
|
599
608
|
end
|
600
609
|
|
610
|
+
# Overwrite the default class equality method to provide support for association proxies.
|
611
|
+
def ===(object)
|
612
|
+
object.is_a?(self)
|
613
|
+
end
|
614
|
+
|
601
615
|
private
|
602
616
|
# Finder methods must instantiate through this method to work with the single-table inheritance model
|
603
617
|
# that makes it possible to create objects of different types from the same table.
|
@@ -663,7 +677,9 @@ module ActiveRecord #:nodoc:
|
|
663
677
|
if method_name =~ /find_(all_by|by)_([_a-z]+)/
|
664
678
|
finder, attributes = ($1 == "all_by" ? :find_all : :find_first), $2.split("_and_")
|
665
679
|
attributes.each { |attr_name| super unless column_methods_hash[attr_name.intern] }
|
666
|
-
|
680
|
+
|
681
|
+
attr_index = -1
|
682
|
+
conditions = attributes.collect { |attr_name| attr_index += 1; "#{attr_name} #{arguments[attr_index] ? "=" : "IS"} ? " }.join(" AND ")
|
667
683
|
send(finder, [conditions, *arguments[0...attributes.length]], *arguments[attributes.length..-1])
|
668
684
|
else
|
669
685
|
super
|
@@ -716,7 +732,7 @@ module ActiveRecord #:nodoc:
|
|
716
732
|
def replace_bind_variables(statement, values)
|
717
733
|
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
|
718
734
|
bound = values.dup
|
719
|
-
statement.gsub('?') {
|
735
|
+
statement.gsub('?') { quote_bound_value(bound.shift) }
|
720
736
|
end
|
721
737
|
|
722
738
|
def replace_named_bind_variables(statement, bind_vars)
|
@@ -724,13 +740,22 @@ module ActiveRecord #:nodoc:
|
|
724
740
|
statement.gsub(/:(\w+)/) do
|
725
741
|
match = $1.to_sym
|
726
742
|
if bind_vars.has_key?(match)
|
727
|
-
|
743
|
+
quote_bound_value(bind_vars[match])
|
728
744
|
else
|
729
745
|
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
730
746
|
end
|
731
747
|
end
|
732
748
|
end
|
733
749
|
|
750
|
+
def quote_bound_value(value)
|
751
|
+
case value
|
752
|
+
when Array
|
753
|
+
value.map { |v| connection.quote(v) }.join(',')
|
754
|
+
else
|
755
|
+
connection.quote(value)
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
734
759
|
def raise_if_bind_arity_mismatch(statement, expected, provided)
|
735
760
|
unless expected == provided
|
736
761
|
raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
|
@@ -1093,22 +1118,30 @@ module ActiveRecord #:nodoc:
|
|
1093
1118
|
|
1094
1119
|
def remove_attributes_protected_from_mass_assignment(attributes)
|
1095
1120
|
if self.class.accessible_attributes.nil? && self.class.protected_attributes.nil?
|
1096
|
-
attributes.reject { |key, value| key
|
1121
|
+
attributes.reject { |key, value| attributes_protected_by_default.include?(key) }
|
1097
1122
|
elsif self.class.protected_attributes.nil?
|
1098
|
-
attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.intern) || key
|
1123
|
+
attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.intern) || attributes_protected_by_default.include?(key) }
|
1099
1124
|
elsif self.class.accessible_attributes.nil?
|
1100
|
-
attributes.reject { |key, value| self.class.protected_attributes.include?(key.intern) || key
|
1125
|
+
attributes.reject { |key, value| self.class.protected_attributes.include?(key.intern) || attributes_protected_by_default.include?(key) }
|
1101
1126
|
end
|
1102
1127
|
end
|
1103
1128
|
|
1129
|
+
# The primary key and inheritance column can never be set by mass-assignment for security reasons.
|
1130
|
+
def attributes_protected_by_default
|
1131
|
+
[ self.class.primary_key, self.class.inheritance_column ]
|
1132
|
+
end
|
1133
|
+
|
1104
1134
|
# Returns copy of the attributes hash where all the values have been safely quoted for use in
|
1105
1135
|
# an SQL statement.
|
1106
1136
|
def attributes_with_quotes(include_primary_key = true)
|
1107
1137
|
columns_hash = self.class.columns_hash
|
1108
|
-
|
1138
|
+
|
1139
|
+
attrs_quoted = @attributes.inject({}) do |attrs_quoted, pair|
|
1109
1140
|
attrs_quoted[pair.first] = quote(pair.last, columns_hash[pair.first]) unless !include_primary_key && pair.first == self.class.primary_key
|
1110
1141
|
attrs_quoted
|
1111
1142
|
end
|
1143
|
+
|
1144
|
+
attrs_quoted.delete_if { |key, value| !self.class.columns_hash.keys.include?(key) }
|
1112
1145
|
end
|
1113
1146
|
|
1114
1147
|
# Quote strings appropriately for SQL statements.
|
@@ -1167,7 +1200,7 @@ module ActiveRecord #:nodoc:
|
|
1167
1200
|
|
1168
1201
|
unless value.empty?
|
1169
1202
|
attributes[attribute_name] <<
|
1170
|
-
[find_parameter_position(multiparameter_name), type_cast_attribute_value(multiparameter_name, value)]
|
1203
|
+
[ find_parameter_position(multiparameter_name), type_cast_attribute_value(multiparameter_name, value) ]
|
1171
1204
|
end
|
1172
1205
|
end
|
1173
1206
|
|
@@ -1192,10 +1225,10 @@ module ActiveRecord #:nodoc:
|
|
1192
1225
|
end
|
1193
1226
|
|
1194
1227
|
def quote_columns(column_quoter, hash)
|
1195
|
-
hash.inject({})
|
1228
|
+
hash.inject({}) do |list, pair|
|
1196
1229
|
list[column_quoter.quote_column_name(pair.first)] = pair.last
|
1197
1230
|
list
|
1198
|
-
|
1231
|
+
end
|
1199
1232
|
end
|
1200
1233
|
|
1201
1234
|
def quoted_comma_pair_list(column_quoter, hash)
|
@@ -1203,7 +1236,7 @@ module ActiveRecord #:nodoc:
|
|
1203
1236
|
end
|
1204
1237
|
|
1205
1238
|
def object_from_yaml(string)
|
1206
|
-
return string unless String
|
1239
|
+
return string unless string.is_a?(String)
|
1207
1240
|
if has_yaml_encoding_header?(string)
|
1208
1241
|
begin
|
1209
1242
|
YAML::load(string)
|
@@ -1220,4 +1253,4 @@ module ActiveRecord #:nodoc:
|
|
1220
1253
|
string[0..3] == "--- "
|
1221
1254
|
end
|
1222
1255
|
end
|
1223
|
-
end
|
1256
|
+
end
|
@@ -217,21 +217,21 @@ module ActiveRecord
|
|
217
217
|
|
218
218
|
private
|
219
219
|
def string_to_date(string)
|
220
|
-
return string if Date
|
220
|
+
return string if string.is_a?(Date)
|
221
221
|
date_array = ParseDate.parsedate(string)
|
222
222
|
# treat 0000-00-00 as nil
|
223
223
|
Date.new(date_array[0], date_array[1], date_array[2]) rescue nil
|
224
224
|
end
|
225
225
|
|
226
226
|
def string_to_time(string)
|
227
|
-
return string if Time
|
227
|
+
return string if string.is_a?(Time)
|
228
228
|
time_array = ParseDate.parsedate(string).compact
|
229
229
|
# treat 0000-00-00 00:00:00 as nil
|
230
230
|
Time.send(Base.default_timezone, *time_array) rescue nil
|
231
231
|
end
|
232
232
|
|
233
233
|
def string_to_dummy_time(string)
|
234
|
-
return string if Time
|
234
|
+
return string if string.is_a?(Time)
|
235
235
|
time_array = ParseDate.parsedate(string)
|
236
236
|
# pad the resulting array with dummy date information
|
237
237
|
time_array[0] = 2000; time_array[1] = 1; time_array[2] = 1;
|
@@ -166,7 +166,7 @@ class Fixtures < Hash
|
|
166
166
|
fixtures.each { |fixture| fixture.insert_fixtures }
|
167
167
|
end
|
168
168
|
|
169
|
-
reset_sequences(connection, table_names) if ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
169
|
+
reset_sequences(connection, table_names) if connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
170
170
|
|
171
171
|
return fixtures.size > 1 ? fixtures : fixtures.first
|
172
172
|
ensure
|
@@ -1,85 +1,83 @@
|
|
1
|
-
begin
|
2
|
-
require 'simplecc'
|
3
|
-
rescue LoadError
|
4
|
-
class Continuation
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
1
|
+
begin
|
2
|
+
require 'simplecc'
|
3
|
+
rescue LoadError
|
4
|
+
class Continuation; end # :nodoc: # for RDoc
|
5
|
+
def Continuation.create(*args, &block) # :nodoc:
|
6
|
+
cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
|
7
|
+
result ||= args
|
8
|
+
return *[cc, *result]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Binding; end # for RDoc
|
13
|
+
# This method returns the binding of the method that called your
|
14
|
+
# method. It will raise an Exception when you're not inside a method.
|
15
|
+
#
|
16
|
+
# It's used like this:
|
17
|
+
# def inc_counter(amount = 1)
|
18
|
+
# Binding.of_caller do |binding|
|
19
|
+
# # Create a lambda that will increase the variable 'counter'
|
20
|
+
# # in the caller of this method when called.
|
21
|
+
# inc = eval("lambda { |arg| counter += arg }", binding)
|
22
|
+
# # We can refer to amount from inside this block safely.
|
23
|
+
# inc.call(amount)
|
24
|
+
# end
|
25
|
+
# # No other statements can go here. Put them inside the block.
|
26
|
+
# end
|
27
|
+
# counter = 0
|
28
|
+
# 2.times { inc_counter }
|
29
|
+
# counter # => 2
|
30
|
+
#
|
31
|
+
# Binding.of_caller must be the last statement in the method.
|
32
|
+
# This means that you will have to put everything you want to
|
33
|
+
# do after the call to Binding.of_caller into the block of it.
|
34
|
+
# This should be no problem however, because Ruby has closures.
|
35
|
+
# If you don't do this an Exception will be raised. Because of
|
36
|
+
# the way that Binding.of_caller is implemented it has to be
|
37
|
+
# done this way.
|
38
|
+
def Binding.of_caller(&block)
|
39
|
+
old_critical = Thread.critical
|
40
|
+
Thread.critical = true
|
41
|
+
count = 0
|
42
|
+
cc, result, error, extra_data = Continuation.create(nil, nil)
|
43
|
+
error.call if error
|
44
|
+
|
45
|
+
tracer = lambda do |*args|
|
46
|
+
type, context, extra_data = args[0], args[4], args
|
47
|
+
if type == "return"
|
48
|
+
count += 1
|
49
|
+
# First this method and then calling one will return --
|
50
|
+
# the trace event of the second event gets the context
|
51
|
+
# of the method which called the method that called this
|
52
|
+
# method.
|
53
|
+
if count == 2
|
54
|
+
# It would be nice if we could restore the trace_func
|
55
|
+
# that was set before we swapped in our own one, but
|
56
|
+
# this is impossible without overloading set_trace_func
|
57
|
+
# in current Ruby.
|
58
|
+
set_trace_func(nil)
|
59
|
+
cc.call(eval("binding", context), nil, extra_data)
|
60
|
+
end
|
61
|
+
elsif type == "line" then
|
62
|
+
nil
|
63
|
+
elsif type == "c-return" and extra_data[3] == :set_trace_func then
|
64
|
+
nil
|
65
|
+
else
|
66
|
+
set_trace_func(nil)
|
67
|
+
error_msg = "Binding.of_caller used in non-method context or " +
|
68
|
+
"trailing statements of method using it aren't in the block."
|
69
|
+
cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
unless result
|
74
|
+
set_trace_func(tracer)
|
75
|
+
return nil
|
76
|
+
else
|
77
|
+
Thread.critical = old_critical
|
78
|
+
case block.arity
|
79
|
+
when 1 then yield(result)
|
80
|
+
else yield(result, extra_data)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|