pluginaweek-polymorphic_identity 0.1.0

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.
@@ -0,0 +1,29 @@
1
+ == master
2
+
3
+ == 0.1.0 / 2008-12-14
4
+
5
+ * Remove the PluginAWeek namespace
6
+
7
+ == 0.0.5 / 2008-06-22
8
+
9
+ * Remove log files from gems
10
+
11
+ == 0.0.4 / 2008-05-05
12
+
13
+ * Updated documentation
14
+
15
+ == 0.0.3 / 2007-09-26
16
+
17
+ * Move test fixtures out of the test application root directory
18
+ * Remove gem dependency on activerecord
19
+
20
+ == 0.0.2 / 2007-08-05
21
+
22
+ * Add api documentation
23
+ * Fix Rakefile syntax errors
24
+ * Refactor tests
25
+ * Use the plugin_test_helper plugin for helping create a Rails environment
26
+
27
+ == 0.0.1 / 2007-02-12
28
+
29
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-2009 Aaron Pfeifer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,76 @@
1
+ = polymorphic_identity
2
+
3
+ +polymorphic_identity+ dynamically generates aliases for polymorphic associations
4
+ based on the class names of those associations.
5
+
6
+ == Resources
7
+
8
+ API
9
+
10
+ * http://api.pluginaweek.org/polymorphic_identity
11
+
12
+ Bugs
13
+
14
+ * http://pluginaweek.lighthouseapp.com/projects/13285-polymorphic_identity
15
+
16
+ Development
17
+
18
+ * http://github.com/pluginaweek/polymorphic_identity
19
+
20
+ Source
21
+
22
+ * git://github.com/pluginaweek/polymorphic_identity.git
23
+
24
+ == Description
25
+
26
+ Polymorphic associations are not very descriptive when it comes to easily
27
+ knowing the type of model your interacting with. For example, a typical
28
+ polymorphic assocation looks like the following:
29
+
30
+ class Tag < ActiveRecord::Base
31
+ belongs_to :taggable, :polymorphic => true
32
+ end
33
+
34
+ When getting the taggable record, you would normally have to call
35
+ <tt>tag.taggable</tt>. However, if you know that the taggable record is just an
36
+ instance of the Article model, then it would feel more comfortable if you could
37
+ just call <tt>tag.article</tt>. polymoprhic_identity makes this possible by
38
+ dynamically checking the name of the polymorphic record's class and creating
39
+ methods that allow you to access the polymorphic association based on that
40
+ class name.
41
+
42
+ == Usage
43
+
44
+ === Example
45
+
46
+ class Comment < ActiveRecord::Base
47
+ belongs_to :commentable, :polymorphic => true
48
+ belongs_to :commenter, :polymorphic => true
49
+ end
50
+
51
+ class Article < ActiveRecord::Base
52
+ has_many :comments, :as => :commentable
53
+ end
54
+
55
+ class User < ActiveRecord::Base
56
+ has_many :comments, :as => :commenter
57
+ end
58
+
59
+ c = Comment.find(1) # => #<Tag id: 1, commentable_id: 1, commentable_type: "Article", commenter_id: 1, commenter_type: "User"}>
60
+ c.commentable # => #<Article id: 1>
61
+ c.article # => #<Article id: 1>
62
+ c.commenter # => #<User id: 1>
63
+ c.user # => #<User id: 1>
64
+
65
+ == Testing
66
+
67
+ Before you can run any tests, the following gem must be installed:
68
+ * plugin_test_helper[http://github.com/pluginaweek/plugin_test_helper]
69
+
70
+ To run against a specific version of Rails:
71
+
72
+ rake test RAILS_FRAMEWORK_ROOT=/path/to/rails
73
+
74
+ == Dependencies
75
+
76
+ * Rails 2.0 or later
@@ -0,0 +1,96 @@
1
+ require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/contrib/sshpublisher'
5
+
6
+ spec = Gem::Specification.new do |s|
7
+ s.name = 'polymorphic_identity'
8
+ s.version = '0.1.0'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'Dynamically generates aliases for polymorphic ActiveRecord associations based on their class names'
11
+ s.description = s.summary
12
+
13
+ s.files = FileList['{lib,test}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc) - FileList['test/app_root/{log,log/*,script,script/*}']
14
+ s.require_path = 'lib'
15
+ s.has_rdoc = true
16
+ s.test_files = Dir['test/**/*_test.rb']
17
+
18
+ s.author = 'Aaron Pfeifer'
19
+ s.email = 'aaron@pluginaweek.org'
20
+ s.homepage = 'http://www.pluginaweek.org'
21
+ s.rubyforge_project = 'pluginaweek'
22
+ end
23
+
24
+ desc 'Default: run all tests.'
25
+ task :default => :test
26
+
27
+ desc "Test the #{spec.name} plugin."
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.libs << 'lib'
30
+ t.test_files = spec.test_files
31
+ t.verbose = true
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ namespace :test do
37
+ desc "Test the #{spec.name} plugin with Rcov."
38
+ Rcov::RcovTask.new(:rcov) do |t|
39
+ t.libs << 'lib'
40
+ t.test_files = spec.test_files
41
+ t.rcov_opts << '--exclude="^(?!lib/)"'
42
+ t.verbose = true
43
+ end
44
+ end
45
+ rescue LoadError
46
+ end
47
+
48
+ desc "Generate documentation for the #{spec.name} plugin."
49
+ Rake::RDocTask.new(:rdoc) do |rdoc|
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = spec.name
52
+ rdoc.template = '../rdoc_template.rb'
53
+ rdoc.options << '--line-numbers' << '--inline-source'
54
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb')
55
+ end
56
+
57
+ desc 'Generate a gemspec file.'
58
+ task :gemspec do
59
+ File.open("#{spec.name}.gemspec", 'w') do |f|
60
+ f.write spec.to_ruby
61
+ end
62
+ end
63
+
64
+ Rake::GemPackageTask.new(spec) do |p|
65
+ p.gem_spec = spec
66
+ p.need_tar = true
67
+ p.need_zip = true
68
+ end
69
+
70
+ desc 'Publish the beta gem.'
71
+ task :pgem => [:package] do
72
+ Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{spec.name}-#{spec.version}.gem").upload
73
+ end
74
+
75
+ desc 'Publish the API documentation.'
76
+ task :pdoc => [:rdoc] do
77
+ Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{spec.name}", 'rdoc').upload
78
+ end
79
+
80
+ desc 'Publish the API docs and gem'
81
+ task :publish => [:pgem, :pdoc, :release]
82
+
83
+ desc 'Publish the release files to RubyForge.'
84
+ task :release => [:gem, :package] do
85
+ require 'rubyforge'
86
+
87
+ ruby_forge = RubyForge.new.configure
88
+ ruby_forge.login
89
+
90
+ %w(gem tgz zip).each do |ext|
91
+ file = "pkg/#{spec.name}-#{spec.version}.#{ext}"
92
+ puts "Releasing #{File.basename(file)}..."
93
+
94
+ ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
95
+ end
96
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'polymorphic_identity'
@@ -0,0 +1,52 @@
1
+ # Adds dynamic attributes for polymorphic associations based on the name of
2
+ # the class for the polymorphic record. For example,
3
+ #
4
+ # class Tag < ActiveRecord::Base
5
+ # belongs_to :taggable, :polymorphic => true
6
+ # end
7
+ #
8
+ # class Article < ActiveRecord::Base
9
+ # has_many :tags, :as => :taggable
10
+ # end
11
+ #
12
+ # t = Tag.find(1) # => #<Tag id: 1, taggable_id: 1, taggable_type: "Article">
13
+ # t.taggable # => #<Article id: 1>
14
+ # t.article # => #<Article id: 1>
15
+ module PolymorphicIdentity
16
+ def self.included(base) #:nodoc:
17
+ base.class_eval do
18
+ alias_method_chain :method_missing, :polymorphic_identity
19
+ alias_method_chain :respond_to?, :polymorphic_identity
20
+ end
21
+ end
22
+
23
+ def method_missing_with_polymorphic_identity(method_id, *args, &block) #:nodoc:
24
+ if association_name = find_polymorphic_association_name(method_id)
25
+ send(association_name, *args, &block)
26
+ else
27
+ method_missing_without_polymorphic_identity(method_id, *args, &block)
28
+ end
29
+ end
30
+
31
+ # True if a polymorphic association can be found whose foreign type is set
32
+ # to the name of the method
33
+ def respond_to_with_polymorphic_identity?(method, include_priv = false) #:nodoc:
34
+ respond_to_without_polymorphic_identity?(method, include_priv) || !find_polymorphic_association_name(method).nil?
35
+ end
36
+
37
+ private
38
+ # Finds the name of the polymorphic association whose foreign type is set to
39
+ # the value specified.
40
+ def find_polymorphic_association_name(foreign_type_value)
41
+ foreign_type_value = foreign_type_value.to_s.camelize
42
+ reflection = self.class.reflections.values.find do |reflection|
43
+ reflection.options[:polymorphic] && self[reflection.options[:foreign_type]] == foreign_type_value
44
+ end
45
+
46
+ reflection ? reflection.name : nil
47
+ end
48
+ end
49
+
50
+ ActiveRecord::Base.class_eval do
51
+ include PolymorphicIdentity
52
+ end
@@ -0,0 +1,4 @@
1
+ class Article < ActiveRecord::Base
2
+ belongs_to :author
3
+ has_many :comments, :as => :commentable
4
+ end
@@ -0,0 +1,5 @@
1
+ class Author < ActiveRecord::Base
2
+ has_many :articles
3
+ has_many :pages
4
+ has_many :comments, :as => :commenter
5
+ end
@@ -0,0 +1,4 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :commentable, :polymorphic => true
3
+ belongs_to :commenter, :polymorphic => true
4
+ end
@@ -0,0 +1,4 @@
1
+ class Page < ActiveRecord::Base
2
+ belongs_to :author
3
+ has_many :comments, :as => :commentable
4
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ has_many :comments, :as => :commenter
3
+ end
@@ -0,0 +1,11 @@
1
+ class CreateAuthors < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :authors do |t|
4
+ t.string :name
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :authors
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class CreateArticles < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :articles do |t|
4
+ t.integer :author_id
5
+ t.text :content
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :articles
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ class CreatePages < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :pages do |t|
4
+ t.integer :author_id
5
+ t.text :content
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :pages
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :users do |t|
4
+ t.string :name
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :users
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ class CreateComments < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :comments do |t|
4
+ t.integer :commentable_id
5
+ t.string :commentable_type
6
+ t.string :commenter_id
7
+ t.string :commenter_type
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :comments
13
+ end
14
+ end
@@ -0,0 +1,66 @@
1
+ module Factory
2
+ # Build actions for the model
3
+ def self.build(model, &block)
4
+ name = model.to_s.underscore
5
+
6
+ define_method("#{name}_attributes", block)
7
+ define_method("valid_#{name}_attributes") {|*args| valid_attributes_for(model, *args)}
8
+ define_method("new_#{name}") {|*args| new_record(model, *args)}
9
+ define_method("create_#{name}") {|*args| create_record(model, *args)}
10
+ end
11
+
12
+ # Get valid attributes for the model
13
+ def valid_attributes_for(model, attributes = {})
14
+ name = model.to_s.underscore
15
+ send("#{name}_attributes", attributes)
16
+ attributes.stringify_keys!
17
+ attributes
18
+ end
19
+
20
+ # Build an unsaved record
21
+ def new_record(model, *args)
22
+ attributes = valid_attributes_for(model, *args)
23
+ record = model.new(attributes)
24
+ attributes.each {|attr, value| record.send("#{attr}=", value) if model.accessible_attributes && !model.accessible_attributes.include?(attr) || model.protected_attributes && model.protected_attributes.include?(attr)}
25
+ record
26
+ end
27
+
28
+ # Build and save/reload a record
29
+ def create_record(model, *args)
30
+ record = new_record(model, *args)
31
+ record.save!
32
+ record.reload
33
+ record
34
+ end
35
+
36
+ build Article do |attributes|
37
+ attributes[:author] = create_author unless attributes.include?(:author)
38
+ attributes.reverse_merge!(
39
+ :content => 'Thanks for visiting my blog!'
40
+ )
41
+ end
42
+
43
+ build Author do |attributes|
44
+ attributes.reverse_merge!(
45
+ :name => 'John Smith'
46
+ )
47
+ end
48
+
49
+ build Comment do |attributes|
50
+ attributes[:commentable] = create_article unless attributes.include?(:commentable)
51
+ attributes[:commenter] = create_user unless attributes.include?(:commenter)
52
+ end
53
+
54
+ build Page do |attributes|
55
+ attributes[:author] = create_author unless attributes.include?(:author)
56
+ attributes.reverse_merge!(
57
+ :content => 'Some information about me...'
58
+ )
59
+ end
60
+
61
+ build User do |attributes|
62
+ attributes.reverse_merge!(
63
+ :name => 'Mr. Bean'
64
+ )
65
+ end
66
+ end
@@ -0,0 +1,13 @@
1
+ # Load the plugin testing framework
2
+ $:.unshift("#{File.dirname(__FILE__)}/../../plugin_test_helper/lib")
3
+ require 'rubygems'
4
+ require 'plugin_test_helper'
5
+
6
+ # Run the migrations
7
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
8
+
9
+ # Mixin the factory helper
10
+ require File.expand_path("#{File.dirname(__FILE__)}/factory")
11
+ Test::Unit::TestCase.class_eval do
12
+ include Factory
13
+ end
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class PolymorphicIdentityTest < ActiveSupport::TestCase
4
+ def setup
5
+ @comment = Comment.new
6
+ @comment.commenter_type = 'Article'
7
+ end
8
+
9
+ def test_should_find_polymorphic_association_name_for_valid_symbolized_association
10
+ assert_equal :commenter, @comment.send(:find_polymorphic_association_name, :article)
11
+ end
12
+
13
+ def test_should_find_polymorphic_association_name_for_valid_stringified_association
14
+ assert_equal :commenter, @comment.send(:find_polymorphic_association_name, 'article')
15
+ end
16
+
17
+ def test_should_not_find_polymorphic_association_name_for_invalid_association
18
+ assert_equal nil, @comment.send(:find_polymorphic_association_name, 'page')
19
+ end
20
+ end
21
+
22
+ class PolymorphicAssociationWithNoValueTest < ActiveSupport::TestCase
23
+ def setup
24
+ @comment = create_comment(:commentable => nil, :commenter => nil)
25
+ end
26
+
27
+ def test_should_not_respond_to_polymorphic_association_name
28
+ assert !@comment.respond_to?(:article)
29
+ assert !@comment.respond_to?(:page)
30
+ assert !@comment.respond_to?(:author)
31
+ assert !@comment.respond_to?(:user)
32
+ end
33
+ end
34
+
35
+ class PolymorphicAssociationsWithValueTest < ActiveSupport::TestCase
36
+ def setup
37
+ @author = create_author
38
+ @article = create_article(:author => @author)
39
+ @comment = create_comment(:commentable => @article, :commenter => @author)
40
+ end
41
+
42
+ def test_should_respond_to_polymorphic_association_name_if_association_exists
43
+ assert @comment.respond_to?(:article)
44
+ assert @comment.respond_to?(:author)
45
+ assert_equal @article, @comment.article
46
+ assert_equal @author, @comment.author
47
+ end
48
+
49
+ def test_should_update_response_when_changing_polymorphic_association
50
+ page = create_page
51
+ user = create_user
52
+
53
+ @comment.commentable = page
54
+ @comment.commenter = user
55
+
56
+ assert !@comment.respond_to?(:article)
57
+ assert !@comment.respond_to?(:author)
58
+ assert @comment.respond_to?(:page)
59
+ assert @comment.respond_to?(:user)
60
+ assert_equal page, @comment.page
61
+ assert_equal user, @comment.user
62
+ end
63
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pluginaweek-polymorphic_identity
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Pfeifer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-08 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Dynamically generates aliases for polymorphic ActiveRecord associations based on their class names
17
+ email: aaron@pluginaweek.org
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/polymorphic_identity.rb
26
+ - test/unit
27
+ - test/unit/polymorphic_identity_test.rb
28
+ - test/factory.rb
29
+ - test/app_root
30
+ - test/app_root/app
31
+ - test/app_root/app/models
32
+ - test/app_root/app/models/comment.rb
33
+ - test/app_root/app/models/page.rb
34
+ - test/app_root/app/models/user.rb
35
+ - test/app_root/app/models/author.rb
36
+ - test/app_root/app/models/article.rb
37
+ - test/app_root/db
38
+ - test/app_root/db/migrate
39
+ - test/app_root/db/migrate/005_create_comments.rb
40
+ - test/app_root/db/migrate/004_create_users.rb
41
+ - test/app_root/db/migrate/001_create_authors.rb
42
+ - test/app_root/db/migrate/002_create_articles.rb
43
+ - test/app_root/db/migrate/003_create_pages.rb
44
+ - test/test_helper.rb
45
+ - CHANGELOG.rdoc
46
+ - init.rb
47
+ - LICENSE
48
+ - Rakefile
49
+ - README.rdoc
50
+ has_rdoc: true
51
+ homepage: http://www.pluginaweek.org
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project: pluginaweek
72
+ rubygems_version: 1.2.0
73
+ signing_key:
74
+ specification_version: 2
75
+ summary: Dynamically generates aliases for polymorphic ActiveRecord associations based on their class names
76
+ test_files:
77
+ - test/unit/polymorphic_identity_test.rb