has_many_polymorphs 2.2 → 2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. data/CHANGELOG +0 -9
  2. data/README +6 -52
  3. data/TODO +1 -0
  4. data/generators/tagging/tagging_generator.rb +1 -14
  5. data/generators/tagging/templates/tag_test.rb +3 -8
  6. data/generators/tagging/templates/tagging.rb +2 -2
  7. data/generators/tagging/templates/tagging_extensions.rb +13 -106
  8. data/generators/tagging/templates/tagging_test.rb +14 -41
  9. data/generators/tagging/templates/taggings.yml +3 -5
  10. data/generators/tagging/templates/tags.yml +2 -2
  11. data/has_many_polymorphs.gemspec +36 -29
  12. data/lib/has_many_polymorphs.rb +5 -6
  13. data/lib/has_many_polymorphs/association.rb +8 -9
  14. data/lib/has_many_polymorphs/autoload.rb +16 -52
  15. data/lib/has_many_polymorphs/base.rb +3 -13
  16. data/lib/has_many_polymorphs/class_methods.rb +102 -181
  17. data/lib/has_many_polymorphs/debugging_tools.rb +0 -2
  18. data/lib/has_many_polymorphs/dependencies.rb +36 -0
  19. data/lib/has_many_polymorphs/rake_task_redefine_task.rb +1 -9
  20. data/lib/has_many_polymorphs/reflection.rb +6 -7
  21. data/lib/has_many_polymorphs/support_methods.rb +4 -10
  22. data/test/fixtures/{fish.yml → aquatic/fish.yml} +0 -0
  23. data/test/fixtures/{little_whale_pupils.yml → aquatic/little_whale_pupils.yml} +0 -0
  24. data/test/fixtures/{whales.yml → aquatic/whales.yml} +0 -0
  25. data/test/models/aquatic/fish.rb +1 -2
  26. data/test/models/aquatic/whale.rb +0 -2
  27. data/test/models/eaters_foodstuff.rb +3 -1
  28. data/test/models/petfood.rb +1 -2
  29. data/test/schema.rb +0 -15
  30. data/test/test_helper.rb +18 -39
  31. data/test/unit/{has_many_polymorphs_test.rb → polymorph_test.rb} +109 -181
  32. metadata +92 -265
  33. data.tar.gz.sig +0 -1
  34. data/Manifest +0 -173
  35. data/Rakefile +0 -28
  36. data/examples/hmph.rb +0 -69
  37. data/lib/has_many_polymorphs/configuration.rb +0 -19
  38. data/test/fixtures/people.yml +0 -7
  39. data/test/generator/tagging_generator_test.rb +0 -42
  40. data/test/integration/app/README +0 -182
  41. data/test/integration/app/Rakefile +0 -19
  42. data/test/integration/app/app/controllers/application.rb +0 -7
  43. data/test/integration/app/app/controllers/bones_controller.rb +0 -5
  44. data/test/integration/app/app/helpers/addresses_helper.rb +0 -2
  45. data/test/integration/app/app/helpers/application_helper.rb +0 -3
  46. data/test/integration/app/app/helpers/bones_helper.rb +0 -2
  47. data/test/integration/app/app/helpers/sellers_helper.rb +0 -28
  48. data/test/integration/app/app/helpers/states_helper.rb +0 -2
  49. data/test/integration/app/app/helpers/users_helper.rb +0 -2
  50. data/test/integration/app/app/models/bone.rb +0 -2
  51. data/test/integration/app/app/models/double_sti_parent.rb +0 -2
  52. data/test/integration/app/app/models/double_sti_parent_relationship.rb +0 -2
  53. data/test/integration/app/app/models/organic_substance.rb +0 -2
  54. data/test/integration/app/app/models/single_sti_parent.rb +0 -4
  55. data/test/integration/app/app/models/single_sti_parent_relationship.rb +0 -4
  56. data/test/integration/app/app/models/stick.rb +0 -2
  57. data/test/integration/app/app/models/stone.rb +0 -2
  58. data/test/integration/app/app/views/addresses/edit.html.erb +0 -12
  59. data/test/integration/app/app/views/addresses/index.html.erb +0 -18
  60. data/test/integration/app/app/views/addresses/new.html.erb +0 -11
  61. data/test/integration/app/app/views/addresses/show.html.erb +0 -3
  62. data/test/integration/app/app/views/bones/index.rhtml +0 -5
  63. data/test/integration/app/app/views/layouts/addresses.html.erb +0 -17
  64. data/test/integration/app/app/views/layouts/sellers.html.erb +0 -17
  65. data/test/integration/app/app/views/layouts/states.html.erb +0 -17
  66. data/test/integration/app/app/views/layouts/users.html.erb +0 -17
  67. data/test/integration/app/app/views/sellers/edit.html.erb +0 -12
  68. data/test/integration/app/app/views/sellers/index.html.erb +0 -20
  69. data/test/integration/app/app/views/sellers/new.html.erb +0 -11
  70. data/test/integration/app/app/views/sellers/show.html.erb +0 -3
  71. data/test/integration/app/app/views/states/edit.html.erb +0 -12
  72. data/test/integration/app/app/views/states/index.html.erb +0 -19
  73. data/test/integration/app/app/views/states/new.html.erb +0 -11
  74. data/test/integration/app/app/views/states/show.html.erb +0 -3
  75. data/test/integration/app/app/views/users/edit.html.erb +0 -12
  76. data/test/integration/app/app/views/users/index.html.erb +0 -22
  77. data/test/integration/app/app/views/users/new.html.erb +0 -11
  78. data/test/integration/app/app/views/users/show.html.erb +0 -3
  79. data/test/integration/app/config/boot.rb +0 -110
  80. data/test/integration/app/config/database.yml +0 -17
  81. data/test/integration/app/config/environment.rb +0 -19
  82. data/test/integration/app/config/environment.rb.canonical +0 -19
  83. data/test/integration/app/config/environments/development.rb +0 -9
  84. data/test/integration/app/config/environments/production.rb +0 -18
  85. data/test/integration/app/config/environments/test.rb +0 -19
  86. data/test/integration/app/config/locomotive.yml +0 -6
  87. data/test/integration/app/config/routes.rb +0 -33
  88. data/test/integration/app/config/ultrasphinx/default.base +0 -56
  89. data/test/integration/app/config/ultrasphinx/development.conf.canonical +0 -155
  90. data/test/integration/app/db/migrate/001_create_sticks.rb +0 -11
  91. data/test/integration/app/db/migrate/002_create_stones.rb +0 -11
  92. data/test/integration/app/db/migrate/003_create_organic_substances.rb +0 -11
  93. data/test/integration/app/db/migrate/004_create_bones.rb +0 -8
  94. data/test/integration/app/db/migrate/005_create_single_sti_parents.rb +0 -11
  95. data/test/integration/app/db/migrate/006_create_double_sti_parents.rb +0 -11
  96. data/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb +0 -13
  97. data/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb +0 -14
  98. data/test/integration/app/db/migrate/009_create_library_model.rb +0 -11
  99. data/test/integration/app/doc/README_FOR_APP +0 -2
  100. data/test/integration/app/generators/commenting_generator_test.rb +0 -83
  101. data/test/integration/app/lib/library_model.rb +0 -2
  102. data/test/integration/app/public/404.html +0 -30
  103. data/test/integration/app/public/500.html +0 -30
  104. data/test/integration/app/public/dispatch.cgi +0 -10
  105. data/test/integration/app/public/dispatch.fcgi +0 -24
  106. data/test/integration/app/public/dispatch.rb +0 -10
  107. data/test/integration/app/public/favicon.ico +0 -0
  108. data/test/integration/app/public/images/rails.png +0 -0
  109. data/test/integration/app/public/index.html +0 -277
  110. data/test/integration/app/public/javascripts/application.js +0 -2
  111. data/test/integration/app/public/javascripts/controls.js +0 -833
  112. data/test/integration/app/public/javascripts/dragdrop.js +0 -942
  113. data/test/integration/app/public/javascripts/effects.js +0 -1088
  114. data/test/integration/app/public/javascripts/prototype.js +0 -2515
  115. data/test/integration/app/public/robots.txt +0 -1
  116. data/test/integration/app/public/stylesheets/scaffold.css +0 -74
  117. data/test/integration/app/script/about +0 -3
  118. data/test/integration/app/script/breakpointer +0 -3
  119. data/test/integration/app/script/console +0 -3
  120. data/test/integration/app/script/destroy +0 -3
  121. data/test/integration/app/script/generate +0 -3
  122. data/test/integration/app/script/performance/benchmarker +0 -3
  123. data/test/integration/app/script/performance/profiler +0 -3
  124. data/test/integration/app/script/plugin +0 -3
  125. data/test/integration/app/script/process/inspector +0 -3
  126. data/test/integration/app/script/process/reaper +0 -3
  127. data/test/integration/app/script/process/spawner +0 -3
  128. data/test/integration/app/script/runner +0 -3
  129. data/test/integration/app/script/server +0 -3
  130. data/test/integration/app/test/fixtures/double_sti_parent_relationships.yml +0 -7
  131. data/test/integration/app/test/fixtures/double_sti_parents.yml +0 -7
  132. data/test/integration/app/test/fixtures/organic_substances.yml +0 -5
  133. data/test/integration/app/test/fixtures/single_sti_parent_relationships.yml +0 -7
  134. data/test/integration/app/test/fixtures/single_sti_parents.yml +0 -7
  135. data/test/integration/app/test/fixtures/sticks.yml +0 -7
  136. data/test/integration/app/test/fixtures/stones.yml +0 -7
  137. data/test/integration/app/test/functional/addresses_controller_test.rb +0 -57
  138. data/test/integration/app/test/functional/bones_controller_test.rb +0 -8
  139. data/test/integration/app/test/functional/sellers_controller_test.rb +0 -57
  140. data/test/integration/app/test/functional/states_controller_test.rb +0 -57
  141. data/test/integration/app/test/functional/users_controller_test.rb +0 -57
  142. data/test/integration/app/test/test_helper.rb +0 -8
  143. data/test/integration/app/test/unit/bone_test.rb +0 -8
  144. data/test/integration/app/test/unit/double_sti_parent_relationship_test.rb +0 -8
  145. data/test/integration/app/test/unit/double_sti_parent_test.rb +0 -8
  146. data/test/integration/app/test/unit/organic_substance_test.rb +0 -8
  147. data/test/integration/app/test/unit/single_sti_parent_relationship_test.rb +0 -8
  148. data/test/integration/app/test/unit/single_sti_parent_test.rb +0 -8
  149. data/test/integration/app/test/unit/stick_test.rb +0 -8
  150. data/test/integration/app/test/unit/stone_test.rb +0 -8
  151. data/test/integration/server_test.rb +0 -43
  152. data/test/models/parentship.rb +0 -4
  153. data/test/models/person.rb +0 -9
  154. data/test/patches/symlinked_plugins_1.2.6.diff +0 -46
  155. data/test/setup.rb +0 -14
  156. metadata.gz.sig +0 -0
