activerecord_authorails 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3043 -0
- data/README +360 -0
- data/RUNNING_UNIT_TESTS +64 -0
- data/Rakefile +226 -0
- data/examples/associations.png +0 -0
- data/examples/associations.rb +87 -0
- data/examples/shared_setup.rb +15 -0
- data/examples/validation.rb +85 -0
- data/install.rb +30 -0
- data/lib/active_record.rb +85 -0
- data/lib/active_record/acts/list.rb +244 -0
- data/lib/active_record/acts/nested_set.rb +211 -0
- data/lib/active_record/acts/tree.rb +89 -0
- data/lib/active_record/aggregations.rb +191 -0
- data/lib/active_record/associations.rb +1637 -0
- data/lib/active_record/associations/association_collection.rb +190 -0
- data/lib/active_record/associations/association_proxy.rb +158 -0
- data/lib/active_record/associations/belongs_to_association.rb +56 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +169 -0
- data/lib/active_record/associations/has_many_association.rb +210 -0
- data/lib/active_record/associations/has_many_through_association.rb +247 -0
- data/lib/active_record/associations/has_one_association.rb +80 -0
- data/lib/active_record/attribute_methods.rb +75 -0
- data/lib/active_record/base.rb +2164 -0
- data/lib/active_record/calculations.rb +270 -0
- data/lib/active_record/callbacks.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +279 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +58 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +343 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +161 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +228 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +728 -0
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +414 -0
- data/lib/active_record/connection_adapters/openbase_adapter.rb +350 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +689 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +584 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +407 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +591 -0
- data/lib/active_record/connection_adapters/sybase_adapter.rb +662 -0
- data/lib/active_record/deprecated_associations.rb +104 -0
- data/lib/active_record/deprecated_finders.rb +44 -0
- data/lib/active_record/fixtures.rb +628 -0
- data/lib/active_record/locking/optimistic.rb +106 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +394 -0
- data/lib/active_record/observer.rb +178 -0
- data/lib/active_record/query_cache.rb +64 -0
- data/lib/active_record/reflection.rb +222 -0
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +149 -0
- data/lib/active_record/timestamp.rb +51 -0
- data/lib/active_record/transactions.rb +136 -0
- data/lib/active_record/validations.rb +843 -0
- data/lib/active_record/vendor/db2.rb +362 -0
- data/lib/active_record/vendor/mysql.rb +1214 -0
- data/lib/active_record/vendor/simple.rb +693 -0
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
- data/lib/active_record/wrappings.rb +58 -0
- data/lib/active_record/xml_serialization.rb +308 -0
- data/test/aaa_create_tables_test.rb +59 -0
- data/test/abstract_unit.rb +77 -0
- data/test/active_schema_test_mysql.rb +31 -0
- data/test/adapter_test.rb +87 -0
- data/test/adapter_test_sqlserver.rb +81 -0
- data/test/aggregations_test.rb +95 -0
- data/test/all.sh +8 -0
- data/test/ar_schema_test.rb +33 -0
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations/callbacks_test.rb +126 -0
- data/test/associations/cascaded_eager_loading_test.rb +138 -0
- data/test/associations/eager_test.rb +393 -0
- data/test/associations/extension_test.rb +42 -0
- data/test/associations/join_model_test.rb +497 -0
- data/test/associations_test.rb +1809 -0
- data/test/attribute_methods_test.rb +49 -0
- data/test/base_test.rb +1586 -0
- data/test/binary_test.rb +37 -0
- data/test/calculations_test.rb +219 -0
- data/test/callbacks_test.rb +377 -0
- data/test/class_inheritable_attributes_test.rb +32 -0
- data/test/column_alias_test.rb +17 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +24 -0
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +23 -0
- data/test/connections/native_sqlite/connection.rb +34 -0
- data/test/connections/native_sqlite3/connection.rb +34 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sqlserver/connection.rb +23 -0
- data/test/connections/native_sqlserver_odbc/connection.rb +25 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/copy_table_sqlite.rb +64 -0
- data/test/datatype_test_postgresql.rb +52 -0
- data/test/default_test_firebird.rb +16 -0
- data/test/defaults_test.rb +60 -0
- data/test/deprecated_associations_test.rb +396 -0
- data/test/deprecated_finder_test.rb +151 -0
- data/test/empty_date_time_test.rb +25 -0
- data/test/finder_test.rb +504 -0
- data/test/fixtures/accounts.yml +28 -0
- data/test/fixtures/author.rb +99 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +7 -0
- data/test/fixtures/auto_id.rb +4 -0
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
- data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
- data/test/fixtures/bad_fixtures/blank_line +3 -0
- data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
- data/test/fixtures/bad_fixtures/missing_value +1 -0
- data/test/fixtures/binary.rb +2 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/category.rb +20 -0
- data/test/fixtures/column_name.rb +3 -0
- data/test/fixtures/comment.rb +23 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +55 -0
- data/test/fixtures/company.rb +107 -0
- data/test/fixtures/company_in_module.rb +59 -0
- data/test/fixtures/computer.rb +3 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/course.rb +3 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customer.rb +55 -0
- data/test/fixtures/customers.yml +17 -0
- data/test/fixtures/db_definitions/db2.drop.sql +32 -0
- data/test/fixtures/db_definitions/db2.sql +231 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +63 -0
- data/test/fixtures/db_definitions/firebird.sql +304 -0
- data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
- data/test/fixtures/db_definitions/firebird2.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +32 -0
- data/test/fixtures/db_definitions/frontbase.sql +268 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +32 -0
- data/test/fixtures/db_definitions/mysql.sql +234 -0
- data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql2.sql +5 -0
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +302 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +65 -0
- data/test/fixtures/db_definitions/oracle.sql +325 -0
- data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +37 -0
- data/test/fixtures/db_definitions/postgresql.sql +263 -0
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +5 -0
- data/test/fixtures/db_definitions/schema.rb +60 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +32 -0
- data/test/fixtures/db_definitions/sqlite.sql +215 -0
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +5 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +34 -0
- data/test/fixtures/db_definitions/sqlserver.sql +243 -0
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +34 -0
- data/test/fixtures/db_definitions/sybase.sql +218 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/default.rb +2 -0
- data/test/fixtures/developer.rb +52 -0
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/developers_projects/david_action_controller +3 -0
- data/test/fixtures/developers_projects/david_active_record +3 -0
- data/test/fixtures/developers_projects/jamis_active_record +2 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrant.rb +3 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
- data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/mixed_case_monkey.rb +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixin.rb +63 -0
- data/test/fixtures/mixins.yml +127 -0
- data/test/fixtures/movie.rb +5 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/people.yml +3 -0
- data/test/fixtures/person.rb +4 -0
- data/test/fixtures/post.rb +58 -0
- data/test/fixtures/posts.yml +48 -0
- data/test/fixtures/project.rb +27 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +37 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +6 -0
- data/test/fixtures/subscribers/first +2 -0
- data/test/fixtures/subscribers/second +2 -0
- data/test/fixtures/tag.rb +7 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/task.rb +3 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topic.rb +25 -0
- data/test/fixtures/topics.yml +22 -0
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +401 -0
- data/test/inheritance_test.rb +205 -0
- data/test/lifecycle_test.rb +137 -0
- data/test/locking_test.rb +190 -0
- data/test/method_scoping_test.rb +416 -0
- data/test/migration_test.rb +768 -0
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_nested_set_test.rb +196 -0
- data/test/mixin_test.rb +550 -0
- data/test/modules_test.rb +34 -0
- data/test/multiple_db_test.rb +60 -0
- data/test/pk_test.rb +104 -0
- data/test/readonly_test.rb +107 -0
- data/test/reflection_test.rb +159 -0
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +96 -0
- data/test/schema_test_postgresql.rb +64 -0
- data/test/synonym_test_oracle.rb +17 -0
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +48 -0
- data/test/transactions_test.rb +230 -0
- data/test/unconnected_test.rb +32 -0
- data/test/validations_test.rb +1097 -0
- data/test/xml_serialization_test.rb +125 -0
- metadata +365 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations # :nodoc:
|
3
|
+
module ClassMethods
|
4
|
+
def deprecated_collection_count_method(collection_name)# :nodoc:
|
5
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
6
|
+
def #{collection_name}_count(force_reload = false)
|
7
|
+
unless has_attribute?(:#{collection_name}_count)
|
8
|
+
ActiveSupport::Deprecation.warn :#{collection_name}_count
|
9
|
+
end
|
10
|
+
#{collection_name}.reload if force_reload
|
11
|
+
#{collection_name}.size
|
12
|
+
end
|
13
|
+
end_eval
|
14
|
+
end
|
15
|
+
|
16
|
+
def deprecated_add_association_relation(association_name)# :nodoc:
|
17
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
18
|
+
def add_#{association_name}(*items)
|
19
|
+
#{association_name}.concat(items)
|
20
|
+
end
|
21
|
+
deprecate :add_#{association_name} => "use #{association_name}.concat instead"
|
22
|
+
end_eval
|
23
|
+
end
|
24
|
+
|
25
|
+
def deprecated_remove_association_relation(association_name)# :nodoc:
|
26
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
27
|
+
def remove_#{association_name}(*items)
|
28
|
+
#{association_name}.delete(items)
|
29
|
+
end
|
30
|
+
deprecate :remove_#{association_name} => "use #{association_name}.delete instead"
|
31
|
+
end_eval
|
32
|
+
end
|
33
|
+
|
34
|
+
def deprecated_has_collection_method(collection_name)# :nodoc:
|
35
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
36
|
+
def has_#{collection_name}?(force_reload = false)
|
37
|
+
!#{collection_name}(force_reload).empty?
|
38
|
+
end
|
39
|
+
deprecate :has_#{collection_name}? => "use !#{collection_name}.empty? instead"
|
40
|
+
end_eval
|
41
|
+
end
|
42
|
+
|
43
|
+
def deprecated_find_in_collection_method(collection_name)# :nodoc:
|
44
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
45
|
+
def find_in_#{collection_name}(association_id)
|
46
|
+
#{collection_name}.find(association_id)
|
47
|
+
end
|
48
|
+
deprecate :find_in_#{collection_name} => "use #{collection_name}.find instead"
|
49
|
+
end_eval
|
50
|
+
end
|
51
|
+
|
52
|
+
def deprecated_find_all_in_collection_method(collection_name)# :nodoc:
|
53
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
54
|
+
def find_all_in_#{collection_name}(runtime_conditions = nil, orderings = nil, limit = nil, joins = nil)
|
55
|
+
ActiveSupport::Deprecation.silence do
|
56
|
+
#{collection_name}.find_all(runtime_conditions, orderings, limit, joins)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
deprecate :find_all_in_#{collection_name} => "use #{collection_name}.find(:all, ...) instead"
|
60
|
+
end_eval
|
61
|
+
end
|
62
|
+
|
63
|
+
def deprecated_collection_create_method(collection_name)# :nodoc:
|
64
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
65
|
+
def create_in_#{collection_name}(attributes = {})
|
66
|
+
#{collection_name}.create(attributes)
|
67
|
+
end
|
68
|
+
deprecate :create_in_#{collection_name} => "use #{collection_name}.create instead"
|
69
|
+
end_eval
|
70
|
+
end
|
71
|
+
|
72
|
+
def deprecated_collection_build_method(collection_name)# :nodoc:
|
73
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
74
|
+
def build_to_#{collection_name}(attributes = {})
|
75
|
+
#{collection_name}.build(attributes)
|
76
|
+
end
|
77
|
+
deprecate :build_to_#{collection_name} => "use #{collection_name}.build instead"
|
78
|
+
end_eval
|
79
|
+
end
|
80
|
+
|
81
|
+
def deprecated_association_comparison_method(association_name, association_class_name) # :nodoc:
|
82
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
83
|
+
def #{association_name}?(comparison_object, force_reload = false)
|
84
|
+
if comparison_object.kind_of?(#{association_class_name})
|
85
|
+
#{association_name}(force_reload) == comparison_object
|
86
|
+
else
|
87
|
+
raise "Comparison object is a #{association_class_name}, should have been \#{comparison_object.class.name}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
deprecate :#{association_name}? => :==
|
91
|
+
end_eval
|
92
|
+
end
|
93
|
+
|
94
|
+
def deprecated_has_association_method(association_name) # :nodoc:
|
95
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
96
|
+
def has_#{association_name}?(force_reload = false)
|
97
|
+
!#{association_name}(force_reload).nil?
|
98
|
+
end
|
99
|
+
deprecate :has_#{association_name}? => "use !#{association_name} insead"
|
100
|
+
end_eval
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
class << self
|
4
|
+
# This method is deprecated in favor of find with the :conditions option.
|
5
|
+
#
|
6
|
+
# Works like find, but the record matching +id+ must also meet the +conditions+.
|
7
|
+
# +RecordNotFound+ is raised if no record can be found matching the +id+ or meeting the condition.
|
8
|
+
# Example:
|
9
|
+
# Person.find_on_conditions 5, "first_name LIKE '%dav%' AND last_name = 'heinemeier'"
|
10
|
+
def find_on_conditions(ids, conditions) # :nodoc:
|
11
|
+
find(ids, :conditions => conditions)
|
12
|
+
end
|
13
|
+
deprecate :find_on_conditions => "use find(ids, :conditions => conditions)"
|
14
|
+
|
15
|
+
# This method is deprecated in favor of find(:first, options).
|
16
|
+
#
|
17
|
+
# Returns the object for the first record responding to the conditions in +conditions+,
|
18
|
+
# such as "group = 'master'". If more than one record is returned from the query, it's the first that'll
|
19
|
+
# be used to create the object. In such cases, it might be beneficial to also specify
|
20
|
+
# +orderings+, like "income DESC, name", to control exactly which record is to be used. Example:
|
21
|
+
# Employee.find_first "income > 50000", "income DESC, name"
|
22
|
+
def find_first(conditions = nil, orderings = nil, joins = nil) # :nodoc:
|
23
|
+
find(:first, :conditions => conditions, :order => orderings, :joins => joins)
|
24
|
+
end
|
25
|
+
deprecate :find_first => "use find(:first, ...)"
|
26
|
+
|
27
|
+
# This method is deprecated in favor of find(:all, options).
|
28
|
+
#
|
29
|
+
# Returns an array of all the objects that could be instantiated from the associated
|
30
|
+
# table in the database. The +conditions+ can be used to narrow the selection of objects (WHERE-part),
|
31
|
+
# such as by "color = 'red'", and arrangement of the selection can be done through +orderings+ (ORDER BY-part),
|
32
|
+
# such as by "last_name, first_name DESC". A maximum of returned objects and their offset can be specified in
|
33
|
+
# +limit+ with either just a single integer as the limit or as an array with the first element as the limit,
|
34
|
+
# the second as the offset. Examples:
|
35
|
+
# Project.find_all "category = 'accounts'", "last_accessed DESC", 15
|
36
|
+
# Project.find_all ["category = ?", category_name], "created ASC", [15, 20]
|
37
|
+
def find_all(conditions = nil, orderings = nil, limit = nil, joins = nil) # :nodoc:
|
38
|
+
limit, offset = limit.is_a?(Array) ? limit : [ limit, nil ]
|
39
|
+
find(:all, :conditions => conditions, :order => orderings, :joins => joins, :limit => limit, :offset => offset)
|
40
|
+
end
|
41
|
+
deprecate :find_all => "use find(:all, ...)"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,628 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'yaml'
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module YAML #:nodoc:
|
6
|
+
class Omap #:nodoc:
|
7
|
+
def keys; map { |k, v| k } end
|
8
|
+
def values; map { |k, v| v } end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
13
|
+
end
|
14
|
+
|
15
|
+
# Fixtures are a way of organizing data that you want to test against; in short, sample data. They come in 3 flavours:
|
16
|
+
#
|
17
|
+
# 1. YAML fixtures
|
18
|
+
# 2. CSV fixtures
|
19
|
+
# 3. Single-file fixtures
|
20
|
+
#
|
21
|
+
# = YAML fixtures
|
22
|
+
#
|
23
|
+
# This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
|
24
|
+
# in a non-verbose, humanly-readable format. It ships with Ruby 1.8.1+.
|
25
|
+
#
|
26
|
+
# Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed
|
27
|
+
# by <tt>Test::Unit::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
|
28
|
+
# put your files in <your-rails-app>/test/fixtures/). The fixture file ends with the .yml file extension (Rails example:
|
29
|
+
# "<your-rails-app>/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this:
|
30
|
+
#
|
31
|
+
# rubyonrails:
|
32
|
+
# id: 1
|
33
|
+
# name: Ruby on Rails
|
34
|
+
# url: http://www.rubyonrails.org
|
35
|
+
#
|
36
|
+
# google:
|
37
|
+
# id: 2
|
38
|
+
# name: Google
|
39
|
+
# url: http://www.google.com
|
40
|
+
#
|
41
|
+
# This YAML fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and is followed by an
|
42
|
+
# indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing
|
43
|
+
# pleasure.
|
44
|
+
#
|
45
|
+
# Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type. See http://yaml.org/type/omap.html
|
46
|
+
# for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table.
|
47
|
+
# This is commonly needed for tree structures. Example:
|
48
|
+
#
|
49
|
+
# --- !omap
|
50
|
+
# - parent:
|
51
|
+
# id: 1
|
52
|
+
# parent_id: NULL
|
53
|
+
# title: Parent
|
54
|
+
# - child:
|
55
|
+
# id: 2
|
56
|
+
# parent_id: 1
|
57
|
+
# title: Child
|
58
|
+
#
|
59
|
+
# = CSV fixtures
|
60
|
+
#
|
61
|
+
# Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored
|
62
|
+
# in a single file, but instead end with the .csv file extension (Rails example: "<your-rails-app>/test/fixtures/web_sites.csv")
|
63
|
+
#
|
64
|
+
# The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
|
65
|
+
# humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised
|
66
|
+
# of the actual data (1 per line). Here's an example:
|
67
|
+
#
|
68
|
+
# id, name, url
|
69
|
+
# 1, Ruby On Rails, http://www.rubyonrails.org
|
70
|
+
# 2, Google, http://www.google.com
|
71
|
+
#
|
72
|
+
# Should you have a piece of data with a comma character in it, you can place double quotes around that value. If you
|
73
|
+
# need to use a double quote character, you must escape it with another double quote.
|
74
|
+
#
|
75
|
+
# Another unique attribute of the CSV fixture is that it has *no* fixture name like the other two formats. Instead, the
|
76
|
+
# fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing
|
77
|
+
# number to the end. In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called
|
78
|
+
# "web_site_2".
|
79
|
+
#
|
80
|
+
# Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
|
81
|
+
# have existing data somewhere already.
|
82
|
+
#
|
83
|
+
# = Single-file fixtures
|
84
|
+
#
|
85
|
+
# This type of fixtures was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats.
|
86
|
+
# Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory
|
87
|
+
# appointed by <tt>Test::Unit::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
|
88
|
+
# put your files in <your-rails-app>/test/fixtures/<your-model-name>/ -- like <your-rails-app>/test/fixtures/web_sites/ for the WebSite
|
89
|
+
# model).
|
90
|
+
#
|
91
|
+
# Each text file placed in this directory represents a "record". Usually these types of fixtures are named without
|
92
|
+
# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the
|
93
|
+
# above example might look like:
|
94
|
+
#
|
95
|
+
# web_sites/google
|
96
|
+
# web_sites/yahoo.txt
|
97
|
+
# web_sites/ruby-on-rails
|
98
|
+
#
|
99
|
+
# The file format of a standard fixture is simple. Each line is a property (or column in db speak) and has the syntax
|
100
|
+
# of "name => value". Here's an example of the ruby-on-rails fixture above:
|
101
|
+
#
|
102
|
+
# id => 1
|
103
|
+
# name => Ruby on Rails
|
104
|
+
# url => http://www.rubyonrails.org
|
105
|
+
#
|
106
|
+
# = Using Fixtures
|
107
|
+
#
|
108
|
+
# Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
|
109
|
+
# fixtures, but first let's take a look at a sample unit test found:
|
110
|
+
#
|
111
|
+
# require 'web_site'
|
112
|
+
#
|
113
|
+
# class WebSiteTest < Test::Unit::TestCase
|
114
|
+
# def test_web_site_count
|
115
|
+
# assert_equal 2, WebSite.count
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# As it stands, unless we pre-load the web_site table in our database with two records, this test will fail. Here's the
|
120
|
+
# easiest way to add fixtures to the database:
|
121
|
+
#
|
122
|
+
# ...
|
123
|
+
# class WebSiteTest < Test::Unit::TestCase
|
124
|
+
# fixtures :web_sites # add more by separating the symbols with commas
|
125
|
+
# ...
|
126
|
+
#
|
127
|
+
# By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here tho), we trigger
|
128
|
+
# the testing environment to automatically load the appropriate fixtures into the database before each test.
|
129
|
+
# To ensure consistent data, the environment deletes the fixtures before running the load.
|
130
|
+
#
|
131
|
+
# In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable
|
132
|
+
# of the test case. It is named after the symbol... so, in our example, there would be a hash available called
|
133
|
+
# @web_sites. This is where the "fixture name" comes into play.
|
134
|
+
#
|
135
|
+
# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name.
|
136
|
+
# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics:
|
137
|
+
#
|
138
|
+
# # test if the object created from the fixture data has the same attributes as the data itself
|
139
|
+
# def test_find
|
140
|
+
# assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name
|
141
|
+
# end
|
142
|
+
#
|
143
|
+
# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return
|
144
|
+
# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded
|
145
|
+
# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual
|
146
|
+
# fixtures available as instance variables @web_site_1 and @web_site_2.
|
147
|
+
#
|
148
|
+
# If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.
|
149
|
+
#
|
150
|
+
# - to completely disable instantiated fixtures:
|
151
|
+
# self.use_instantiated_fixtures = false
|
152
|
+
#
|
153
|
+
# - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
|
154
|
+
# self.use_instantiated_fixtures = :no_instances
|
155
|
+
#
|
156
|
+
# Even if auto-instantiated fixtures are disabled, you can still access them
|
157
|
+
# by name via special dynamic methods. Each method has the same name as the
|
158
|
+
# model, and accepts the name of the fixture to instantiate:
|
159
|
+
#
|
160
|
+
# fixtures :web_sites
|
161
|
+
#
|
162
|
+
# def test_find
|
163
|
+
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# = Dynamic fixtures with ERb
|
167
|
+
#
|
168
|
+
# Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
|
169
|
+
# mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
|
170
|
+
#
|
171
|
+
# <% for i in 1..1000 %>
|
172
|
+
# fix_<%= i %>:
|
173
|
+
# id: <%= i %>
|
174
|
+
# name: guy_<%= 1 %>
|
175
|
+
# <% end %>
|
176
|
+
#
|
177
|
+
# This will create 1000 very simple YAML fixtures.
|
178
|
+
#
|
179
|
+
# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>.
|
180
|
+
# This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable
|
181
|
+
# sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application
|
182
|
+
# is properly testable. Hence, dynamic values in fixtures are to be considered a code smell.
|
183
|
+
#
|
184
|
+
# = Transactional fixtures
|
185
|
+
#
|
186
|
+
# TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case.
|
187
|
+
# They can also turn off auto-instantiation of fixture data since the feature is costly and often unused.
|
188
|
+
#
|
189
|
+
# class FooTest < Test::Unit::TestCase
|
190
|
+
# self.use_transactional_fixtures = true
|
191
|
+
# self.use_instantiated_fixtures = false
|
192
|
+
#
|
193
|
+
# fixtures :foos
|
194
|
+
#
|
195
|
+
# def test_godzilla
|
196
|
+
# assert !Foo.find(:all).empty?
|
197
|
+
# Foo.destroy_all
|
198
|
+
# assert Foo.find(:all).empty?
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# def test_godzilla_aftermath
|
202
|
+
# assert !Foo.find(:all).empty?
|
203
|
+
# end
|
204
|
+
# end
|
205
|
+
#
|
206
|
+
# If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
|
207
|
+
# then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
|
208
|
+
#
|
209
|
+
# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
|
210
|
+
# access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
|
211
|
+
#
|
212
|
+
# When *not* to use transactional fixtures:
|
213
|
+
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
|
214
|
+
# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
|
215
|
+
# the results of your transaction until Active Record supports nested transactions or savepoints (in progress.)
|
216
|
+
# 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
|
217
|
+
# Use InnoDB, MaxDB, or NDB instead.
|
218
|
+
class Fixtures < YAML::Omap
|
219
|
+
DEFAULT_FILTER_RE = /\.ya?ml$/
|
220
|
+
|
221
|
+
def self.instantiate_fixtures(object, table_name, fixtures, load_instances=true)
|
222
|
+
object.instance_variable_set "@#{table_name.to_s.gsub('.','_')}", fixtures
|
223
|
+
if load_instances
|
224
|
+
ActiveRecord::Base.silence do
|
225
|
+
fixtures.each do |name, fixture|
|
226
|
+
begin
|
227
|
+
object.instance_variable_set "@#{name}", fixture.find
|
228
|
+
rescue FixtureClassNotFound
|
229
|
+
nil
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.instantiate_all_loaded_fixtures(object, load_instances=true)
|
237
|
+
all_loaded_fixtures.each do |table_name, fixtures|
|
238
|
+
Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
cattr_accessor :all_loaded_fixtures
|
243
|
+
self.all_loaded_fixtures = {}
|
244
|
+
|
245
|
+
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
|
246
|
+
table_names = [table_names].flatten.map { |n| n.to_s }
|
247
|
+
connection = block_given? ? yield : ActiveRecord::Base.connection
|
248
|
+
ActiveRecord::Base.silence do
|
249
|
+
fixtures_map = {}
|
250
|
+
fixtures = table_names.map do |table_name|
|
251
|
+
fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
|
252
|
+
end
|
253
|
+
all_loaded_fixtures.merge! fixtures_map
|
254
|
+
|
255
|
+
connection.transaction(Thread.current['open_transactions'] == 0) do
|
256
|
+
fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
|
257
|
+
fixtures.each { |fixture| fixture.insert_fixtures }
|
258
|
+
|
259
|
+
# Cap primary key sequences to max(pk).
|
260
|
+
if connection.respond_to?(:reset_pk_sequence!)
|
261
|
+
table_names.each do |table_name|
|
262
|
+
connection.reset_pk_sequence!(table_name)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
return fixtures.size > 1 ? fixtures : fixtures.first
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
attr_reader :table_name
|
273
|
+
|
274
|
+
def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)
|
275
|
+
@connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
|
276
|
+
@class_name = class_name ||
|
277
|
+
(ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
|
278
|
+
@table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
|
279
|
+
@table_name = class_name.table_name if class_name.respond_to?(:table_name)
|
280
|
+
@connection = class_name.connection if class_name.respond_to?(:connection)
|
281
|
+
read_fixture_files
|
282
|
+
end
|
283
|
+
|
284
|
+
def delete_existing_fixtures
|
285
|
+
@connection.delete "DELETE FROM #{@table_name}", 'Fixture Delete'
|
286
|
+
end
|
287
|
+
|
288
|
+
def insert_fixtures
|
289
|
+
values.each do |fixture|
|
290
|
+
@connection.execute "INSERT INTO #{@table_name} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert'
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
private
|
295
|
+
|
296
|
+
def read_fixture_files
|
297
|
+
if File.file?(yaml_file_path)
|
298
|
+
# YAML fixtures
|
299
|
+
yaml_string = ""
|
300
|
+
Dir["#{@fixture_path}/**/*.yml"].select {|f| test(?f,f) }.each do |subfixture_path|
|
301
|
+
yaml_string << IO.read(subfixture_path)
|
302
|
+
end
|
303
|
+
yaml_string << IO.read(yaml_file_path)
|
304
|
+
|
305
|
+
begin
|
306
|
+
yaml = YAML::load(erb_render(yaml_string))
|
307
|
+
rescue Exception=>boom
|
308
|
+
raise Fixture::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{boom.class}: #{boom}"
|
309
|
+
end
|
310
|
+
|
311
|
+
if yaml
|
312
|
+
# If the file is an ordered map, extract its children.
|
313
|
+
yaml_value =
|
314
|
+
if yaml.respond_to?(:type_id) && yaml.respond_to?(:value)
|
315
|
+
yaml.value
|
316
|
+
else
|
317
|
+
[yaml]
|
318
|
+
end
|
319
|
+
|
320
|
+
yaml_value.each do |fixture|
|
321
|
+
fixture.each do |name, data|
|
322
|
+
unless data
|
323
|
+
raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
|
324
|
+
end
|
325
|
+
|
326
|
+
self[name] = Fixture.new(data, @class_name)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
elsif File.file?(csv_file_path)
|
331
|
+
# CSV fixtures
|
332
|
+
reader = CSV::Reader.create(erb_render(IO.read(csv_file_path)))
|
333
|
+
header = reader.shift
|
334
|
+
i = 0
|
335
|
+
reader.each do |row|
|
336
|
+
data = {}
|
337
|
+
row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip }
|
338
|
+
self["#{Inflector::underscore(@class_name)}_#{i+=1}"]= Fixture.new(data, @class_name)
|
339
|
+
end
|
340
|
+
elsif File.file?(deprecated_yaml_file_path)
|
341
|
+
raise Fixture::FormatError, ".yml extension required: rename #{deprecated_yaml_file_path} to #{yaml_file_path}"
|
342
|
+
else
|
343
|
+
# Standard fixtures
|
344
|
+
Dir.entries(@fixture_path).each do |file|
|
345
|
+
path = File.join(@fixture_path, file)
|
346
|
+
if File.file?(path) and file !~ @file_filter
|
347
|
+
self[file] = Fixture.new(path, @class_name)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def yaml_file_path
|
354
|
+
"#{@fixture_path}.yml"
|
355
|
+
end
|
356
|
+
|
357
|
+
def deprecated_yaml_file_path
|
358
|
+
"#{@fixture_path}.yaml"
|
359
|
+
end
|
360
|
+
|
361
|
+
def csv_file_path
|
362
|
+
@fixture_path + ".csv"
|
363
|
+
end
|
364
|
+
|
365
|
+
def yaml_fixtures_key(path)
|
366
|
+
File.basename(@fixture_path).split(".").first
|
367
|
+
end
|
368
|
+
|
369
|
+
def erb_render(fixture_content)
|
370
|
+
ERB.new(fixture_content).result
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
class Fixture #:nodoc:
|
375
|
+
include Enumerable
|
376
|
+
class FixtureError < StandardError#:nodoc:
|
377
|
+
end
|
378
|
+
class FormatError < FixtureError#:nodoc:
|
379
|
+
end
|
380
|
+
|
381
|
+
def initialize(fixture, class_name)
|
382
|
+
case fixture
|
383
|
+
when Hash, YAML::Omap
|
384
|
+
@fixture = fixture
|
385
|
+
when String
|
386
|
+
@fixture = read_fixture_file(fixture)
|
387
|
+
else
|
388
|
+
raise ArgumentError, "Bad fixture argument #{fixture.inspect} during creation of #{class_name} fixture"
|
389
|
+
end
|
390
|
+
|
391
|
+
@class_name = class_name
|
392
|
+
end
|
393
|
+
|
394
|
+
def each
|
395
|
+
@fixture.each { |item| yield item }
|
396
|
+
end
|
397
|
+
|
398
|
+
def [](key)
|
399
|
+
@fixture[key]
|
400
|
+
end
|
401
|
+
|
402
|
+
def to_hash
|
403
|
+
@fixture
|
404
|
+
end
|
405
|
+
|
406
|
+
def key_list
|
407
|
+
columns = @fixture.keys.collect{ |column_name| ActiveRecord::Base.connection.quote_column_name(column_name) }
|
408
|
+
columns.join(", ")
|
409
|
+
end
|
410
|
+
|
411
|
+
def value_list
|
412
|
+
klass = @class_name.constantize rescue nil
|
413
|
+
|
414
|
+
list = @fixture.inject([]) do |fixtures, (key, value)|
|
415
|
+
col = klass.columns_hash[key] if klass.kind_of?(ActiveRecord::Base)
|
416
|
+
fixtures << ActiveRecord::Base.connection.quote(value, col).gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r")
|
417
|
+
end
|
418
|
+
list * ', '
|
419
|
+
end
|
420
|
+
|
421
|
+
def find
|
422
|
+
klass = @class_name.is_a?(Class) ? @class_name : Object.const_get(@class_name) rescue nil
|
423
|
+
if klass
|
424
|
+
klass.find(self[klass.primary_key])
|
425
|
+
else
|
426
|
+
raise FixtureClassNotFound, "The class #{@class_name.inspect} was not found."
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
private
|
431
|
+
def read_fixture_file(fixture_file_path)
|
432
|
+
IO.readlines(fixture_file_path).inject({}) do |fixture, line|
|
433
|
+
# Mercifully skip empty lines.
|
434
|
+
next if line =~ /^\s*$/
|
435
|
+
|
436
|
+
# Use the same regular expression for attributes as Active Record.
|
437
|
+
unless md = /^\s*([a-zA-Z][-_\w]*)\s*=>\s*(.+)\s*$/.match(line)
|
438
|
+
raise FormatError, "#{fixture_file_path}: fixture format error at '#{line}'. Expecting 'key => value'."
|
439
|
+
end
|
440
|
+
key, value = md.captures
|
441
|
+
|
442
|
+
# Disallow duplicate keys to catch typos.
|
443
|
+
raise FormatError, "#{fixture_file_path}: duplicate '#{key}' in fixture." if fixture[key]
|
444
|
+
fixture[key] = value.strip
|
445
|
+
fixture
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
module Test #:nodoc:
|
451
|
+
module Unit #:nodoc:
|
452
|
+
class TestCase #:nodoc:
|
453
|
+
cattr_accessor :fixture_path
|
454
|
+
class_inheritable_accessor :fixture_table_names
|
455
|
+
class_inheritable_accessor :fixture_class_names
|
456
|
+
class_inheritable_accessor :use_transactional_fixtures
|
457
|
+
class_inheritable_accessor :use_instantiated_fixtures # true, false, or :no_instances
|
458
|
+
class_inheritable_accessor :pre_loaded_fixtures
|
459
|
+
|
460
|
+
self.fixture_table_names = []
|
461
|
+
self.use_transactional_fixtures = false
|
462
|
+
self.use_instantiated_fixtures = true
|
463
|
+
self.pre_loaded_fixtures = false
|
464
|
+
|
465
|
+
self.fixture_class_names = {}
|
466
|
+
|
467
|
+
@@already_loaded_fixtures = {}
|
468
|
+
self.fixture_class_names = {}
|
469
|
+
|
470
|
+
def self.set_fixture_class(class_names = {})
|
471
|
+
self.fixture_class_names = self.fixture_class_names.merge(class_names)
|
472
|
+
end
|
473
|
+
|
474
|
+
def self.fixtures(*table_names)
|
475
|
+
table_names = table_names.flatten.map { |n| n.to_s }
|
476
|
+
self.fixture_table_names |= table_names
|
477
|
+
require_fixture_classes(table_names)
|
478
|
+
setup_fixture_accessors(table_names)
|
479
|
+
end
|
480
|
+
|
481
|
+
def self.require_fixture_classes(table_names=nil)
|
482
|
+
(table_names || fixture_table_names).each do |table_name|
|
483
|
+
file_name = table_name.to_s
|
484
|
+
file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
|
485
|
+
begin
|
486
|
+
require_dependency file_name
|
487
|
+
rescue LoadError
|
488
|
+
# Let's hope the developer has included it himself
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
def self.setup_fixture_accessors(table_names=nil)
|
494
|
+
(table_names || fixture_table_names).each do |table_name|
|
495
|
+
table_name = table_name.to_s.tr('.','_')
|
496
|
+
define_method(table_name) do |fixture, *optionals|
|
497
|
+
force_reload = optionals.shift
|
498
|
+
@fixture_cache[table_name] ||= Hash.new
|
499
|
+
@fixture_cache[table_name][fixture] = nil if force_reload
|
500
|
+
if @loaded_fixtures[table_name][fixture.to_s]
|
501
|
+
@fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
|
502
|
+
else
|
503
|
+
raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def self.uses_transaction(*methods)
|
510
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
511
|
+
@uses_transaction.concat methods.map(&:to_s)
|
512
|
+
end
|
513
|
+
|
514
|
+
def self.uses_transaction?(method)
|
515
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
516
|
+
@uses_transaction.include?(method.to_s)
|
517
|
+
end
|
518
|
+
|
519
|
+
def use_transactional_fixtures?
|
520
|
+
use_transactional_fixtures &&
|
521
|
+
!self.class.uses_transaction?(method_name)
|
522
|
+
end
|
523
|
+
|
524
|
+
def setup_with_fixtures
|
525
|
+
return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
|
526
|
+
|
527
|
+
if pre_loaded_fixtures && !use_transactional_fixtures
|
528
|
+
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
529
|
+
end
|
530
|
+
|
531
|
+
@fixture_cache = Hash.new
|
532
|
+
|
533
|
+
# Load fixtures once and begin transaction.
|
534
|
+
if use_transactional_fixtures?
|
535
|
+
if @@already_loaded_fixtures[self.class]
|
536
|
+
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
537
|
+
else
|
538
|
+
load_fixtures
|
539
|
+
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
540
|
+
end
|
541
|
+
ActiveRecord::Base.send :increment_open_transactions
|
542
|
+
ActiveRecord::Base.connection.begin_db_transaction
|
543
|
+
|
544
|
+
# Load fixtures for every test.
|
545
|
+
else
|
546
|
+
@@already_loaded_fixtures[self.class] = nil
|
547
|
+
load_fixtures
|
548
|
+
end
|
549
|
+
|
550
|
+
# Instantiate fixtures for every test if requested.
|
551
|
+
instantiate_fixtures if use_instantiated_fixtures
|
552
|
+
end
|
553
|
+
|
554
|
+
alias_method :setup, :setup_with_fixtures
|
555
|
+
|
556
|
+
def teardown_with_fixtures
|
557
|
+
return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
|
558
|
+
|
559
|
+
# Rollback changes if a transaction is active.
|
560
|
+
if use_transactional_fixtures? && Thread.current['open_transactions'] != 0
|
561
|
+
ActiveRecord::Base.connection.rollback_db_transaction
|
562
|
+
Thread.current['open_transactions'] = 0
|
563
|
+
end
|
564
|
+
ActiveRecord::Base.verify_active_connections!
|
565
|
+
end
|
566
|
+
|
567
|
+
alias_method :teardown, :teardown_with_fixtures
|
568
|
+
|
569
|
+
def self.method_added(method)
|
570
|
+
case method.to_s
|
571
|
+
when 'setup'
|
572
|
+
unless method_defined?(:setup_without_fixtures)
|
573
|
+
alias_method :setup_without_fixtures, :setup
|
574
|
+
define_method(:setup) do
|
575
|
+
setup_with_fixtures
|
576
|
+
setup_without_fixtures
|
577
|
+
end
|
578
|
+
end
|
579
|
+
when 'teardown'
|
580
|
+
unless method_defined?(:teardown_without_fixtures)
|
581
|
+
alias_method :teardown_without_fixtures, :teardown
|
582
|
+
define_method(:teardown) do
|
583
|
+
teardown_without_fixtures
|
584
|
+
teardown_with_fixtures
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
private
|
591
|
+
def load_fixtures
|
592
|
+
@loaded_fixtures = {}
|
593
|
+
fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
|
594
|
+
unless fixtures.nil?
|
595
|
+
if fixtures.instance_of?(Fixtures)
|
596
|
+
@loaded_fixtures[fixtures.table_name] = fixtures
|
597
|
+
else
|
598
|
+
fixtures.each { |f| @loaded_fixtures[f.table_name] = f }
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
# for pre_loaded_fixtures, only require the classes once. huge speed improvement
|
604
|
+
@@required_fixture_classes = false
|
605
|
+
|
606
|
+
def instantiate_fixtures
|
607
|
+
if pre_loaded_fixtures
|
608
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
|
609
|
+
unless @@required_fixture_classes
|
610
|
+
self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
|
611
|
+
@@required_fixture_classes = true
|
612
|
+
end
|
613
|
+
Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
|
614
|
+
else
|
615
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
|
616
|
+
@loaded_fixtures.each do |table_name, fixtures|
|
617
|
+
Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
|
618
|
+
end
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
def load_instances?
|
623
|
+
use_instantiated_fixtures != :no_instances
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
end
|
628
|
+
end
|