ferblape-query_memcached 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. data/.gitignore +2 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.markdown +87 -0
  4. data/RUNNING_TESTS +18 -0
  5. data/Rakefile +37 -0
  6. data/TODO +6 -0
  7. data/init.rb +3 -0
  8. data/lib/extensions/lock.rb +31 -0
  9. data/lib/query_memcached.rb +191 -0
  10. data/test/query_memcached_test.rb +26 -0
  11. data/test/testing_app/README +1 -0
  12. data/test/testing_app/Rakefile +8 -0
  13. data/test/testing_app/app/controllers/application.rb +15 -0
  14. data/test/testing_app/app/helpers/application_helper.rb +3 -0
  15. data/test/testing_app/app/models/author.rb +133 -0
  16. data/test/testing_app/app/models/auto_id.rb +4 -0
  17. data/test/testing_app/app/models/binary.rb +2 -0
  18. data/test/testing_app/app/models/book.rb +4 -0
  19. data/test/testing_app/app/models/categorization.rb +5 -0
  20. data/test/testing_app/app/models/category.rb +29 -0
  21. data/test/testing_app/app/models/citation.rb +6 -0
  22. data/test/testing_app/app/models/club.rb +7 -0
  23. data/test/testing_app/app/models/column_name.rb +3 -0
  24. data/test/testing_app/app/models/comment.rb +25 -0
  25. data/test/testing_app/app/models/company.rb +123 -0
  26. data/test/testing_app/app/models/company_in_module.rb +61 -0
  27. data/test/testing_app/app/models/computer.rb +4 -0
  28. data/test/testing_app/app/models/contact.rb +16 -0
  29. data/test/testing_app/app/models/course.rb +3 -0
  30. data/test/testing_app/app/models/customer.rb +55 -0
  31. data/test/testing_app/app/models/default.rb +2 -0
  32. data/test/testing_app/app/models/developer.rb +76 -0
  33. data/test/testing_app/app/models/edge.rb +5 -0
  34. data/test/testing_app/app/models/entrant.rb +3 -0
  35. data/test/testing_app/app/models/guid.rb +2 -0
  36. data/test/testing_app/app/models/item.rb +7 -0
  37. data/test/testing_app/app/models/job.rb +5 -0
  38. data/test/testing_app/app/models/joke.rb +3 -0
  39. data/test/testing_app/app/models/keyboard.rb +3 -0
  40. data/test/testing_app/app/models/legacy_thing.rb +3 -0
  41. data/test/testing_app/app/models/matey.rb +4 -0
  42. data/test/testing_app/app/models/member.rb +9 -0
  43. data/test/testing_app/app/models/membership.rb +9 -0
  44. data/test/testing_app/app/models/minimalistic.rb +2 -0
  45. data/test/testing_app/app/models/mixed_case_monkey.rb +3 -0
  46. data/test/testing_app/app/models/movie.rb +5 -0
  47. data/test/testing_app/app/models/order.rb +4 -0
  48. data/test/testing_app/app/models/owner.rb +4 -0
  49. data/test/testing_app/app/models/parrot.rb +13 -0
  50. data/test/testing_app/app/models/person.rb +10 -0
  51. data/test/testing_app/app/models/pet.rb +4 -0
  52. data/test/testing_app/app/models/pirate.rb +9 -0
  53. data/test/testing_app/app/models/post.rb +80 -0
  54. data/test/testing_app/app/models/price_estimate.rb +3 -0
  55. data/test/testing_app/app/models/project.rb +29 -0
  56. data/test/testing_app/app/models/reader.rb +4 -0
  57. data/test/testing_app/app/models/reference.rb +4 -0
  58. data/test/testing_app/app/models/reply.rb +39 -0
  59. data/test/testing_app/app/models/ship.rb +3 -0
  60. data/test/testing_app/app/models/sponsor.rb +4 -0
  61. data/test/testing_app/app/models/subject.rb +4 -0
  62. data/test/testing_app/app/models/subscriber.rb +8 -0
  63. data/test/testing_app/app/models/subscription.rb +4 -0
  64. data/test/testing_app/app/models/tag.rb +7 -0
  65. data/test/testing_app/app/models/tagging.rb +10 -0
  66. data/test/testing_app/app/models/task.rb +2 -0
  67. data/test/testing_app/app/models/topic.rb +65 -0
  68. data/test/testing_app/app/models/treasure.rb +6 -0
  69. data/test/testing_app/app/models/vertex.rb +9 -0
  70. data/test/testing_app/app/models/warehouse_thing.rb +5 -0
  71. data/test/testing_app/config/boot.rb +109 -0
  72. data/test/testing_app/config/database.yml +11 -0
  73. data/test/testing_app/config/environment.rb +19 -0
  74. data/test/testing_app/config/environments/development.rb +0 -0
  75. data/test/testing_app/config/environments/production.rb +0 -0
  76. data/test/testing_app/config/environments/test.rb +0 -0
  77. data/test/testing_app/config/initializers/inflections.rb +10 -0
  78. data/test/testing_app/config/initializers/mime_types.rb +5 -0
  79. data/test/testing_app/config/initializers/new_rails_defaults.rb +15 -0
  80. data/test/testing_app/config/routes.rb +41 -0
  81. data/test/testing_app/db/schema.rb +443 -0
  82. data/test/testing_app/script/about +3 -0
  83. data/test/testing_app/script/console +3 -0
  84. data/test/testing_app/script/dbconsole +3 -0
  85. data/test/testing_app/script/destroy +3 -0
  86. data/test/testing_app/script/generate +3 -0
  87. data/test/testing_app/script/performance/benchmarker +3 -0
  88. data/test/testing_app/script/performance/profiler +3 -0
  89. data/test/testing_app/script/performance/request +3 -0
  90. data/test/testing_app/script/plugin +3 -0
  91. data/test/testing_app/script/process/inspector +3 -0
  92. data/test/testing_app/script/process/reaper +3 -0
  93. data/test/testing_app/script/process/spawner +3 -0
  94. data/test/testing_app/script/runner +3 -0
  95. data/test/testing_app/script/server +3 -0
  96. data/test/testing_app/test/fixtures/accounts.yml +28 -0
  97. data/test/testing_app/test/fixtures/all/developers.yml +0 -0
  98. data/test/testing_app/test/fixtures/all/people.csv +0 -0
  99. data/test/testing_app/test/fixtures/all/tasks.yml +0 -0
  100. data/test/testing_app/test/fixtures/author_addresses.yml +5 -0
  101. data/test/testing_app/test/fixtures/author_favorites.yml +4 -0
  102. data/test/testing_app/test/fixtures/authors.yml +9 -0
  103. data/test/testing_app/test/fixtures/binaries.yml +132 -0
  104. data/test/testing_app/test/fixtures/books.yml +7 -0
  105. data/test/testing_app/test/fixtures/categories.yml +14 -0
  106. data/test/testing_app/test/fixtures/categories/special_categories.yml +9 -0
  107. data/test/testing_app/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  108. data/test/testing_app/test/fixtures/categories_posts.yml +23 -0
  109. data/test/testing_app/test/fixtures/categorizations.yml +17 -0
  110. data/test/testing_app/test/fixtures/clubs.yml +6 -0
  111. data/test/testing_app/test/fixtures/comments.yml +59 -0
  112. data/test/testing_app/test/fixtures/companies.yml +55 -0
  113. data/test/testing_app/test/fixtures/computers.yml +4 -0
  114. data/test/testing_app/test/fixtures/courses.yml +7 -0
  115. data/test/testing_app/test/fixtures/customers.yml +17 -0
  116. data/test/testing_app/test/fixtures/developers.yml +21 -0
  117. data/test/testing_app/test/fixtures/developers_projects.yml +17 -0
  118. data/test/testing_app/test/fixtures/edges.yml +6 -0
  119. data/test/testing_app/test/fixtures/entrants.yml +14 -0
  120. data/test/testing_app/test/fixtures/fk_test_has_fk.yml +3 -0
  121. data/test/testing_app/test/fixtures/fk_test_has_pk.yml +2 -0
  122. data/test/testing_app/test/fixtures/funny_jokes.yml +10 -0
  123. data/test/testing_app/test/fixtures/items.yml +4 -0
  124. data/test/testing_app/test/fixtures/jobs.yml +7 -0
  125. data/test/testing_app/test/fixtures/legacy_things.yml +3 -0
  126. data/test/testing_app/test/fixtures/mateys.yml +4 -0
  127. data/test/testing_app/test/fixtures/members.yml +4 -0
  128. data/test/testing_app/test/fixtures/memberships.yml +20 -0
  129. data/test/testing_app/test/fixtures/minimalistics.yml +2 -0
  130. data/test/testing_app/test/fixtures/mixed_case_monkeys.yml +6 -0
  131. data/test/testing_app/test/fixtures/mixins.yml +29 -0
  132. data/test/testing_app/test/fixtures/movies.yml +7 -0
  133. data/test/testing_app/test/fixtures/naked/csv/accounts.csv +1 -0
  134. data/test/testing_app/test/fixtures/naked/yml/accounts.yml +1 -0
  135. data/test/testing_app/test/fixtures/naked/yml/companies.yml +1 -0
  136. data/test/testing_app/test/fixtures/naked/yml/courses.yml +1 -0
  137. data/test/testing_app/test/fixtures/owners.yml +7 -0
  138. data/test/testing_app/test/fixtures/parrots.yml +27 -0
  139. data/test/testing_app/test/fixtures/parrots_pirates.yml +7 -0
  140. data/test/testing_app/test/fixtures/people.yml +6 -0
  141. data/test/testing_app/test/fixtures/pets.yml +14 -0
  142. data/test/testing_app/test/fixtures/pirates.yml +9 -0
  143. data/test/testing_app/test/fixtures/posts.yml +49 -0
  144. data/test/testing_app/test/fixtures/price_estimates.yml +7 -0
  145. data/test/testing_app/test/fixtures/projects.yml +7 -0
  146. data/test/testing_app/test/fixtures/readers.yml +9 -0
  147. data/test/testing_app/test/fixtures/references.yml +17 -0
  148. data/test/testing_app/test/fixtures/reserved_words/distinct.yml +5 -0
  149. data/test/testing_app/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  150. data/test/testing_app/test/fixtures/reserved_words/group.yml +14 -0
  151. data/test/testing_app/test/fixtures/reserved_words/select.yml +8 -0
  152. data/test/testing_app/test/fixtures/reserved_words/values.yml +7 -0
  153. data/test/testing_app/test/fixtures/ships.yml +5 -0
  154. data/test/testing_app/test/fixtures/sponsors.yml +9 -0
  155. data/test/testing_app/test/fixtures/subscribers.yml +7 -0
  156. data/test/testing_app/test/fixtures/subscriptions.yml +12 -0
  157. data/test/testing_app/test/fixtures/taggings.yml +28 -0
  158. data/test/testing_app/test/fixtures/tags.yml +7 -0
  159. data/test/testing_app/test/fixtures/tasks.yml +7 -0
  160. data/test/testing_app/test/fixtures/topics.yml +42 -0
  161. data/test/testing_app/test/fixtures/treasures.yml +10 -0
  162. data/test/testing_app/test/fixtures/vertices.yml +4 -0
  163. data/test/testing_app/test/fixtures/warehouse-things.yml +3 -0
  164. data/test/testing_app/test/test_helper.rb +131 -0
  165. data/test/testing_app/test/unit/query_cache_test.rb +180 -0
  166. metadata +289 -0