@@ -1,36 +1,43 @@
1
- # -*- encoding: utf-8 -*-
1
+
2
+ # Gem::Specification for Has_many_polymorphs-2.9
3
+ # Originally generated by Echoe
2
4
 
3
5
  Gem::Specification.new do |s|
4
6
  s.name = %q{has_many_polymorphs}
5
- s.version = "2.2"
6
-
7
- s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
- s.authors = [""]
9
- s.cert_chain = ["/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem"]
10
- s.date = %q{2009-11-18}
11
- s.description = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.}
7
+ s.version = "2.9"
8
+ s.date = %q{2007-08-13}
9
+ s.summary = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.}
12
10
  s.email = %q{}
13
- s.extra_rdoc_files = ["CHANGELOG", "generators/tagging/templates/migration.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tagging_extensions.rb", "lib/has_many_polymorphs/association.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/configuration.rb", "lib/has_many_polymorphs/reflection.rb", "LICENSE", "README", "test/integration/app/doc/README_FOR_APP", "test/integration/app/README", "TODO"]
14
- s.files = ["CHANGELOG", "examples/hmph.rb", "generators/tagging/tagging_generator.rb", "generators/tagging/templates/migration.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/tag_test.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tagging_extensions.rb", "generators/tagging/templates/tagging_test.rb", "generators/tagging/templates/taggings.yml", "generators/tagging/templates/tags.yml", "init.rb", "lib/has_many_polymorphs/association.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/base.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/configuration.rb", "lib/has_many_polymorphs/debugging_tools.rb", "lib/has_many_polymorphs/rake_task_redefine_task.rb", "lib/has_many_polymorphs/reflection.rb", "lib/has_many_polymorphs/support_methods.rb", "lib/has_many_polymorphs.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/fixtures/bow_wows.yml", "test/fixtures/cats.yml", "test/fixtures/eaters_foodstuffs.yml", "test/fixtures/fish.yml", "test/fixtures/frogs.yml", "test/fixtures/keep_your_enemies_close.yml", "test/fixtures/little_whale_pupils.yml", "test/fixtures/people.yml", "test/fixtures/petfoods.yml", "test/fixtures/whales.yml", "test/fixtures/wild_boars.yml", "test/generator/tagging_generator_test.rb", "test/integration/app/app/controllers/application.rb", "test/integration/app/app/controllers/bones_controller.rb", "test/integration/app/app/helpers/addresses_helper.rb", "test/integration/app/app/helpers/application_helper.rb", "test/integration/app/app/helpers/bones_helper.rb", "test/integration/app/app/helpers/sellers_helper.rb", "test/integration/app/app/helpers/states_helper.rb", "test/integration/app/app/helpers/users_helper.rb", "test/integration/app/app/models/bone.rb", "test/integration/app/app/models/double_sti_parent.rb", "test/integration/app/app/models/double_sti_parent_relationship.rb", "test/integration/app/app/models/organic_substance.rb", "test/integration/app/app/models/single_sti_parent.rb", "test/integration/app/app/models/single_sti_parent_relationship.rb", "test/integration/app/app/models/stick.rb", "test/integration/app/app/models/stone.rb", "test/integration/app/app/views/addresses/edit.html.erb", "test/integration/app/app/views/addresses/index.html.erb", "test/integration/app/app/views/addresses/new.html.erb", "test/integration/app/app/views/addresses/show.html.erb", "test/integration/app/app/views/bones/index.rhtml", "test/integration/app/app/views/layouts/addresses.html.erb", "test/integration/app/app/views/layouts/sellers.html.erb", "test/integration/app/app/views/layouts/states.html.erb", "test/integration/app/app/views/layouts/users.html.erb", "test/integration/app/app/views/sellers/edit.html.erb", "test/integration/app/app/views/sellers/index.html.erb", "test/integration/app/app/views/sellers/new.html.erb", "test/integration/app/app/views/sellers/show.html.erb", "test/integration/app/app/views/states/edit.html.erb", "test/integration/app/app/views/states/index.html.erb", "test/integration/app/app/views/states/new.html.erb", "test/integration/app/app/views/states/show.html.erb", "test/integration/app/app/views/users/edit.html.erb", "test/integration/app/app/views/users/index.html.erb", "test/integration/app/app/views/users/new.html.erb", "test/integration/app/app/views/users/show.html.erb", "test/integration/app/config/boot.rb", "test/integration/app/config/database.yml", "test/integration/app/config/environment.rb", "test/integration/app/config/environment.rb.canonical", "test/integration/app/config/environments/development.rb", "test/integration/app/config/environments/production.rb", "test/integration/app/config/environments/test.rb", "test/integration/app/config/locomotive.yml", "test/integration/app/config/routes.rb", "test/integration/app/config/ultrasphinx/default.base", "test/integration/app/config/ultrasphinx/development.conf.canonical", "test/integration/app/db/migrate/001_create_sticks.rb", "test/integration/app/db/migrate/002_create_stones.rb", "test/integration/app/db/migrate/003_create_organic_substances.rb", "test/integration/app/db/migrate/004_create_bones.rb", "test/integration/app/db/migrate/005_create_single_sti_parents.rb", "test/integration/app/db/migrate/006_create_double_sti_parents.rb", "test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb", "test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb", "test/integration/app/db/migrate/009_create_library_model.rb", "test/integration/app/doc/README_FOR_APP", "test/integration/app/generators/commenting_generator_test.rb", "test/integration/app/lib/library_model.rb", "test/integration/app/public/404.html", "test/integration/app/public/500.html", "test/integration/app/public/dispatch.cgi", "test/integration/app/public/dispatch.fcgi", "test/integration/app/public/dispatch.rb", "test/integration/app/public/favicon.ico", "test/integration/app/public/images/rails.png", "test/integration/app/public/index.html", "test/integration/app/public/javascripts/application.js", "test/integration/app/public/javascripts/controls.js", "test/integration/app/public/javascripts/dragdrop.js", "test/integration/app/public/javascripts/effects.js", "test/integration/app/public/javascripts/prototype.js", "test/integration/app/public/robots.txt", "test/integration/app/public/stylesheets/scaffold.css", "test/integration/app/Rakefile", "test/integration/app/README", "test/integration/app/script/about", "test/integration/app/script/breakpointer", "test/integration/app/script/console", "test/integration/app/script/destroy", "test/integration/app/script/generate", "test/integration/app/script/performance/benchmarker", "test/integration/app/script/performance/profiler", "test/integration/app/script/plugin", "test/integration/app/script/process/inspector", "test/integration/app/script/process/reaper", "test/integration/app/script/process/spawner", "test/integration/app/script/runner", "test/integration/app/script/server", "test/integration/app/test/fixtures/double_sti_parent_relationships.yml", "test/integration/app/test/fixtures/double_sti_parents.yml", "test/integration/app/test/fixtures/organic_substances.yml", "test/integration/app/test/fixtures/single_sti_parent_relationships.yml", "test/integration/app/test/fixtures/single_sti_parents.yml", "test/integration/app/test/fixtures/sticks.yml", "test/integration/app/test/fixtures/stones.yml", "test/integration/app/test/functional/addresses_controller_test.rb", "test/integration/app/test/functional/bones_controller_test.rb", "test/integration/app/test/functional/sellers_controller_test.rb", "test/integration/app/test/functional/states_controller_test.rb", "test/integration/app/test/functional/users_controller_test.rb", "test/integration/app/test/test_helper.rb", "test/integration/app/test/unit/bone_test.rb", "test/integration/app/test/unit/double_sti_parent_relationship_test.rb", "test/integration/app/test/unit/double_sti_parent_test.rb", "test/integration/app/test/unit/organic_substance_test.rb", "test/integration/app/test/unit/single_sti_parent_relationship_test.rb", "test/integration/app/test/unit/single_sti_parent_test.rb", "test/integration/app/test/unit/stick_test.rb", "test/integration/app/test/unit/stone_test.rb", "test/integration/server_test.rb", "test/models/aquatic/fish.rb", "test/models/aquatic/pupils_whale.rb", "test/models/aquatic/whale.rb", "test/models/beautiful_fight_relationship.rb", "test/models/canine.rb", "test/models/cat.rb", "test/models/dog.rb", "test/models/eaters_foodstuff.rb", "test/models/frog.rb", "test/models/kitten.rb", "test/models/parentship.rb", "test/models/person.rb", "test/models/petfood.rb", "test/models/tabby.rb", "test/models/wild_boar.rb", "test/modules/extension_module.rb", "test/modules/other_extension_module.rb", "test/patches/symlinked_plugins_1.2.6.diff", "test/schema.rb", "test/setup.rb", "test/test_helper.rb", "test/unit/has_many_polymorphs_test.rb", "TODO", "has_many_polymorphs.gemspec"]
15
- s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/}
16
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Has_many_polymorphs", "--main", "README"]
17
- s.require_paths = ["lib"]
11
+ s.homepage = %q{http://blog.evanweaver.com/pages/code#polymorphs}
18
12
  s.rubyforge_project = %q{fauna}
19
- s.rubygems_version = %q{1.3.5}
20
- s.signing_key = %q{/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-private_key.pem}
21
- s.summary = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.}
22
- s.test_files = ["test/generator/tagging_generator_test.rb", "test/integration/server_test.rb", "test/unit/has_many_polymorphs_test.rb"]
13
+ s.description = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.}
14
+ s.has_rdoc = true
15
+ s.authors = [""]
16
+ s.files = ["test/unit/polymorph_test.rb", "test/test_helper.rb", "test/schema.rb", "test/modules/other_extension_module.rb", "test/modules/extension_module.rb", "test/models/wild_boar.rb", "test/models/tabby.rb", "test/models/petfood.rb", "test/models/kitten.rb", "test/models/frog.rb", "test/models/eaters_foodstuff.rb", "test/models/dog.rb", "test/models/cat.rb", "test/models/canine.rb", "test/models/beautiful_fight_relationship.rb", "test/models/aquatic/whale.rb", "test/models/aquatic/pupils_whale.rb", "test/models/aquatic/fish.rb", "test/fixtures/wild_boars.yml", "test/fixtures/petfoods.yml", "test/fixtures/keep_your_enemies_close.yml", "test/fixtures/frogs.yml", "test/fixtures/eaters_foodstuffs.yml", "test/fixtures/cats.yml", "test/fixtures/bow_wows.yml", "test/fixtures/aquatic/whales.yml", "test/fixtures/aquatic/little_whale_pupils.yml", "test/fixtures/aquatic/fish.yml", "lib/has_many_polymorphs.rb", "lib/has_many_polymorphs/support_methods.rb", "lib/has_many_polymorphs/reflection.rb", "lib/has_many_polymorphs/rake_task_redefine_task.rb", "lib/has_many_polymorphs/dependencies.rb", "lib/has_many_polymorphs/debugging_tools.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/base.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/association.rb", "init.rb", "generators/tagging/templates/tags.yml", "generators/tagging/templates/taggings.yml", "generators/tagging/templates/tagging_test.rb", "generators/tagging/templates/tagging_extensions.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tag_test.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/migration.rb", "generators/tagging/tagging_generator.rb", "TODO", "README", "LICENSE", "CHANGELOG", "has_many_polymorphs.gemspec"]
17
+ s.test_files = ["test/test_helper.rb"]
18
+ s.add_dependency(%q<activerecord>, ["> 0.0.0"])
19
+ end
23
20
 
