has_many_polymorphs 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.
- data/CHANGELOG +86 -0
- data/LICENSE +184 -0
- data/Manifest +173 -0
- data/README +205 -0
- data/Rakefile +28 -0
- data/TODO +2 -0
- data/examples/hmph.rb +69 -0
- data/generators/tagging/tagging_generator.rb +97 -0
- data/generators/tagging/templates/migration.rb +28 -0
- data/generators/tagging/templates/tag.rb +39 -0
- data/generators/tagging/templates/tag_test.rb +15 -0
- data/generators/tagging/templates/tagging.rb +16 -0
- data/generators/tagging/templates/tagging_extensions.rb +203 -0
- data/generators/tagging/templates/tagging_test.rb +85 -0
- data/generators/tagging/templates/taggings.yml +23 -0
- data/generators/tagging/templates/tags.yml +7 -0
- data/has_many_polymorphs.gemspec +36 -0
- data/init.rb +2 -0
- data/lib/has_many_polymorphs/association.rb +160 -0
- data/lib/has_many_polymorphs/autoload.rb +69 -0
- data/lib/has_many_polymorphs/base.rb +60 -0
- data/lib/has_many_polymorphs/class_methods.rb +600 -0
- data/lib/has_many_polymorphs/configuration.rb +19 -0
- data/lib/has_many_polymorphs/debugging_tools.rb +103 -0
- data/lib/has_many_polymorphs/rake_task_redefine_task.rb +35 -0
- data/lib/has_many_polymorphs/reflection.rb +58 -0
- data/lib/has_many_polymorphs/support_methods.rb +88 -0
- data/lib/has_many_polymorphs.rb +27 -0
- data/test/fixtures/bow_wows.yml +10 -0
- data/test/fixtures/cats.yml +18 -0
- data/test/fixtures/eaters_foodstuffs.yml +0 -0
- data/test/fixtures/fish.yml +12 -0
- data/test/fixtures/frogs.yml +5 -0
- data/test/fixtures/keep_your_enemies_close.yml +0 -0
- data/test/fixtures/little_whale_pupils.yml +0 -0
- data/test/fixtures/people.yml +7 -0
- data/test/fixtures/petfoods.yml +11 -0
- data/test/fixtures/whales.yml +5 -0
- data/test/fixtures/wild_boars.yml +10 -0
- data/test/generator/tagging_generator_test.rb +42 -0
- data/test/integration/app/README +182 -0
- data/test/integration/app/Rakefile +19 -0
- data/test/integration/app/app/controllers/application.rb +7 -0
- data/test/integration/app/app/controllers/bones_controller.rb +5 -0
- data/test/integration/app/app/helpers/addresses_helper.rb +2 -0
- data/test/integration/app/app/helpers/application_helper.rb +3 -0
- data/test/integration/app/app/helpers/bones_helper.rb +2 -0
- data/test/integration/app/app/helpers/sellers_helper.rb +28 -0
- data/test/integration/app/app/helpers/states_helper.rb +2 -0
- data/test/integration/app/app/helpers/users_helper.rb +2 -0
- data/test/integration/app/app/models/bone.rb +2 -0
- data/test/integration/app/app/models/double_sti_parent.rb +2 -0
- data/test/integration/app/app/models/double_sti_parent_relationship.rb +2 -0
- data/test/integration/app/app/models/organic_substance.rb +2 -0
- data/test/integration/app/app/models/single_sti_parent.rb +4 -0
- data/test/integration/app/app/models/single_sti_parent_relationship.rb +4 -0
- data/test/integration/app/app/models/stick.rb +2 -0
- data/test/integration/app/app/models/stone.rb +2 -0
- data/test/integration/app/app/views/addresses/edit.html.erb +12 -0
- data/test/integration/app/app/views/addresses/index.html.erb +18 -0
- data/test/integration/app/app/views/addresses/new.html.erb +11 -0
- data/test/integration/app/app/views/addresses/show.html.erb +3 -0
- data/test/integration/app/app/views/bones/index.rhtml +5 -0
- data/test/integration/app/app/views/layouts/addresses.html.erb +17 -0
- data/test/integration/app/app/views/layouts/sellers.html.erb +17 -0
- data/test/integration/app/app/views/layouts/states.html.erb +17 -0
- data/test/integration/app/app/views/layouts/users.html.erb +17 -0
- data/test/integration/app/app/views/sellers/edit.html.erb +12 -0
- data/test/integration/app/app/views/sellers/index.html.erb +20 -0
- data/test/integration/app/app/views/sellers/new.html.erb +11 -0
- data/test/integration/app/app/views/sellers/show.html.erb +3 -0
- data/test/integration/app/app/views/states/edit.html.erb +12 -0
- data/test/integration/app/app/views/states/index.html.erb +19 -0
- data/test/integration/app/app/views/states/new.html.erb +11 -0
- data/test/integration/app/app/views/states/show.html.erb +3 -0
- data/test/integration/app/app/views/users/edit.html.erb +12 -0
- data/test/integration/app/app/views/users/index.html.erb +22 -0
- data/test/integration/app/app/views/users/new.html.erb +11 -0
- data/test/integration/app/app/views/users/show.html.erb +3 -0
- data/test/integration/app/config/boot.rb +110 -0
- data/test/integration/app/config/database.yml +17 -0
- data/test/integration/app/config/environment.rb +19 -0
- data/test/integration/app/config/environment.rb.canonical +19 -0
- data/test/integration/app/config/environments/development.rb +9 -0
- data/test/integration/app/config/environments/production.rb +18 -0
- data/test/integration/app/config/environments/test.rb +19 -0
- data/test/integration/app/config/locomotive.yml +6 -0
- data/test/integration/app/config/routes.rb +33 -0
- data/test/integration/app/config/ultrasphinx/default.base +56 -0
- data/test/integration/app/config/ultrasphinx/development.conf.canonical +155 -0
- data/test/integration/app/db/migrate/001_create_sticks.rb +11 -0
- data/test/integration/app/db/migrate/002_create_stones.rb +11 -0
- data/test/integration/app/db/migrate/003_create_organic_substances.rb +11 -0
- data/test/integration/app/db/migrate/004_create_bones.rb +8 -0
- data/test/integration/app/db/migrate/005_create_single_sti_parents.rb +11 -0
- data/test/integration/app/db/migrate/006_create_double_sti_parents.rb +11 -0
- data/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb +13 -0
- data/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb +14 -0
- data/test/integration/app/db/migrate/009_create_library_model.rb +11 -0
- data/test/integration/app/doc/README_FOR_APP +2 -0
- data/test/integration/app/generators/commenting_generator_test.rb +83 -0
- data/test/integration/app/lib/library_model.rb +2 -0
- data/test/integration/app/public/404.html +30 -0
- data/test/integration/app/public/500.html +30 -0
- data/test/integration/app/public/dispatch.cgi +10 -0
- data/test/integration/app/public/dispatch.fcgi +24 -0
- data/test/integration/app/public/dispatch.rb +10 -0
- data/test/integration/app/public/favicon.ico +0 -0
- data/test/integration/app/public/images/rails.png +0 -0
- data/test/integration/app/public/index.html +277 -0
- data/test/integration/app/public/javascripts/application.js +2 -0
- data/test/integration/app/public/javascripts/controls.js +833 -0
- data/test/integration/app/public/javascripts/dragdrop.js +942 -0
- data/test/integration/app/public/javascripts/effects.js +1088 -0
- data/test/integration/app/public/javascripts/prototype.js +2515 -0
- data/test/integration/app/public/robots.txt +1 -0
- data/test/integration/app/public/stylesheets/scaffold.css +74 -0
- data/test/integration/app/script/about +3 -0
- data/test/integration/app/script/breakpointer +3 -0
- data/test/integration/app/script/console +3 -0
- data/test/integration/app/script/destroy +3 -0
- data/test/integration/app/script/generate +3 -0
- data/test/integration/app/script/performance/benchmarker +3 -0
- data/test/integration/app/script/performance/profiler +3 -0
- data/test/integration/app/script/plugin +3 -0
- data/test/integration/app/script/process/inspector +3 -0
- data/test/integration/app/script/process/reaper +3 -0
- data/test/integration/app/script/process/spawner +3 -0
- data/test/integration/app/script/runner +3 -0
- data/test/integration/app/script/server +3 -0
- data/test/integration/app/test/fixtures/double_sti_parent_relationships.yml +7 -0
- data/test/integration/app/test/fixtures/double_sti_parents.yml +7 -0
- data/test/integration/app/test/fixtures/organic_substances.yml +5 -0
- data/test/integration/app/test/fixtures/single_sti_parent_relationships.yml +7 -0
- data/test/integration/app/test/fixtures/single_sti_parents.yml +7 -0
- data/test/integration/app/test/fixtures/sticks.yml +7 -0
- data/test/integration/app/test/fixtures/stones.yml +7 -0
- data/test/integration/app/test/functional/addresses_controller_test.rb +57 -0
- data/test/integration/app/test/functional/bones_controller_test.rb +8 -0
- data/test/integration/app/test/functional/sellers_controller_test.rb +57 -0
- data/test/integration/app/test/functional/states_controller_test.rb +57 -0
- data/test/integration/app/test/functional/users_controller_test.rb +57 -0
- data/test/integration/app/test/test_helper.rb +8 -0
- data/test/integration/app/test/unit/bone_test.rb +8 -0
- data/test/integration/app/test/unit/double_sti_parent_relationship_test.rb +8 -0
- data/test/integration/app/test/unit/double_sti_parent_test.rb +8 -0
- data/test/integration/app/test/unit/organic_substance_test.rb +8 -0
- data/test/integration/app/test/unit/single_sti_parent_relationship_test.rb +8 -0
- data/test/integration/app/test/unit/single_sti_parent_test.rb +8 -0
- data/test/integration/app/test/unit/stick_test.rb +8 -0
- data/test/integration/app/test/unit/stone_test.rb +8 -0
- data/test/integration/server_test.rb +43 -0
- data/test/models/aquatic/fish.rb +5 -0
- data/test/models/aquatic/pupils_whale.rb +7 -0
- data/test/models/aquatic/whale.rb +15 -0
- data/test/models/beautiful_fight_relationship.rb +26 -0
- data/test/models/canine.rb +9 -0
- data/test/models/cat.rb +5 -0
- data/test/models/dog.rb +18 -0
- data/test/models/eaters_foodstuff.rb +8 -0
- data/test/models/frog.rb +4 -0
- data/test/models/kitten.rb +3 -0
- data/test/models/parentship.rb +4 -0
- data/test/models/person.rb +9 -0
- data/test/models/petfood.rb +39 -0
- data/test/models/tabby.rb +2 -0
- data/test/models/wild_boar.rb +3 -0
- data/test/modules/extension_module.rb +9 -0
- data/test/modules/other_extension_module.rb +9 -0
- data/test/patches/symlinked_plugins_1.2.6.diff +46 -0
- data/test/schema.rb +87 -0
- data/test/setup.rb +14 -0
- data/test/test_helper.rb +52 -0
- data/test/unit/has_many_polymorphs_test.rb +713 -0
- data.tar.gz.sig +1 -0
- metadata +279 -0
- metadata.gz.sig +0 -0
data/examples/hmph.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'camping'
|
|
2
|
+
require 'has_many_polymorphs'
|
|
3
|
+
|
|
4
|
+
Camping.goes :Hmph
|
|
5
|
+
|
|
6
|
+
module Hmph::Models
|
|
7
|
+
class GuestsKennel < Base
|
|
8
|
+
belongs_to :kennel
|
|
9
|
+
belongs_to :guest, :polymorphic => true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Dog < Base
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Cat < Base
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Bird < Base
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Kennel < Base
|
|
22
|
+
has_many_polymorphs :guests,
|
|
23
|
+
:from => [:dogs, :cats, :birds],
|
|
24
|
+
:through => :guests_kennels,
|
|
25
|
+
:namespace => :"hmph/models/"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class InitialSchema < V 1.0
|
|
29
|
+
def self.up
|
|
30
|
+
create_table :hmph_kennels do |t|
|
|
31
|
+
t.column :created_at, :datetime
|
|
32
|
+
t.column :modified_at, :datetime
|
|
33
|
+
t.column :name, :string, :default => 'Anonymous Kennel'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
create_table :hmph_guests_kennels do |t|
|
|
37
|
+
t.column :guest_id, :integer
|
|
38
|
+
t.column :guest_type, :string
|
|
39
|
+
t.column :kennel_id, :integer
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
create_table :hmph_dogs do |t|
|
|
43
|
+
t.column :name, :string, :default => 'Fido'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
create_table :hmph_cats do |t|
|
|
47
|
+
t.column :name, :string, :default => 'Morris'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
create_table :hmph_birds do |t|
|
|
51
|
+
t.column :name, :string, :default => 'Polly'
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.down
|
|
56
|
+
drop_table :hmph_kennels
|
|
57
|
+
drop_table :hmph_guests_kennels
|
|
58
|
+
drop_table :hmph_dogs
|
|
59
|
+
drop_table :hmph_cats
|
|
60
|
+
drop_table :hmph_birds
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
module Hmph::Controllers
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
module Hmph::Views
|
|
69
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require 'ruby-debug' and Debugger.start if ENV['USER'] == 'eweaver'
|
|
2
|
+
|
|
3
|
+
class TaggingGenerator < Rails::Generator::NamedBase
|
|
4
|
+
default_options :skip_migration => false
|
|
5
|
+
default_options :self_referential => false
|
|
6
|
+
attr_reader :parent_association_name
|
|
7
|
+
attr_reader :taggable_models
|
|
8
|
+
|
|
9
|
+
def initialize(runtime_args, runtime_options = {})
|
|
10
|
+
parse!(runtime_args, runtime_options)
|
|
11
|
+
|
|
12
|
+
@parent_association_name = (runtime_args.include?("--self-referential") ? "tagger" : "tag")
|
|
13
|
+
@taggable_models = runtime_args.reject{|opt| opt =~ /^--/}.map do |taggable|
|
|
14
|
+
":" + taggable.underscore.pluralize
|
|
15
|
+
end
|
|
16
|
+
@taggable_models += [":tags"] if runtime_args.include?("--self-referential")
|
|
17
|
+
@taggable_models.uniq!
|
|
18
|
+
|
|
19
|
+
verify @taggable_models
|
|
20
|
+
hacks
|
|
21
|
+
runtime_args.unshift("placeholder")
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def verify models
|
|
26
|
+
puts "** Warning: only one taggable model specified; tests may not run properly." if models.size < 2
|
|
27
|
+
models.each do |model|
|
|
28
|
+
model = model[1..-1].classify
|
|
29
|
+
next if model == "Tag" # don't load ourselves when --self-referential is used
|
|
30
|
+
self.class.const_get(model) rescue puts "** Error: model #{model[1..-1].classify} could not be loaded." or exit
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def hacks
|
|
35
|
+
# add the extension require in environment.rb
|
|
36
|
+
phrase = "require 'tagging_extensions'"
|
|
37
|
+
filename = "#{RAILS_ROOT}/config/environment.rb"
|
|
38
|
+
unless (open(filename) do |file|
|
|
39
|
+
file.grep(/#{Regexp.escape phrase}/).any?
|
|
40
|
+
end)
|
|
41
|
+
open(filename, 'a+') do |file|
|
|
42
|
+
file.puts "\n" + phrase + "\n"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def manifest
|
|
48
|
+
record do |m|
|
|
49
|
+
m.class_collisions class_path, class_name, "#{class_name}Test"
|
|
50
|
+
|
|
51
|
+
m.directory File.join('app/models', class_path)
|
|
52
|
+
m.directory File.join('test/unit', class_path)
|
|
53
|
+
m.directory File.join('test/fixtures', class_path)
|
|
54
|
+
m.directory File.join('test/fixtures', class_path)
|
|
55
|
+
m.directory File.join('lib')
|
|
56
|
+
|
|
57
|
+
m.template 'tag.rb', File.join('app/models', class_path, "tag.rb")
|
|
58
|
+
m.template 'tag_test.rb', File.join('test/unit', class_path, "tag_test.rb")
|
|
59
|
+
m.template 'tags.yml', File.join('test/fixtures', class_path, "tags.yml")
|
|
60
|
+
|
|
61
|
+
m.template 'tagging.rb', File.join('app/models', class_path, "tagging.rb")
|
|
62
|
+
m.template 'tagging_test.rb', File.join('test/unit', class_path, "tagging_test.rb")
|
|
63
|
+
m.template 'taggings.yml', File.join('test/fixtures', class_path, "taggings.yml")
|
|
64
|
+
|
|
65
|
+
m.template 'tagging_extensions.rb', File.join('lib', 'tagging_extensions.rb')
|
|
66
|
+
|
|
67
|
+
unless options[:skip_migration]
|
|
68
|
+
m.migration_template 'migration.rb', 'db/migrate',
|
|
69
|
+
:migration_file_name => "create_tags_and_taggings"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
protected
|
|
76
|
+
def banner
|
|
77
|
+
"Usage: #{$0} generate tagging [TaggableModelA TaggableModelB ...]"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def add_options!(opt)
|
|
81
|
+
opt.separator ''
|
|
82
|
+
opt.separator 'Options:'
|
|
83
|
+
opt.on("--skip-migration",
|
|
84
|
+
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
|
|
85
|
+
opt.on("--self-referential",
|
|
86
|
+
"Allow tags to tag themselves.") { |v| options[:self_referential] = v }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Useful for generating tests/fixtures
|
|
90
|
+
def model_one
|
|
91
|
+
taggable_models[0][1..-1].classify
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def model_two
|
|
95
|
+
taggable_models[1][1..-1].classify rescue model_one
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
# A migration to add tables for Tag and Tagging. This file is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs.
|
|
3
|
+
|
|
4
|
+
class CreateTagsAndTaggings < ActiveRecord::Migration
|
|
5
|
+
|
|
6
|
+
# Add the new tables.
|
|
7
|
+
def self.up
|
|
8
|
+
create_table :tags do |t|
|
|
9
|
+
t.column :name, :string, :null => false
|
|
10
|
+
end
|
|
11
|
+
add_index :tags, :name, :unique => true
|
|
12
|
+
|
|
13
|
+
create_table :taggings do |t|
|
|
14
|
+
t.column :<%= parent_association_name -%>_id, :integer, :null => false
|
|
15
|
+
t.column :taggable_id, :integer, :null => false
|
|
16
|
+
t.column :taggable_type, :string, :null => false
|
|
17
|
+
# t.column :position, :integer # Uncomment this if you need to use <tt>acts_as_list</tt>.
|
|
18
|
+
end
|
|
19
|
+
add_index :taggings, [:<%= parent_association_name -%>_id, :taggable_id, :taggable_type], :unique => true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Remove the tables.
|
|
23
|
+
def self.down
|
|
24
|
+
drop_table :tags
|
|
25
|
+
drop_table :taggings
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
# The Tag model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs.
|
|
3
|
+
|
|
4
|
+
class Tag < ActiveRecord::Base
|
|
5
|
+
|
|
6
|
+
DELIMITER = " " # Controls how to split and join tagnames from strings. You may need to change the <tt>validates_format_of parameters</tt> if you change this.
|
|
7
|
+
|
|
8
|
+
# If database speed becomes an issue, you could remove these validations and rescue the ActiveRecord database constraint errors instead.
|
|
9
|
+
validates_presence_of :name
|
|
10
|
+
validates_uniqueness_of :name, :case_sensitive => false
|
|
11
|
+
|
|
12
|
+
# Change this validation if you need more complex tag names.
|
|
13
|
+
validates_format_of :name, :with => /^[a-zA-Z0-9\_\-]+$/, :message => "can not contain special characters"
|
|
14
|
+
|
|
15
|
+
# Set up the polymorphic relationship.
|
|
16
|
+
has_many_polymorphs :taggables,
|
|
17
|
+
:from => [<%= taggable_models.join(", ") %>],
|
|
18
|
+
:through => :taggings,
|
|
19
|
+
:dependent => :destroy,
|
|
20
|
+
<% if options[:self_referential] -%> :as => :<%= parent_association_name -%>,
|
|
21
|
+
<% end -%>
|
|
22
|
+
:skip_duplicates => false,
|
|
23
|
+
:parent_extend => proc {
|
|
24
|
+
# Defined on the taggable models, not on Tag itself. Return the tagnames associated with this record as a string.
|
|
25
|
+
def to_s
|
|
26
|
+
self.map(&:name).sort.join(Tag::DELIMITER)
|
|
27
|
+
end
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Callback to strip extra spaces from the tagname before saving it. If you allow tags to be renamed later, you might want to use the <tt>before_save</tt> callback instead.
|
|
31
|
+
def before_create
|
|
32
|
+
self.name = name.downcase.strip.squeeze(" ")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if something goes wrong.
|
|
36
|
+
class Error < StandardError
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
|
2
|
+
|
|
3
|
+
class TagTest < ActiveSupport::TestCase
|
|
4
|
+
fixtures <%= taggable_models[0..1].join(", ") -%>
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
@obj = <%= model_two %>.find(:first)
|
|
8
|
+
@obj.tag_with "pale imperial"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_to_s
|
|
12
|
+
assert_equal "imperial pale", <%= model_two -%>.find(:first).tags.to_s
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
# The Tagging join model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs.
|
|
3
|
+
|
|
4
|
+
class Tagging < ActiveRecord::Base
|
|
5
|
+
|
|
6
|
+
belongs_to :<%= parent_association_name -%><%= ", :foreign_key => \"#{parent_association_name}_id\", :class_name => \"Tag\"" if options[:self_referential] %>
|
|
7
|
+
belongs_to :taggable, :polymorphic => true
|
|
8
|
+
|
|
9
|
+
# If you also need to use <tt>acts_as_list</tt>, you will have to manage the tagging positions manually by creating decorated join records when you associate Tags with taggables.
|
|
10
|
+
# acts_as_list :scope => :taggable
|
|
11
|
+
|
|
12
|
+
# This callback makes sure that an orphaned <tt>Tag</tt> is deleted if it no longer tags anything.
|
|
13
|
+
def after_destroy
|
|
14
|
+
<%= parent_association_name -%>.destroy_without_callbacks if <%= parent_association_name -%> and <%= parent_association_name -%>.taggings.count == 0
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
class ActiveRecord::Base #:nodoc:
|
|
2
|
+
|
|
3
|
+
# These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs.
|
|
4
|
+
module TaggingExtensions
|
|
5
|
+
|
|
6
|
+
# Add tags to <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags.
|
|
7
|
+
#
|
|
8
|
+
# We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores.
|
|
9
|
+
def _add_tags incoming
|
|
10
|
+
taggable?(true)
|
|
11
|
+
tag_cast_to_string(incoming).each do |tag_name|
|
|
12
|
+
begin
|
|
13
|
+
tag = Tag.find_or_create_by_name(tag_name)
|
|
14
|
+
raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record?
|
|
15
|
+
tags << tag
|
|
16
|
+
rescue ActiveRecord::StatementInvalid => e
|
|
17
|
+
raise unless e.to_s =~ /duplicate/i
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Removes tags from <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags.
|
|
23
|
+
def _remove_tags outgoing
|
|
24
|
+
taggable?(true)
|
|
25
|
+
outgoing = tag_cast_to_string(outgoing)
|
|
26
|
+
<% if options[:self_referential] %>
|
|
27
|
+
# because of http://dev.rubyonrails.org/ticket/6466
|
|
28
|
+
taggings.destroy(*(taggings.find(:all, :include => :<%= parent_association_name -%>).select do |tagging|
|
|
29
|
+
outgoing.include? tagging.<%= parent_association_name -%>.name
|
|
30
|
+
end))
|
|
31
|
+
<% else -%>
|
|
32
|
+
<%= parent_association_name -%>s.delete(*(<%= parent_association_name -%>s.select do |tag|
|
|
33
|
+
outgoing.include? tag.name
|
|
34
|
+
end))
|
|
35
|
+
<% end -%>
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns the tags on <tt>self</tt> as a string.
|
|
39
|
+
def tag_list
|
|
40
|
+
# Redefined later to avoid an RDoc parse error.
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Replace the existing tags on <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags.
|
|
44
|
+
def tag_with list
|
|
45
|
+
#:stopdoc:
|
|
46
|
+
taggable?(true)
|
|
47
|
+
list = tag_cast_to_string(list)
|
|
48
|
+
|
|
49
|
+
# Transactions may not be ideal for you here; be aware.
|
|
50
|
+
Tag.transaction do
|
|
51
|
+
current = <%= parent_association_name -%>s.map(&:name)
|
|
52
|
+
_add_tags(list - current)
|
|
53
|
+
_remove_tags(current - list)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
self
|
|
57
|
+
#:startdoc:
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Returns the tags on <tt>self</tt> as a string.
|
|
61
|
+
def tag_list #:nodoc:
|
|
62
|
+
#:stopdoc:
|
|
63
|
+
taggable?(true)
|
|
64
|
+
<%= parent_association_name -%>s.reload
|
|
65
|
+
<%= parent_association_name -%>s.to_s
|
|
66
|
+
#:startdoc:
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def tag_list=(value)
|
|
70
|
+
tag_with(value)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def tag_cast_to_string obj #:nodoc:
|
|
76
|
+
case obj
|
|
77
|
+
when Array
|
|
78
|
+
obj.map! do |item|
|
|
79
|
+
case item
|
|
80
|
+
when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot.
|
|
81
|
+
when Tag then item.name
|
|
82
|
+
when String then item
|
|
83
|
+
else
|
|
84
|
+
raise "Invalid type"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
when String
|
|
88
|
+
obj = obj.split(Tag::DELIMITER).map do |tag_name|
|
|
89
|
+
tag_name.strip.squeeze(" ")
|
|
90
|
+
end
|
|
91
|
+
else
|
|
92
|
+
raise "Invalid object of class #{obj.class} as tagging method parameter"
|
|
93
|
+
end.flatten.compact.map(&:downcase).uniq
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model.
|
|
97
|
+
def taggable?(should_raise = false) #:nodoc:
|
|
98
|
+
unless flag = respond_to?(:<%= parent_association_name -%>s)
|
|
99
|
+
raise "#{self.class} is not a taggable model" if should_raise
|
|
100
|
+
end
|
|
101
|
+
flag
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
module TaggingFinders
|
|
107
|
+
# Find all the objects tagged with the supplied list of tags
|
|
108
|
+
#
|
|
109
|
+
# Usage : Model.tagged_with("ruby")
|
|
110
|
+
# Model.tagged_with("hello", "world")
|
|
111
|
+
# Model.tagged_with("hello", "world", :limit => 10)
|
|
112
|
+
#
|
|
113
|
+
# XXX This query strategy is not performant, and needs to be rewritten as an inverted join or a series of unions
|
|
114
|
+
#
|
|
115
|
+
def tagged_with(*tag_list)
|
|
116
|
+
options = tag_list.last.is_a?(Hash) ? tag_list.pop : {}
|
|
117
|
+
tag_list = parse_tags(tag_list)
|
|
118
|
+
|
|
119
|
+
scope = scope(:find)
|
|
120
|
+
options[:select] ||= "#{table_name}.*"
|
|
121
|
+
options[:from] ||= "#{table_name}, tags, taggings"
|
|
122
|
+
|
|
123
|
+
sql = "SELECT #{(scope && scope[:select]) || options[:select]} "
|
|
124
|
+
sql << "FROM #{(scope && scope[:from]) || options[:from]} "
|
|
125
|
+
|
|
126
|
+
add_joins!(sql, options[:joins], scope)
|
|
127
|
+
|
|
128
|
+
sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id "
|
|
129
|
+
sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' "
|
|
130
|
+
sql << "AND taggings.tag_id = tags.id "
|
|
131
|
+
|
|
132
|
+
tag_list_condition = tag_list.map {|name| "'#{name}'"}.join(", ")
|
|
133
|
+
|
|
134
|
+
sql << "AND (tags.name IN (#{sanitize_sql(tag_list_condition)})) "
|
|
135
|
+
sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions]
|
|
136
|
+
|
|
137
|
+
columns = column_names.map do |column|
|
|
138
|
+
"#{table_name}.#{column}"
|
|
139
|
+
end.join(", ")
|
|
140
|
+
|
|
141
|
+
sql << "GROUP BY #{columns} "
|
|
142
|
+
sql << "HAVING COUNT(taggings.tag_id) = #{tag_list.size}"
|
|
143
|
+
|
|
144
|
+
add_order!(sql, options[:order], scope)
|
|
145
|
+
add_limit!(sql, options, scope)
|
|
146
|
+
add_lock!(sql, options, scope)
|
|
147
|
+
|
|
148
|
+
find_by_sql(sql)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def self.tagged_with_any(*tag_list)
|
|
152
|
+
options = tag_list.last.is_a?(Hash) ? tag_list.pop : {}
|
|
153
|
+
tag_list = parse_tags(tag_list)
|
|
154
|
+
|
|
155
|
+
scope = scope(:find)
|
|
156
|
+
options[:select] ||= "#{table_name}.*"
|
|
157
|
+
options[:from] ||= "#{table_name}, tags, taggings"
|
|
158
|
+
|
|
159
|
+
sql = "SELECT #{(scope && scope[:select]) || options[:select]} "
|
|
160
|
+
sql << "FROM #{(scope && scope[:from]) || options[:from]} "
|
|
161
|
+
|
|
162
|
+
add_joins!(sql, options, scope)
|
|
163
|
+
|
|
164
|
+
sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id "
|
|
165
|
+
sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' "
|
|
166
|
+
sql << "AND taggings.tag_id = tags.id "
|
|
167
|
+
|
|
168
|
+
sql << "AND ("
|
|
169
|
+
or_options = []
|
|
170
|
+
tag_list.each do |name|
|
|
171
|
+
or_options << "tags.name = '#{name}'"
|
|
172
|
+
end
|
|
173
|
+
or_options_joined = or_options.join(" OR ")
|
|
174
|
+
sql << "#{or_options_joined}) "
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions]
|
|
178
|
+
|
|
179
|
+
columns = column_names.map do |column|
|
|
180
|
+
"#{table_name}.#{column}"
|
|
181
|
+
end.join(", ")
|
|
182
|
+
|
|
183
|
+
sql << "GROUP BY #{columns} "
|
|
184
|
+
|
|
185
|
+
add_order!(sql, options[:order], scope)
|
|
186
|
+
add_limit!(sql, options, scope)
|
|
187
|
+
add_lock!(sql, options, scope)
|
|
188
|
+
|
|
189
|
+
find_by_sql(sql)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def parse_tags(tags)
|
|
193
|
+
return [] if tags.blank?
|
|
194
|
+
tags = Array(tags).first
|
|
195
|
+
tags = tags.respond_to?(:flatten) ? tags.flatten : tags.split(Tag::DELIMITER)
|
|
196
|
+
tags.map { |tag| tag.strip.squeeze(" ") }.flatten.compact.map(&:downcase).uniq
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
include TaggingExtensions
|
|
202
|
+
extend TaggingFinders
|
|
203
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
|
2
|
+
|
|
3
|
+
class TaggingTest < ActiveSupport::TestCase
|
|
4
|
+
fixtures :tags, :taggings, <%= taggable_models[0..1].join(", ") -%>
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
@objs = <%= model_two %>.find(:all, :limit => 2)
|
|
8
|
+
|
|
9
|
+
@obj1 = @objs[0]
|
|
10
|
+
@obj1.tag_with("pale")
|
|
11
|
+
@obj1.reload
|
|
12
|
+
|
|
13
|
+
@obj2 = @objs[1]
|
|
14
|
+
@obj2.tag_with("pale imperial")
|
|
15
|
+
@obj2.reload
|
|
16
|
+
|
|
17
|
+
<% if taggable_models.size > 1 -%>
|
|
18
|
+
@obj3 = <%= model_one -%>.find(:first)
|
|
19
|
+
<% end -%>
|
|
20
|
+
@tag1 = Tag.find(1)
|
|
21
|
+
@tag2 = Tag.find(2)
|
|
22
|
+
@tagging1 = Tagging.find(1)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_tag_with
|
|
26
|
+
@obj2.tag_with "hoppy pilsner"
|
|
27
|
+
assert_equal "hoppy pilsner", @obj2.tag_list
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_find_tagged_with
|
|
31
|
+
@obj1.tag_with "seasonal lager ipa"
|
|
32
|
+
@obj2.tag_with ["lager", "stout", "fruity", "seasonal"]
|
|
33
|
+
|
|
34
|
+
result1 = [@obj1]
|
|
35
|
+
assert_equal <%= model_two %>.tagged_with("ipa"), result1
|
|
36
|
+
assert_equal <%= model_two %>.tagged_with("ipa lager"), result1
|
|
37
|
+
assert_equal <%= model_two %>.tagged_with("ipa", "lager"), result1
|
|
38
|
+
|
|
39
|
+
result2 = [@obj1.id, @obj2.id].sort
|
|
40
|
+
assert_equal <%= model_two %>.tagged_with("seasonal").map(&:id).sort, result2
|
|
41
|
+
assert_equal <%= model_two %>.tagged_with("seasonal lager").map(&:id).sort, result2
|
|
42
|
+
assert_equal <%= model_two %>.tagged_with("seasonal", "lager").map(&:id).sort, result2
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
<% if options[:self_referential] -%>
|
|
46
|
+
def test_self_referential_tag_with
|
|
47
|
+
@tag1.tag_with [1, 2]
|
|
48
|
+
assert @tag1.tags.any? {|obj| obj == @tag1}
|
|
49
|
+
assert !@tag2.tags.any? {|obj| obj == @tag1}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
<% end -%>
|
|
53
|
+
def test__add_tags
|
|
54
|
+
@obj1._add_tags "porter longneck"
|
|
55
|
+
assert Tag.find_by_name("porter").taggables.any? {|obj| obj == @obj1}
|
|
56
|
+
assert Tag.find_by_name("longneck").taggables.any? {|obj| obj == @obj1}
|
|
57
|
+
assert_equal "longneck pale porter", @obj1.tag_list
|
|
58
|
+
|
|
59
|
+
@obj1._add_tags [2]
|
|
60
|
+
assert_equal "imperial longneck pale porter", @obj1.tag_list
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test__remove_tags
|
|
64
|
+
@obj2._remove_tags ["2", @tag1]
|
|
65
|
+
assert @obj2.tags.empty?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_tag_list
|
|
69
|
+
assert_equal "imperial pale", @obj2.tag_list
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_taggable
|
|
73
|
+
assert_raises(RuntimeError) do
|
|
74
|
+
@tagging1.send(:taggable?, true)
|
|
75
|
+
end
|
|
76
|
+
assert !@tagging1.send(:taggable?)
|
|
77
|
+
<% if taggable_models.size > 1 -%>
|
|
78
|
+
assert @obj3.send(:taggable?)
|
|
79
|
+
<% end -%>
|
|
80
|
+
<% if options[:self_referential] -%>
|
|
81
|
+
assert @tag1.send(:taggable?)
|
|
82
|
+
<% end -%>
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
<% if taggable_models.size > 1 -%>
|
|
3
|
+
taggings_003:
|
|
4
|
+
<%= parent_association_name -%>_id: "2"
|
|
5
|
+
id: "3"
|
|
6
|
+
taggable_type: <%= model_one %>
|
|
7
|
+
taggable_id: "1"
|
|
8
|
+
<% end -%>
|
|
9
|
+
taggings_004:
|
|
10
|
+
<%= parent_association_name -%>_id: "2"
|
|
11
|
+
id: "4"
|
|
12
|
+
taggable_type: <%= model_two %>
|
|
13
|
+
taggable_id: "2"
|
|
14
|
+
taggings_001:
|
|
15
|
+
<%= parent_association_name -%>_id: "1"
|
|
16
|
+
id: "1"
|
|
17
|
+
taggable_type: <%= model_two %>
|
|
18
|
+
taggable_id: "1"
|
|
19
|
+
taggings_002:
|
|
20
|
+
<%= parent_association_name -%>_id: "1"
|
|
21
|
+
id: "2"
|
|
22
|
+
taggable_type: <%= model_two %>
|
|
23
|
+
taggable_id: "2"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
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.}
|
|
12
|
+
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"]
|
|
18
|
+
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"]
|
|
23
|
+
|
|
24
|
+
if s.respond_to? :specification_version then
|
|
25
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
26
|
+
s.specification_version = 3
|
|
27
|
+
|
|
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
|
data/init.rb
ADDED