@@ -0,0 +1,16 @@
1
+ class Contact < ActiveRecord::Base
2
+ # mock out self.columns so no pesky db is needed for these tests
3
+ def self.column(name, sql_type = nil, options = {})
4
+ @columns ||= []
5
+ @columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default], sql_type.to_s, options[:null])
6
+ end
7
+
8
+ column :name, :string
9
+ column :age, :integer
10
+ column :avatar, :binary
11
+ column :created_at, :datetime
12
+ column :awesome, :boolean
13
+ column :preferences, :string
14
+
15
+ serialize :preferences
16
+ end
@@ -0,0 +1,3 @@
1
+ class Course < ActiveRecord::Base
2
+ has_many :entrants
3
+ end
@@ -0,0 +1,55 @@
1
+ class Customer < ActiveRecord::Base
2
+ composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true
3
+ composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money }
4
+ composed_of :gps_location, :allow_nil => true
5
+ end
6
+
7
+ class Address
8
+ attr_reader :street, :city, :country
9
+
10
+ def initialize(street, city, country)
11
+ @street, @city, @country = street, city, country
12
+ end
13
+
14
+ def close_to?(other_address)
15
+ city == other_address.city && country == other_address.country
16
+ end
17
+
18
+ def ==(other)
19
+ other.is_a?(self.class) && other.street == street && other.city == city && other.country == country
20
+ end
21
+ end
22
+
23
+ class Money
24
+ attr_reader :amount, :currency
25
+
26
+ EXCHANGE_RATES = { "USD_TO_DKK" => 6, "DKK_TO_USD" => 0.6 }
27
+
28
+ def initialize(amount, currency = "USD")
29
+ @amount, @currency = amount, currency
30
+ end
31
+
32
+ def exchange_to(other_currency)
33
+ Money.new((amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor, other_currency)
34
+ end
35
+ end
36
+
37
+ class GpsLocation
38
+ attr_reader :gps_location
39
+
40
+ def initialize(gps_location)
41
+ @gps_location = gps_location
42
+ end
43
+
44
+ def latitude
45
+ gps_location.split("x").first
46
+ end
47
+
48
+ def longitude
49
+ gps_location.split("x").last
50
+ end
51
+
52
+ def ==(other)
53
+ self.latitude == other.latitude && self.longitude == other.longitude
54
+ end
55
+ end
@@ -0,0 +1,2 @@
1
+ class Default < ActiveRecord::Base
2
+ end
@@ -0,0 +1,76 @@
1
+ module DeveloperProjectsAssociationExtension
2
+ def find_most_recent
3
+ find(:first, :order => "id DESC")
4
+ end
5
+ end
6
+
7
+ module DeveloperProjectsAssociationExtension2
8
+ def find_least_recent
9
+ find(:first, :order => "id ASC")
10
+ end
11
+ end
12
+
13
+ class Developer < ActiveRecord::Base
14
+ has_and_belongs_to_many :projects do
15
+ def find_most_recent
16
+ find(:first, :order => "id DESC")
17
+ end
18
+ end
19
+
20
+ has_and_belongs_to_many :projects_extended_by_name,
21
+ :class_name => "Project",
22
+ :join_table => "developers_projects",
23
+ :association_foreign_key => "project_id",
24
+ :extend => DeveloperProjectsAssociationExtension
25
+
26
+ has_and_belongs_to_many :projects_extended_by_name_twice,
27
+ :class_name => "Project",
28
+ :join_table => "developers_projects",
29
+ :association_foreign_key => "project_id",
30
+ :extend => [DeveloperProjectsAssociationExtension, DeveloperProjectsAssociationExtension2]
31
+
32
+ has_and_belongs_to_many :projects_extended_by_name_and_block,
33
+ :class_name => "Project",
34
+ :join_table => "developers_projects",
35
+ :association_foreign_key => "project_id",
36
+ :extend => DeveloperProjectsAssociationExtension do
37
+ def find_least_recent
38
+ find(:first, :order => "id ASC")
39
+ end
40
+ end
41
+
42
+ has_and_belongs_to_many :special_projects, :join_table => 'developers_projects', :association_foreign_key => 'project_id'
43
+
44
+ has_many :audit_logs
45
+
46
+ validates_inclusion_of :salary, :in => 50000..200000
47
+ validates_length_of :name, :within => 3..20
48
+
49
+ before_create do |developer|
50
+ developer.audit_logs.build :message => "Computer created"
51
+ end
52
+
53
+ def log=(message)
54
+ audit_logs.build :message => message
55
+ end
56
+ end
57
+
58
+ class AuditLog < ActiveRecord::Base
59
+ belongs_to :developer
60
+ end
61
+
62
+ DeveloperSalary = Struct.new(:amount)
63
+ class DeveloperWithAggregate < ActiveRecord::Base
64
+ self.table_name = 'developers'
65
+ composed_of :salary, :class_name => 'DeveloperSalary', :mapping => [%w(salary amount)]
66
+ end
67
+
68
+ class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base
69
+ self.table_name = 'developers'
70
+ has_and_belongs_to_many :projects, :join_table => 'developers_projects', :foreign_key => 'developer_id'
71
+ before_destroy :raise_if_projects_empty!
72
+
73
+ def raise_if_projects_empty!
74
+ raise if projects.empty?
75
+ end
76
+ end
@@ -0,0 +1,5 @@
1
+ # This class models an edge in a directed graph.
2
+ class Edge < ActiveRecord::Base
3
+ belongs_to :source, :class_name => 'Vertex', :foreign_key => 'source_id'
4
+ belongs_to :sink, :class_name => 'Vertex', :foreign_key => 'sink_id'
5
+ end
@@ -0,0 +1,3 @@
1
+ class Entrant < ActiveRecord::Base
2
+ belongs_to :course
3
+ end
@@ -0,0 +1,2 @@
1
+ class Guid < ActiveRecord::Base
2
+ end
@@ -0,0 +1,7 @@
1
+ class AbstractItem < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ has_one :tagging, :as => :taggable
4
+ end
5
+
6
+ class Item < AbstractItem
7
+ end
@@ -0,0 +1,5 @@
1
+ class Job < ActiveRecord::Base
2
+ has_many :references
3
+ has_many :people, :through => :references
4
+ belongs_to :ideal_reference, :class_name => 'Reference'
5
+ end
@@ -0,0 +1,3 @@
1
+ class Joke < ActiveRecord::Base
2
+ set_table_name 'funny_jokes'
3
+ end
@@ -0,0 +1,3 @@
1
+ class Keyboard < ActiveRecord::Base
2
+ set_primary_key 'key_number'
3
+ end
@@ -0,0 +1,3 @@
1
+ class LegacyThing < ActiveRecord::Base
2
+ set_locking_column :version
3
+ end
@@ -0,0 +1,4 @@
1
+ class Matey < ActiveRecord::Base
2
+ belongs_to :pirate
3
+ belongs_to :target, :class_name => 'Pirate'
4
+ end
@@ -0,0 +1,9 @@
1
+ class Member < ActiveRecord::Base
2
+ has_one :current_membership
3
+ has_many :memberships
4
+ has_many :fellow_members, :through => :club, :source => :members
5
+ has_one :club, :through => :current_membership
6
+ has_one :favourite_club, :through => :memberships, :conditions => ["memberships.favourite = ?", true], :source => :club
7
+ has_one :sponsor, :as => :sponsorable
8
+ has_one :sponsor_club, :through => :sponsor
9
+ end
@@ -0,0 +1,9 @@
1
+ class Membership < ActiveRecord::Base
2
+ belongs_to :member
3
+ belongs_to :club
4
+ end
5
+
6
+ class CurrentMembership < Membership
7
+ belongs_to :member
8
+ belongs_to :club
9
+ end
@@ -0,0 +1,2 @@
1
+ class Minimalistic < ActiveRecord::Base
2
+ end
@@ -0,0 +1,3 @@
1
+ class MixedCaseMonkey < ActiveRecord::Base
2
+ set_primary_key 'monkeyID'
3
+ end
@@ -0,0 +1,5 @@
1
+ class Movie < ActiveRecord::Base
2
+ def self.primary_key
3
+ "movieid"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ class Order < ActiveRecord::Base
2
+ belongs_to :billing, :class_name => 'Customer', :foreign_key => 'billing_customer_id'
3
+ belongs_to :shipping, :class_name => 'Customer', :foreign_key => 'shipping_customer_id'
4
+ end
@@ -0,0 +1,4 @@
1
+ class Owner < ActiveRecord::Base
2
+ set_primary_key :owner_id
3
+ has_many :pets
4
+ end
@@ -0,0 +1,13 @@
1
+ class Parrot < ActiveRecord::Base
2
+ set_inheritance_column :parrot_sti_class
3
+ has_and_belongs_to_many :pirates
4
+ has_and_belongs_to_many :treasures
5
+ has_many :loots, :as => :looter
6
+ end
7
+
8
+ class LiveParrot < Parrot
9
+ end
10
+
11
+ class DeadParrot < Parrot
12
+ belongs_to :killer, :class_name => 'Pirate'
13
+ end
@@ -0,0 +1,10 @@
1
+ class Person < ActiveRecord::Base
2
+ has_many :readers
3
+ has_many :posts, :through => :readers
4
+ has_many :posts_with_no_comments, :through => :readers, :source => :post, :include => :comments, :conditions => 'comments.id is null'
5
+
6
+ has_many :references
7
+ has_many :jobs, :through => :references
8
+ has_one :favourite_reference, :class_name => 'Reference', :conditions => ['favourite=?', true]
9
+
10
+ end
@@ -0,0 +1,4 @@
1
+ class Pet < ActiveRecord::Base
2
+ set_primary_key :pet_id
3
+ belongs_to :owner
4
+ end
@@ -0,0 +1,9 @@
1
+ class Pirate < ActiveRecord::Base
2
+ belongs_to :parrot
3
+ has_and_belongs_to_many :parrots
4
+ has_many :treasures, :as => :looter
5
+
6
+ has_many :treasure_estimates, :through => :treasures, :source => :price_estimates
7
+
8
+ validates_presence_of :catchphrase
9
+ end
@@ -0,0 +1,80 @@
1
+ class Post < ActiveRecord::Base
2
+ named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'"
3
+
4
+ belongs_to :author do
5
+ def greeting
6
+ "hello"
7
+ end
8
+ end
9
+
10
+ belongs_to :author_with_posts, :class_name => "Author", :foreign_key => :author_id, :include => :posts
11
+
12
+ has_one :last_comment, :class_name => 'Comment', :order => 'id desc'
13
+
14
+ has_many :comments, :order => "body" do
15
+ def find_most_recent
16
+ find(:first, :order => "id DESC")
17
+ end
18
+ end
19
+
20
+ has_many :comments_with_interpolated_conditions, :class_name => 'Comment',
21
+ :conditions => ['#{"#{aliased_table_name}." rescue ""}body = ?', 'Thank you for the welcome']
22
+
23
+ has_one :very_special_comment
24
+ has_one :very_special_comment_with_post, :class_name => "VerySpecialComment", :include => :post
25
+ has_many :special_comments
26
+ has_many :nonexistant_comments, :class_name => 'Comment', :conditions => 'comments.id < 0'
27
+
28
+ has_and_belongs_to_many :categories
29
+ has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id'
30
+
31
+ has_many :taggings, :as => :taggable
32
+ has_many :tags, :through => :taggings do
33
+ def add_joins_and_select
34
+ find :all, :select => 'tags.*, authors.id as author_id', :include => false,
35
+ :joins => 'left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id'
36
+ end
37
+ end
38
+
39
+ has_many :funky_tags, :through => :taggings, :source => :tag
40
+ has_many :super_tags, :through => :taggings
41
+ has_one :tagging, :as => :taggable
42
+
43
+ has_many :invalid_taggings, :as => :taggable, :class_name => "Tagging", :conditions => 'taggings.id < 0'
44
+ has_many :invalid_tags, :through => :invalid_taggings, :source => :tag
45
+
46
+ has_many :categorizations, :foreign_key => :category_id
47
+ has_many :authors, :through => :categorizations
48
+
49
+ has_many :readers
50
+ has_many :people, :through => :readers
51
+ has_many :people_with_callbacks, :source=>:person, :through => :readers,
52
+ :before_add => lambda {|owner, reader| log(:added, :before, reader.first_name) },
53
+ :after_add => lambda {|owner, reader| log(:added, :after, reader.first_name) },
54
+ :before_remove => lambda {|owner, reader| log(:removed, :before, reader.first_name) },
55
+ :after_remove => lambda {|owner, reader| log(:removed, :after, reader.first_name) }
56
+
57
+ def self.reset_log
58
+ @log = []
59
+ end
60
+
61
+ def self.log(message=nil, side=nil, new_record=nil)
62
+ return @log if message.nil?
63
+ @log << [message, side, new_record]
64
+ end
65
+
66
+ def self.what_are_you
67
+ 'a post...'
68
+ end
69
+ end
70
+
71
+ class SpecialPost < Post; end
72
+
73
+ class StiPost < Post
74
+ self.abstract_class = true
75
+ has_one :special_comment, :class_name => "SpecialComment"
76
+ end
77
+
78
+ class SubStiPost < StiPost
79
+ self.table_name = Post.table_name
80
+ end
@@ -0,0 +1,3 @@
1
+ class PriceEstimate < ActiveRecord::Base
2
+ belongs_to :estimate_of, :polymorphic => true
3
+ end
@@ -0,0 +1,29 @@
1
+ class Project < ActiveRecord::Base
2
+ has_and_belongs_to_many :developers, :uniq => true, :order => 'developers.name desc, developers.id desc'
3
+ has_and_belongs_to_many :readonly_developers, :class_name => "Developer", :readonly => true
4
+ has_and_belongs_to_many :selected_developers, :class_name => "Developer", :select => "developers.*", :uniq => true
5
+ has_and_belongs_to_many :non_unique_developers, :order => 'developers.name desc, developers.id desc', :class_name => 'Developer'
6
+ has_and_belongs_to_many :limited_developers, :class_name => "Developer", :limit => 1
7
+ has_and_belongs_to_many :developers_named_david, :class_name => "Developer", :conditions => "name = 'David'", :uniq => true
8
+ has_and_belongs_to_many :developers_named_david_with_hash_conditions, :class_name => "Developer", :conditions => { :name => 'David' }, :uniq => true
9
+ has_and_belongs_to_many :salaried_developers, :class_name => "Developer", :conditions => "salary > 0"
10
+ has_and_belongs_to_many :developers_with_finder_sql, :class_name => "Developer", :finder_sql => 'SELECT t.*, j.* FROM developers_projects j, developers t WHERE t.id = j.developer_id AND j.project_id = #{id}'
11
+ has_and_belongs_to_many :developers_by_sql, :class_name => "Developer", :delete_sql => "DELETE FROM developers_projects WHERE project_id = \#{id} AND developer_id = \#{record.id}"
12
+ has_and_belongs_to_many :developers_with_callbacks, :class_name => "Developer", :before_add => Proc.new {|o, r| o.developers_log << "before_adding#{r.id || '<new>'}"},
13
+ :after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id || '<new>'}"},
14
+ :before_remove => Proc.new {|o, r| o.developers_log << "before_removing#{r.id}"},
15
+ :after_remove => Proc.new {|o, r| o.developers_log << "after_removing#{r.id}"}
16
+
17
+ attr_accessor :developers_log
18
+
19
+ def after_initialize
20
+ @developers_log = []
21
+ end
22
+
23
+ end
24
+
25
+ class SpecialProject < Project
26
+ def hello_world
27
+ "hello there!"
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ class Reader < ActiveRecord::Base
2
+ belongs_to :post
3
+ belongs_to :person
4
+ end
@@ -0,0 +1,4 @@
1
+ class Reference < ActiveRecord::Base
2
+ belongs_to :person
3
+ belongs_to :job
4
+ end
@@ -0,0 +1,39 @@
1
+ require 'models/topic'
2
+
3
+ class Reply < Topic
4
+ named_scope :base
5
+
6
+ belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true
7
+ has_many :replies, :class_name => "SillyReply", :dependent => :destroy, :foreign_key => "parent_id"
8
+
9
+ validate :errors_on_empty_content
10
+ validate_on_create :title_is_wrong_create
11
+
12
+ attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read
13
+
14
+ def validate
15
+ errors.add("title", "Empty") unless attribute_present? "title"
16
+ end
17
+
18
+ def errors_on_empty_content
19
+ errors.add("content", "Empty") unless attribute_present? "content"
20
+ end
21
+
22
+ def validate_on_create
23
+ if attribute_present?("title") && attribute_present?("content") && content == "Mismatch"
24
+ errors.add("title", "is Content Mismatch")
25
+ end
26
+ end
27
+
28
+ def title_is_wrong_create
29
+ errors.add("title", "is Wrong Create") if attribute_present?("title") && title == "Wrong Create"
30
+ end
31
+
32
+ def validate_on_update
33
+ errors.add("title", "is Wrong Update") if attribute_present?("title") && title == "Wrong Update"
34
+ end
35
+ end
36
+
37
+ class SillyReply < Reply
38
+ belongs_to :reply, :foreign_key => "parent_id", :counter_cache => :replies_count
39
+ end