24
- if s.respond_to? :specification_version then
25
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
- s.specification_version = 3
27
21
 
28
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
29
- s.add_runtime_dependency(%q<activerecord>, [">= 0"])
30
- else
31
- s.add_dependency(%q<activerecord>, [">= 0"])
32
- end
33
- else
34
- s.add_dependency(%q<activerecord>, [">= 0"])
35
- end
36
- end
22
+ # # Original Rakefile source (requires the Echoe gem):
23
+ #
24
+ #
25
+ # require 'rubygems'
26
+ # gem 'echoe', '>=2.2'
27
+ # require 'echoe'
28
+ # require 'lib/has_many_polymorphs/rake_task_redefine_task'
29
+ #
30
+ # Echoe.new("has_many_polymorphs") do |p|
31
+ # p.project = "fauna"
32
+ # p.summary = "An ActiveRecord plugin for self-referential and double-sided polymorphic associations."
33
+ # p.url = "http://blog.evanweaver.com/pages/code#polymorphs"
34
+ # p.docs_host = "blog.evanweaver.com:~/www/snax/public/files/doc/"
35
+ # p.dependencies = ["activerecord"]
36
+ # p.rdoc_pattern = /polymorphs\/association|polymorphs\/class_methods|polymorphs\/reflection|README|CHANGELOG|TODO|LICENSE|templates\/migration\.rb|templates\/tag\.rb|templates\/tagging\.rb|templates\/tagging_extensions\.rb/
37
+ # end
38
+ #
39
+ # desc 'Run the test suite.'
40
+ # Rake::Task.redefine_task("test") do
41
+ # puts "Warning! Tests must be run with the plugin installed in a functioning Rails\nenvironment."
42
+ # system "ruby -Ibin:lib:test test/unit/polymorph_test.rb #{ENV['METHOD'] ? "--name=#{ENV['METHOD']}" : ""}"
43
+ # end
@@ -1,8 +1,6 @@
1
1
 
2
2
  require 'active_record'
3
3
 
4
- RAILS_DEFAULT_LOGGER = nil unless defined? RAILS_DEFAULT_LOGGER
5
-
6
4
  require 'has_many_polymorphs/reflection'
7
5
  require 'has_many_polymorphs/association'
8
6
  require 'has_many_polymorphs/class_methods'
@@ -14,14 +12,15 @@ class ActiveRecord::Base
14
12
  extend ActiveRecord::Associations::PolymorphicClassMethods
15
13
  end
16
14
 
17
- if ENV['HMP_DEBUG'] || ENV['RAILS_ENV'] =~ /development|test/ && ENV['USER'] == 'eweaver'
15
+ if ENV['HMP_DEBUG'] or (ENV['RAILS_ENV'] =~ /development|test/ and ENV['USER'] == 'eweaver')
16
+ _logger_warn "has_many_polymorphs: debug mode enabled"
18
17
  require 'has_many_polymorphs/debugging_tools'
19
18
  end
20
19
 
21
20
  if defined? Rails and RAILS_ENV and RAILS_ROOT
22
- _logger_warn "rails environment detected"
23
- require 'has_many_polymorphs/configuration'
21
+ _logger_warn "has_many_polymorphs: Rails environment detected"
22
+ require 'has_many_polymorphs/dependencies'
24
23
  require 'has_many_polymorphs/autoload'
25
24
  end
26
25
 
27
- _logger_debug "loaded ok"
26
+ _logger_debug "has_many_polymorphs: loaded ok"
@@ -88,19 +88,18 @@ module ActiveRecord #:nodoc:
88
88
  def construct_quoted_owner_attributes(*args) #:nodoc:
89
89
  # no access to returning() here? why not?
90
90
  type_key = @reflection.options[:foreign_type_key]
91
- h = {@reflection.primary_key_name => @owner.id}
92
- h[type_key] = @owner.class.base_class.name if type_key
93
- h
91
+ {@reflection.primary_key_name => @owner.id,
92
+ type_key=> (@owner.class.base_class.name if type_key)}
94
93
  end
95
94
 
96
95
  def construct_from #:nodoc:
97
96
  # build the FROM part of the query, in this case, the polymorphic join table
98
- @reflection.klass.quoted_table_name
97
+ @reflection.klass.table_name
99
98
  end
100
99
 
101
100
  def construct_owner #:nodoc:
102
101
  # the table name for the owner object's class
103
- @owner.class.quoted_table_name
102
+ @owner.class.table_name
104
103
  end
105
104
 
106
105
  def construct_owner_key #:nodoc:
@@ -115,10 +114,10 @@ module ActiveRecord #:nodoc:
115
114
 
116
115
  def construct_joins(custom_joins = nil) #:nodoc:
117
116
  # build the string of default joins
118
- "JOIN #{construct_owner} AS polymorphic_parent ON #{construct_from}.#{@reflection.options[:foreign_key]} = polymorphic_parent.#{construct_owner_key} " +
117
+ "JOIN #{construct_owner} polymorphic_parent ON #{construct_from}.#{@reflection.options[:foreign_key]} = polymorphic_parent.#{construct_owner_key} " +
119
118
  @reflection.options[:from].map do |plural|
120
119
  klass = plural._as_class
121
- "LEFT JOIN #{klass.quoted_table_name} ON #{construct_from}.#{@reflection.options[:polymorphic_key]} = #{klass.quoted_table_name}.#{klass.primary_key} AND #{construct_from}.#{@reflection.options[:polymorphic_type_key]} = #{@reflection.klass.quote_value(klass.base_class.name)}"
120
+ "LEFT JOIN #{klass.table_name} ON #{construct_from}.#{@reflection.options[:polymorphic_key]} = #{klass.table_name}.#{klass.primary_key} AND #{construct_from}.#{@reflection.options[:polymorphic_type_key]} = #{@reflection.klass.quote_value(klass.base_class.name)}"
122
121
  end.uniq.join(" ") + " #{custom_joins}"
123
122
  end
124
123
 
@@ -154,7 +153,7 @@ module ActiveRecord #:nodoc:
154
153
  raise PolymorphicMethodNotSupportedError, "You can't associate new records."
155
154
  end
156
155
 
157
- end
158
-
156
+ end
157
+
159
158
  end
160
159
  end
@@ -1,69 +1,33 @@
1
- require 'initializer' unless defined? ::Rails::Initializer
2
- require 'action_controller/dispatcher' unless defined? ::ActionController::Dispatcher
3
1
 
4
- module HasManyPolymorphs
2
+ require 'initializer'
5
3
 
6
- =begin rdoc
4
+ class Rails::Initializer
5
+
6
+ =begin rdoc
7
7
  Searches for models that use <tt>has_many_polymorphs</tt> or <tt>acts_as_double_polymorphic_join</tt> and makes sure that they get loaded during app initialization. This ensures that helper methods are injected into the target classes.
8
8
 
9
- Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_polymorphs_options. For example, if you need an application extension to be required before has_many_polymorphs loads your models, add an <tt>after_initialize</tt> block in <tt>config/environment.rb</tt> that appends to the <tt>'requirements'</tt> key:
10
- Rails::Initializer.run do |config|
11
- # your other configuration here
12
-
13
- config.after_initialize do
14
- config.has_many_polymorphs_options['requirements'] << 'lib/my_extension'
15
- end
16
- end
17
-
9
+ Overrides Rails::Initializer#after_initialize.
18
10
  =end
19
11
 
20
- DEFAULT_OPTIONS = {
21
- :file_pattern => "#{RAILS_ROOT}/app/models/**/*.rb",
22
- :file_exclusions => ['svn', 'CVS', 'bzr'],
23
- :methods => ['has_many_polymorphs', 'acts_as_double_polymorphic_join'],
24
- :requirements => []}
25
-
26
- mattr_accessor :options
27
- @@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS)
28
-
29
- # Dispatcher callback to load polymorphic relationships from the top down.
30
- def self.autoload
31
-
32
- _logger_debug "autoload hook invoked"
33
-
34
- options[:requirements].each do |requirement|
35
- _logger_warn "forcing requirement load of #{requirement}"
36
- require requirement
37
- end
12
+ def after_initialize_with_autoload
13
+ after_initialize_without_autoload
38
14
 
39
- Dir.glob(options[:file_pattern]).each do |filename|
40
- next if filename =~ /#{options[:file_exclusions].join("|")}/
15
+ _logger_debug "has_many_polymorphs: autoload hook invoked"
16
+ Dir["#{RAILS_ROOT}/app/models/**/*.rb"].each do |filename|
17
+ next if filename =~ /svn|CVS|bzr/
41
18
  open filename do |file|
42
- if file.grep(/#{options[:methods].join("|")}/).any?
19
+ if file.grep(/has_many_polymorphs|acts_as_double_polymorphic_join/).any?
43
20
  begin
44
- model = File.basename(filename)[0..-4].camelize
45
- _logger_warn "preloading parent model #{model}"
21
+ model = File.basename(filename)[0..-4].classify
22
+ _logger_warn "has_many_polymorphs: preloading parent model #{model}"
46
23
  model.constantize
47
24
  rescue Object => e
48
- _logger_warn "#{model} could not be preloaded: #{e.inspect}"
25
+ _logger_warn "has_many_polymorphs: WARNING; possibly critical error preloading #{model}: #{e.inspect}"
49
26
  end
50
27
  end
51
28
  end
52
29
  end
53
30
  end
54
-
55
- end
56
-
57
- class Rails::Initializer #:nodoc:
58
- # Make sure it gets loaded in the console, tests, and migrations
59
- def after_initialize_with_autoload
60
- after_initialize_without_autoload
61
- HasManyPolymorphs.autoload
62
- end
63
- alias_method_chain :after_initialize, :autoload
64
- end
65
-
66
- ActionController::Dispatcher.to_prepare(:has_many_polymorphs_autoload) do
67
- # Make sure it gets loaded in the app
68
- HasManyPolymorphs.autoload
31
+
32
+ alias_method_chain :after_initialize, :autoload
69
33
  end
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  class << self
6
6
 
7
7
  # Interprets a polymorphic row from a unified SELECT, returning the appropriate ActiveRecord instance. Overrides ActiveRecord::Base.instantiate_without_callbacks.
8
- def instantiate_with_polymorphic_checks(record)
8
+ def instantiate_without_callbacks_with_polymorphic_checks(record)
9
9
  if record['polymorphic_parent_class']
10
10
  reflection = record['polymorphic_parent_class'].constantize.reflect_on_association(record['polymorphic_association_id'].to_sym)
11
11
  # _logger_debug "Instantiating a polymorphic row for #{record['polymorphic_parent_class']}.reflect_on_association(:#{record['polymorphic_association_id']})"
@@ -37,23 +37,13 @@ module ActiveRecord
37
37
  # allocate and assign values
38
38
  returning(klass.allocate) do |obj|
39
39
  obj.instance_variable_set("@attributes", record)
40
- obj.instance_variable_set("@attributes_cache", Hash.new)
41
-
42
- if obj.respond_to_without_attributes?(:after_find)
43
- obj.send(:callback, :after_find)
44
- end
45
-
46
- if obj.respond_to_without_attributes?(:after_initialize)
47
- obj.send(:callback, :after_initialize)
48
- end
49
-
50
40
  end
51
41
  else
52
- instantiate_without_polymorphic_checks(record)
42
+ instantiate_without_callbacks_without_polymorphic_checks(record)
53
43
  end
54
44
  end
55
45
 
56
- alias_method_chain :instantiate, :polymorphic_checks
46
+ alias_method_chain :instantiate_without_callbacks, :polymorphic_checks
57
47
  end
58
48
 
59
49
  end
@@ -12,17 +12,14 @@ STI association targets must enumerated and named. For example, if Dog and Cat b
12
12
 
13
13
  Namespaced models follow the Rails <tt>underscore</tt> convention. ZooAnimal::Lion becomes <tt>:'zoo_animal/lion'</tt>.
14
14
 
15
- You do not need to set up any other associations other than for either the regular method or the double. The join associations and all individual and reverse associations are generated for you. However, a join model and table are required.
16
-
17
- There is a tentative report that you can make the parent model be its own join model, but this is untested.
15
+ You do not need to set up any other associations other than for either the regular method or the double. The join associations and all individual and reverse associations are generated for you. However, a join class and table is required. There are tentative reports that it works without it if you make the parent class join to the targets <tt>:through</tt> itself, but this is untested.
18
16
 
19
17
  =end
20
18
 
21
19
  module PolymorphicClassMethods
22
20
 
23
- RESERVED_DOUBLES_KEYS = [:conditions, :order, :limit, :offset, :extend, :skip_duplicates,
24
- :join_extend, :dependent, :rename_individual_collections,
25
- :namespace] #:nodoc:
21
+ RESERVED_KEYS = [:conditions, :order, :limit, :offset, :extend, :skip_duplicates,
22
+ :join_extend, :dependent, :rename_individual_collections] #:nodoc:
26
23
 
27
24
  =begin rdoc
28
25
 
@@ -55,22 +52,41 @@ These options are passed through to targets on both sides of the association. If
55
52
  <tt>:order</tt>:: A string for the SQL <tt>ORDER BY</tt> clause.
56
53
  <tt>:limit</tt>:: An integer. Affects the polymorphic and individual associations.
57
54
  <tt>:offset</tt>:: An integer. Only affects the polymorphic association.
58
- <tt>:namespace</tt>:: A symbol. Prepended to all the models in the <tt>:from</tt> and <tt>:through</tt> keys. This is especially useful for Camping, which namespaces models by default.
59
-
55
+
60
56
  =end
61
57
 
62
- def acts_as_double_polymorphic_join options={}, &extension
58
+ def acts_as_double_polymorphic_join options={}, &extension
63
59
 
64
- collections, options = extract_double_collections(options)
60
+ collections = options._select {|k,v| v.is_a? Array and k.to_s !~ /(#{RESERVED_KEYS.map(&:to_s).join('|')})$/}
61
+ raise PolymorphicError, "Couldn't understand options in acts_as_double_polymorphic_join. Valid parameters are your two class collections, and then #{RESERVED_KEYS.inspect[1..-2]}, with optionally your collection names prepended and joined with an underscore." unless collections.size == 2
65
62
 
66
- # handle the block
67
- options[:extend] = (if options[:extend]
68
- Array(options[:extend]) + [extension]
69
- else
70
- extension
71
- end) if extension
72
-
73
- collection_option_keys = make_general_option_keys_specific!(options, collections)
63
+ options = options._select {|k,v| !collections[k]}
64
+ options[:extend] = (options[:extend] ? Array(options[:extend]) + [extension] : extension) if extension # inline the block
65
+
66
+ collection_option_keys = Hash[*collections.keys.map do |key|
67
+ [key, RESERVED_KEYS.map{|option| "#{key}_#{option}".to_sym}]
68
+ end._flatten_once]
69
+
70
+ collections.keys.each do |collection|
71
+ options.each do |key, value|
72
+ next if collection_option_keys.values.flatten.include? key
73
+ # shift the general options to the individual sides
74
+ collection_value = options[collection_key = "#{collection}_#{key}".to_sym]
75
+ case key
76
+ when :conditions
77
+ collection_value, value = sanitize_sql(collection_value), sanitize_sql(value)
78
+ options[collection_key] = (collection_value ? "(#{collection_value}) AND (#{value})" : value)
79
+ when :order
80
+ options[collection_key] = (collection_value ? "#{collection_value}, #{value}" : value)
81
+ when :extend, :join_extend
82
+ options[collection_key] = Array(collection_value) + Array(value)
83
+ when :limit, :offset, :dependent, :rename_individual_collections
84
+ options[collection_key] ||= value
85
+ else
86
+ raise PolymorphicError, "Unknown option key #{key.inspect}."
87
+ end
88
+ end
89
+ end
74
90
 
75
91
  join_name = self.name.tableize.to_sym
76
92
  collections.each do |association_id, children|
@@ -81,7 +97,7 @@ These options are passed through to targets on both sides of the association. If
81
97
  rescue NoMethodError
82
98
  raise PolymorphicError, "Couldn't find 'belongs_to' association for :#{parent_hash_key._singularize} in #{self.name}." unless parent_foreign_key
83
99
  end
84
-
100
+
85
101
  parents = collections[parent_hash_key]
86
102
  conflicts = (children & parents) # set intersection
87
103
  parents.each do |plural_parent_name|
@@ -89,31 +105,19 @@ These options are passed through to targets on both sides of the association. If
89
105
  parent_class = plural_parent_name._as_class
90
106
  singular_reverse_association_id = parent_hash_key._singularize
91
107
 
92
- internal_options = {
93
- :is_double => true,
94
- :from => children,
95
- :as => singular_reverse_association_id,
96
- :through => join_name.to_sym,
97
- :foreign_key => parent_foreign_key,
98
- :foreign_type_key => parent_foreign_key.to_s.sub(/_id$/, '_type'),
99
- :singular_reverse_association_id => singular_reverse_association_id,
100
- :conflicts => conflicts
101
- }
102
-
103
- general_options = Hash[*options._select do |key, value|
104
- collection_option_keys[association_id].include? key and !value.nil?
105
- end.map do |key, value|
106
- [key.to_s[association_id.to_s.length+1..-1].to_sym, value]
107
- end._flatten_once] # rename side-specific options to general names
108
-
109
- general_options.each do |key, value|
110
- # avoid clobbering keys that appear in both option sets
111
- if internal_options[key]
112
- general_options[key] = Array(value) + Array(internal_options[key])
113
- end
114
- end
115
-
116
- parent_class.send(:has_many_polymorphs, association_id, internal_options.merge(general_options))
108
+ parent_class.send(:has_many_polymorphs,
109
+ association_id, {:is_double => true,
110
+ :from => children,
111
+ :as => singular_reverse_association_id,
112
+ :through => join_name.to_sym,
113
+ :foreign_key => parent_foreign_key,
114
+ :foreign_type_key => parent_foreign_key.to_s.sub(/_id$/, '_type'),
115
+ :singular_reverse_association_id => singular_reverse_association_id,
116
+ :conflicts => conflicts}.merge(Hash[*options._select do |key, value|
117
+ collection_option_keys[association_id].include? key and !value.nil?
118
+ end.map do |key, value|
119
+ [key.to_s[association_id.to_s.length+1..-1].to_sym, value]
120
+ end._flatten_once])) # rename side-specific options to general names
117
121
 
118
122
  if conflicts.include? plural_parent_name
119
123
  # unify the alternate sides of the conflicting children
@@ -124,7 +128,7 @@ These options are passed through to targets on both sides of the association. If
124
128
  self.send("#{association_id._singularize}_#{method_name}")).freeze
125
129
  end
126
130
  end
127
- end
131
+ end
128
132
 
129
133
  # unify the join model... join model is always renamed for doubles, unlike child associations
130
134
  unless parent_class.instance_methods.include?(join_name)
@@ -142,54 +146,6 @@ These options are passed through to targets on both sides of the association. If
142
146
  end
143
147
  end
144
148
  end
145
-
146
- private
147
-
148
- def extract_double_collections(options)
149
- collections = options._select do |key, value|
150
- value.is_a? Array and key.to_s !~ /(#{RESERVED_DOUBLES_KEYS.map(&:to_s).join('|')})$/
151
- end
152
-
153
- raise PolymorphicError, "Couldn't understand options in acts_as_double_polymorphic_join. Valid parameters are your two class collections, and then #{RESERVED_DOUBLES_KEYS.inspect[1..-2]}, with optionally your collection names prepended and joined with an underscore." unless collections.size == 2
154
-
155
- options = options._select do |key, value|
156
- !collections[key]
157
- end
158
-
159
- [collections, options]
160
- end
161
-
162
- def make_general_option_keys_specific!(options, collections)
163
- collection_option_keys = Hash[*collections.keys.map do |key|
164
- [key, RESERVED_DOUBLES_KEYS.map{|option| "#{key}_#{option}".to_sym}]
165
- end._flatten_once]
166
-
167
- collections.keys.each do |collection|
168
- options.each do |key, value|
169
- next if collection_option_keys.values.flatten.include? key
170
- # shift the general options to the individual sides
171
- collection_key = "#{collection}_#{key}".to_sym
172
- collection_value = options[collection_key]
173
- case key
174
- when :conditions
175
- collection_value, value = sanitize_sql(collection_value), sanitize_sql(value)
176
- options[collection_key] = (collection_value ? "(#{collection_value}) AND (#{value})" : value)
177
- when :order
178
- options[collection_key] = (collection_value ? "#{collection_value}, #{value}" : value)
179
- when :extend, :join_extend
180
- options[collection_key] = Array(collection_value) + Array(value)
181
- else
182
- options[collection_key] ||= value
183
- end
184
- end
185
- end
186
-
187
- collection_option_keys
188
- end
189
-
190
-
191
-
192
- public
193
149
 
194
150
  =begin rdoc
195
151
 
@@ -201,45 +157,36 @@ This method createds a single-sided polymorphic relationship.
201
157
 
202
158
  The only required parameter, aside from the association name, is <tt>:from</tt>.
203
159
 
204
- The method generates a number of associations aside from the polymorphic one. In this example Petfood also gets <tt>dogs</tt>, <tt>cats</tt>, and <tt>birds</tt>, and Dog, Cat, and Bird get <tt>petfoods</tt>. (The reverse association to the parents is always plural.)
160
+ The method generates a number of associations aside from the polymorphic one. In this example Petfood also gets <tt>dogs</tt>, <tt>cats</tt>, and <tt>birds</tt>, and Dog, Cat, and Bird get <tt>petfoods</tt>. (The reverse association to the parent is always plural.)
205
161
 
206
162
  == Available options
207
163
 
208
- <tt>:from</tt>:: An array of symbols representing the target models. Required.
164
+ <tt>:from</tt>:: An array of symbols representing the target classes. Required.
209
165
  <tt>:as</tt>:: A symbol for the parent's interface in the join--what the parent 'acts as'.
210
166
  <tt>:through</tt>:: A symbol representing the class of the join model. Follows Rails defaults if not supplied (the parent and the association names, alphabetized, concatenated with an underscore, and singularized).
167
+ <tt>:foreign_key</tt>:: The column name for the parent's id in the join.
168
+ <tt>:foreign_type_key</tt>:: The column name for the parent's class in the join, if the parent itself is polymorphic. Rarely needed.
169
+ <tt>:polymorphic_key</tt>:: The column name for the child's id in the join.
170
+ <tt>:polymorphic_type_key</tt>:: The column name for the child's class in the join.
211
171
  <tt>:dependent</tt>:: Accepts <tt>:destroy</tt>, <tt>:nullify</tt>, <tt>:delete_all</tt>. Controls how the join record gets treated on any associate delete (whether from the polymorph or from an individual collection); defaults to <tt>:destroy</tt>.
212
172
  <tt>:skip_duplicates</tt>:: If <tt>true</tt>, will check to avoid pushing already associated records (but also triggering a database load). Defaults to <tt>true</tt>.
213
173
  <tt>:rename_individual_collections</tt>:: If <tt>true</tt>, all individual collections are prepended with the polymorph name, and the children's parent collection is appended with "_of_#{association_name}"</tt>. For example, <tt>zoos</tt> becomes <tt>zoos_of_animals</tt>. This is to help avoid method name collisions in crowded classes.
214
174
  <tt>:extend</tt>:: One or an array of mixed modules and procs, which are applied to the polymorphic association (usually to define custom methods).
215
175
  <tt>:join_extend</tt>:: One or an array of mixed modules and procs, which are applied to the join association.
216
- <tt>:parent_extend</tt>:: One or an array of mixed modules and procs, which are applied to the target models' association to the parents.
176
+ <tt>:parent_extend</tt>:: One or an array of mixed modules and procs, which are applied to the target classes' association to the parent.
217
177
  <tt>:conditions</tt>:: An array or string of conditions for the SQL <tt>WHERE</tt> clause.
218
- <tt>:parent_conditions</tt>:: An array or string of conditions which are applied to the target models' association to the parents.
219
178
  <tt>:order</tt>:: A string for the SQL <tt>ORDER BY</tt> clause.
220
- <tt>:parent_order</tt>:: A string for the SQL <tt>ORDER BY</tt> which is applied to the target models' association to the parents.
221
179
  <tt>:group</tt>:: An array or string of conditions for the SQL <tt>GROUP BY</tt> clause. Affects the polymorphic and individual associations.
222
180
  <tt>:limit</tt>:: An integer. Affects the polymorphic and individual associations.
223
181
  <tt>:offset</tt>:: An integer. Only affects the polymorphic association.
224
- <tt>:namespace</tt>:: A symbol. Prepended to all the models in the <tt>:from</tt> and <tt>:through</tt> keys. This is especially useful for Camping, which namespaces models by default.
225
182
  <tt>:uniq</tt>:: If <tt>true</tt>, the records returned are passed through a pure-Ruby <tt>uniq</tt> before they are returned. Rarely needed.
226
- <tt>:foreign_key</tt>:: The column name for the parent's id in the join.
227
- <tt>:foreign_type_key</tt>:: The column name for the parent's class name in the join, if the parent itself is polymorphic. Rarely needed--if you're thinking about using this, you almost certainly want to use <tt>acts_as_double_polymorphic_join()</tt> instead.
228
- <tt>:polymorphic_key</tt>:: The column name for the child's id in the join.
229
- <tt>:polymorphic_type_key</tt>:: The column name for the child's class name in the join.
230
183
 
231
184
  If you pass a block, it gets converted to a Proc and added to <tt>:extend</tt>.
232
185
 
233
- == On condition nullification
234
-
235
- When you request an individual association, non-applicable but fully-qualified fields in the polymorphic association's <tt>:conditions</tt>, <tt>:order</tt>, and <tt>:group</tt> options get changed to <tt>NULL</tt>. For example, if you set <tt>:conditions => "dogs.name != 'Spot'"</tt>, when you request <tt>.cats</tt>, the conditions string is changed to <tt>NULL != 'Spot'</tt>.
236
-
237
- Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQL's 3-value logic. Instead, you need to use the <tt>:conditions</tt> string <tt>"dogs.name IS NULL OR dogs.name != 'Spot'"</tt> to get the behavior you probably expect for negative matches.
238
-
239
186
  =end
240
187
 
241
188
  def has_many_polymorphs (association_id, options = {}, &extension)
242
- _logger_debug "associating #{self}.#{association_id}"
189
+ _logger_debug "has_many_polymorphs: associating #{self}.#{association_id}"
243
190
  reflection = create_has_many_polymorphs_reflection(association_id, options, &extension)
244
191
  # puts "Created reflection #{reflection.inspect}"
245
192
  # configure_dependency_for_has_many(reflection)
@@ -272,8 +219,6 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
272
219
  :select, # applies to the polymorphic relationship
273
220
  :conditions, # applies to the polymorphic relationship, the children, and the join
274
221
  # :include,
275
- :parent_conditions,
276
- :parent_order,
277
222
  :order, # applies to the polymorphic relationship, the children, and the join
278
223
  :group, # only applies to the polymorphic relationship and the children
279
224
  :limit, # only applies to the polymorphic relationship and the children
@@ -283,7 +228,6 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
283
228
  :parent_limit,
284
229
  :parent_offset,
285
230
  # :source,
286
- :namespace,
287
231
  :uniq, # XXX untested, only applies to the polymorphic relationship
288
232
  # :finder_sql,
289
233
  # :counter_sql,
@@ -298,13 +242,13 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
298
242
  raise PolymorphicError, ":from option must be an array" unless options[:from].is_a? Array
299
243
  options[:from].each{|plural| verify_pluralization_of(plural)}
300
244
 
301
- options[:as] ||= self.name.demodulize.underscore.to_sym
245
+ options[:as] ||= self.name.demodulize.downcase.to_sym
302
246
  options[:conflicts] = Array(options[:conflicts])
303
247
  options[:foreign_key] ||= "#{options[:as]}_id"
304
248
 
305
249
  options[:association_foreign_key] =
306
250
  options[:polymorphic_key] ||= "#{association_id._singularize}_id"
307
- options[:polymorphic_type_key] ||= "#{association_id._singularize}_type"
251
+ options[:polymorphic_type_key] ||= "#{association_id._singularize}_type"
308
252
 
309
253
  if options.has_key? :ignore_duplicates
310
254
  _logger_warn "DEPRECATION WARNING: please use :skip_duplicates instead of :ignore_duplicates"
@@ -314,20 +258,9 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
314
258
  options[:dependent] = :destroy unless options.has_key? :dependent
315
259
  options[:conditions] = sanitize_sql(options[:conditions])
316
260
 
317
- # options[:finder_sql] ||= "(options[:polymorphic_key]
318
-
319
- options[:through] ||= build_join_table_symbol(association_id, (options[:as]._pluralize or self.table_name))
320
-
321
- # set up namespaces if we have a namespace key
322
- # XXX needs test coverage
323
- if options[:namespace]
324
- namespace = options[:namespace].to_s.chomp("/") + "/"
325
- options[:from].map! do |child|
326
- "#{namespace}#{child}".to_sym
327
- end
328
- options[:through] = "#{namespace}#{options[:through]}".to_sym
329
- end
330
-
261
+ # options[:finder_sql] ||= "(options[:polymorphic_key]
262
+
263
+ options[:through] ||= build_join_table_symbol((options[:as]._pluralize or self.table_name), association_id)
331
264
  options[:join_class_name] ||= options[:through]._classify
332
265
  options[:table_aliases] ||= build_table_aliases([options[:through]] + options[:from])
333
266
  options[:select] ||= build_select(association_id, options[:table_aliases])
@@ -340,7 +273,11 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
340
273
  options[:parent_extend] = spiked_create_extension_module(association_id, Array(options[:parent_extend]), "Parent")
341
274
 
342
275
  # create the reflection object
343
- returning(create_reflection(:has_many_polymorphs, association_id, options, self)) do |reflection|
276
+ returning(create_reflection(:has_many_polymorphs, association_id, options, self)) do |reflection|
277
+ if defined? Dependencies and RAILS_ENV == "development"
278
+ inject_dependencies(association_id, reflection) if Dependencies.mechanism == :load
279
+ end
280
+
344
281
  # set up the other related associations
345
282
  create_join_association(association_id, reflection)
346
283
  create_has_many_through_associations_for_parent_to_children(association_id, reflection)
@@ -357,17 +294,9 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
357
294
  # for the targets
358
295
  returning({}) do |aliases|
359
296
  from.map(&:to_s).sort.map(&:to_sym).each_with_index do |plural, t_index|
360
- begin
361
- table = plural._as_class.table_name
362
- rescue NameError => e
363
- raise PolymorphicError, "Could not find a valid class for #{plural.inspect} (tried #{plural.to_s._classify}). If it's namespaced, be sure to specify it as :\"module/#{plural}\" instead."
364
- end
365
- begin
366
- plural._as_class.columns.map(&:name).each_with_index do |field, f_index|
367
- aliases["#{table}.#{field}"] = "t#{t_index}_r#{f_index}"
368
- end
369
- rescue ActiveRecord::StatementInvalid => e
370
- _logger_warn "Looks like your table doesn't exist for #{plural.to_s._classify}.\nError #{e}\nSkipping..."
297
+ table = plural._as_class.table_name
298
+ plural._as_class.columns.map(&:name).each_with_index do |field, f_index|
299
+ aliases["#{table}.#{field}"] = "t#{t_index}_r#{f_index}"
371
300
  end
372
301
  end
373
302
  end
@@ -381,37 +310,43 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
381
310
  "#{table} AS #{_alias}"
382
311
  end.sort).join(", ")
383
312
  end
384
-
313
+
314
+ # model caching
315
+ def inject_dependencies(association_id, reflection)
316
+ _logger_debug "has_many_polymorphs: injecting dependencies"
317
+ requirements = [self, reflection.klass].map{|klass| [klass, klass.base_class]}.flatten.uniq
318
+ (all_classes_for(association_id, reflection) - requirements).each do |target_klass|
319
+ Dependencies.inject_dependency(target_klass, *requirements)
320
+ end
321
+ end
322
+
385
323
  # method sub-builders
386
324
 
387
325
  def create_join_association(association_id, reflection)
388
326
 
389
- options = {
390
- :foreign_key => reflection.options[:foreign_key],
327
+ options = {:foreign_key => reflection.options[:foreign_key],
391
328
  :dependent => reflection.options[:dependent],
392
329
  :class_name => reflection.klass.name,
393
- :extend => reflection.options[:join_extend]
394
- # :limit => reflection.options[:limit],
395
- # :offset => reflection.options[:offset],
396
- # :order => devolve(association_id, reflection, reflection.options[:order], reflection.klass, true),
397
- # :conditions => devolve(association_id, reflection, reflection.options[:conditions], reflection.klass, true)
398
- }
330
+ :extend => reflection.options[:join_extend],
331
+ # :limit => reflection.options[:limit],
332
+ # :offset => reflection.options[:offset],
333
+ :order => devolve(association_id, reflection, reflection.options[:order], reflection.klass),
334
+ :conditions => devolve(association_id, reflection, reflection.options[:conditions], reflection.klass)
335
+ }
399
336
 
400
337
  if reflection.options[:foreign_type_key]
401
- type_check = "#{reflection.options[:join_class_name].constantize.quoted_table_name}.#{reflection.options[:foreign_type_key]} = #{quote_value(self.base_class.name)}"
338
+ type_check = "#{reflection.options[:foreign_type_key]} = #{quote_value(self.base_class.name)}"
402
339
  conjunction = options[:conditions] ? " AND " : nil
403
340
  options[:conditions] = "#{options[:conditions]}#{conjunction}#{type_check}"
404
- options[:as] = reflection.options[:as]
405
341
  end
406
-
407
- has_many(reflection.options[:through], options)
408
-
342
+
343
+ has_many(reflection.options[:through], options)
409
344
  inject_before_save_into_join_table(association_id, reflection)
410
345
  end
411
346
 
412
347
  def inject_before_save_into_join_table(association_id, reflection)
413
348
  sti_hook = "sti_class_rewrite"
414
- rewrite_procedure = %[self.send(:#{reflection.options[:polymorphic_type_key]}=, self.#{reflection.options[:polymorphic_type_key]}.constantize.base_class.name)]
349
+ rewrite_procedure = %[self.send(:#{association_id._singularize}_type=, self.#{association_id._singularize}_type.constantize.base_class.name)]
415
350
 
416
351
  # XXX should be abstracted?
417
352
  reflection.klass.class_eval %[
@@ -452,34 +387,27 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
452
387
  through = "#{reflection.options[:through]}#{'_as_child' if parent == self}".to_sym
453
388
  has_many(through,
454
389
  :as => association_id._singularize,
455
- # :source => association_id._singularize,
456
- # :source_type => reflection.options[:polymorphic_type_key],
457
390
  :class_name => reflection.klass.name,
458
391
  :dependent => reflection.options[:dependent],
459
392
  :extend => reflection.options[:join_extend],
460
393
  # :limit => reflection.options[:limit],
461
394
  # :offset => reflection.options[:offset],
462
- :order => devolve(association_id, reflection, reflection.options[:parent_order], reflection.klass),
463
- :conditions => devolve(association_id, reflection, reflection.options[:parent_conditions], reflection.klass)
395
+ :order => devolve(association_id, reflection, reflection.options[:order], reflection.klass),
396
+ :conditions => devolve(association_id, reflection, reflection.options[:conditions], reflection.klass)
464
397
  )
465
398
 
466
- # the association to the target's parents
399
+ # the association to the collection parents
467
400
  association = "#{reflection.options[:as]._pluralize}#{"_of_#{association_id}" if reflection.options[:rename_individual_collections]}".to_sym
468
401
  has_many(association,
469
402
  :through => through,
470
403
  :class_name => parent.name,
471
404
  :source => reflection.options[:as],
472
- :foreign_key => reflection.options[:foreign_key],
405
+ :foreign_key => reflection.options[:foreign_key] ,
473
406
  :extend => reflection.options[:parent_extend],
474
- :conditions => reflection.options[:parent_conditions],
475
407
  :order => reflection.options[:parent_order],
476
408
  :offset => reflection.options[:parent_offset],
477
409
  :limit => reflection.options[:parent_limit],
478
410
  :group => reflection.options[:parent_group])
479
-
480
- # debugger if association == :parents
481
- #
482
- # nil
483
411
 
484
412
  end
485
413
  end
@@ -524,8 +452,8 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
524
452
  end
525
453
  end
526
454
 
527
- # some support methods
528
-
455
+ # some support methods
456
+
529
457
  def child_pluralization_map(association_id, reflection)
530
458
  Hash[*reflection.options[:from].map do |plural|
531
459
  [plural, plural._singularize]
@@ -542,8 +470,8 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
542
470
  s.to_s.gsub('/', '_').to_sym
543
471
  end
544
472
 
545
- def build_join_table_symbol(association_id, name)
546
- [name.to_s, association_id.to_s].sort.join("_").to_sym
473
+ def build_join_table_symbol(a, b)
474
+ [a.to_s, b.to_s].sort.join("_").to_sym
547
475
  end
548
476
 
549
477
  def all_classes_for(association_id, reflection)
@@ -552,25 +480,18 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
552
480
  klasses.uniq
553
481
  end
554
482
 
555
- def devolve(association_id, reflection, string, klass, remove_inappropriate_clauses = false)
556
- # XXX remove_inappropriate_clauses is not implemented; we'll wait until someone actually needs it
483
+ def devolve(association_id, reflection, string, klass)
557
484
  return unless string
558
- string = string.dup
559
- # _logger_debug "devolving #{string} for #{klass}"
560
- inappropriate_classes = (all_classes_for(association_id, reflection) - # the join class must always be preserved
561
- [klass, klass.base_class, reflection.klass, reflection.klass.base_class])
562
- inappropriate_classes.map do |klass|
485
+ (all_classes_for(association_id, reflection) - # the join class must always be preserved
486
+ [klass, klass.base_class, reflection.klass, reflection.klass.base_class]).map do |klass|
563
487
  klass.columns.map do |column|
564
488
  [klass.table_name, column.name]
565
489
  end.map do |table, column|
566
490
  ["#{table}.#{column}", "`#{table}`.#{column}", "#{table}.`#{column}`", "`#{table}`.`#{column}`"]
567
491
  end
568
492
  end.flatten.sort_by(&:size).reverse.each do |quoted_reference|
569
- # _logger_debug "devolved #{quoted_reference} to NULL"
570
- # XXX clause removal would go here
571
493
  string.gsub!(quoted_reference, "NULL")
572
494
  end
573
- # _logger_debug "altered to #{string}"
574
495
  string
575
496
  end
576
497