diff --git a/.travis.yml b/.travis.yml index 8c326fa66..16ff2cfef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,7 @@ script: "cp spec/database.yml.sample spec/database.yml && bundle install && bundle exec rake" rvm: - - 1.8.7 - - ree - 1.9.2 - - rbx + - 1.9.3 env: - DB=sqlite3 - DB=mysql diff --git a/acts-as-taggable-on.gemspec b/acts-as-taggable-on.gemspec index 1acb829db..a21b0e7bf 100644 --- a/acts-as-taggable-on.gemspec +++ b/acts-as-taggable-on.gemspec @@ -4,16 +4,16 @@ require 'acts-as-taggable-on/version' Gem::Specification.new do |gem| gem.name = %q{acts-as-taggable-on} gem.authors = ["Michael Bleigh"] - gem.date = %q{2010-05-19} + gem.date = %q{2011-09-26} gem.description = %q{With ActsAsTaggableOn, you can tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality.} gem.summary = "Advanced tagging for Rails." gem.email = %q{michael@intridea.com} gem.homepage = '' - gem.add_runtime_dependency 'rails' + gem.add_runtime_dependency 'rails', '~> 3.1' gem.add_development_dependency 'rspec', '~> 2.5' gem.add_development_dependency 'sqlite3' - gem.add_development_dependency 'mysql2', '< 0.3' + gem.add_development_dependency 'mysql2', '~> 0.3.7' gem.add_development_dependency 'pg' gem.add_development_dependency 'guard' gem.add_development_dependency 'guard-rspec' diff --git a/lib/acts-as-taggable-on.rb b/lib/acts-as-taggable-on.rb index abc567351..92ae3dfae 100644 --- a/lib/acts-as-taggable-on.rb +++ b/lib/acts-as-taggable-on.rb @@ -1,12 +1,9 @@ require "active_record" require "active_record/version" require "action_view" -RAILS_3 = ::ActiveRecord::VERSION::MAJOR >= 3 $LOAD_PATH.unshift(File.dirname(__FILE__)) -require "acts_as_taggable_on/compatibility/active_record_backports" unless RAILS_3 - require "acts_as_taggable_on/utils" require "acts_as_taggable_on/acts_as_taggable_on" @@ -16,7 +13,6 @@ require "acts_as_taggable_on/acts_as_taggable_on/ownership" require "acts_as_taggable_on/acts_as_taggable_on/related" -#require "acts_as_taggable_on/utils" require "acts_as_taggable_on/acts_as_tagger" require "acts_as_taggable_on/tag" require "acts_as_taggable_on/tag_list" diff --git a/lib/acts_as_taggable_on/acts_as_taggable_on.rb b/lib/acts_as_taggable_on/acts_as_taggable_on.rb index 56a0d794c..c24f1f49e 100644 --- a/lib/acts_as_taggable_on/acts_as_taggable_on.rb +++ b/lib/acts_as_taggable_on/acts_as_taggable_on.rb @@ -28,20 +28,11 @@ def acts_as_taggable_on(*tag_types) tag_types = tag_types.to_a.flatten.compact.map(&:to_sym) if taggable? - if RAILS_3 - self.tag_types = (self.tag_types + tag_types).uniq - else - write_inheritable_attribute(:tag_types, (self.tag_types + tag_types).uniq) - end + self.tag_types = (self.tag_types + tag_types).uniq else - if RAILS_3 class_attribute :tag_types self.tag_types = tag_types - else - write_inheritable_attribute(:tag_types, tag_types) - class_inheritable_reader(:tag_types) - end - + class_eval do has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging" has_many :base_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag" @@ -49,8 +40,8 @@ def acts_as_taggable_on(*tag_types) def self.taggable? true end - - include ActsAsTaggableOn::Utils + + include ActsAsTaggableOn::Utils include ActsAsTaggableOn::Taggable::Core include ActsAsTaggableOn::Taggable::Collection include ActsAsTaggableOn::Taggable::Cache diff --git a/lib/acts_as_taggable_on/tag.rb b/lib/acts_as_taggable_on/tag.rb index 132860a93..ace859e2b 100644 --- a/lib/acts_as_taggable_on/tag.rb +++ b/lib/acts_as_taggable_on/tag.rb @@ -1,8 +1,7 @@ module ActsAsTaggableOn class Tag < ::ActiveRecord::Base - include ActsAsTaggableOn::ActiveRecord::Backports if ::ActiveRecord::VERSION::MAJOR < 3 include ActsAsTaggableOn::Utils - + attr_accessible :name ### ASSOCIATIONS: @@ -15,15 +14,15 @@ class Tag < ::ActiveRecord::Base validates_uniqueness_of :name ### SCOPES: - + def self.named(name) where(["name #{like_operator} ?", escape_like(name)]) end - + def self.named_any(list) where(list.map { |tag| sanitize_sql(["name #{like_operator} ?", escape_like(tag.to_s)]) }.join(" OR ")) end - + def self.named_like(name) where(["name #{like_operator} ?", "%#{escape_like(name)}%"]) end @@ -44,7 +43,7 @@ def self.find_or_create_all_with_like_by_name(*list) return [] if list.empty? existing_tags = Tag.named_any(list).all - new_tag_names = list.reject do |name| + new_tag_names = list.reject do |name| name = comparable_name(name) existing_tags.any? { |tag| comparable_name(tag.name) == name } end @@ -66,13 +65,13 @@ def to_s def count read_attribute(:count).to_i end - + def safe_name name.gsub(/[^a-zA-Z0-9]/, '') end - + class << self - private + private def comparable_name(str) RUBY_VERSION >= "1.9" ? str.downcase : str.mb_chars.downcase end diff --git a/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb b/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb index 1c8cbcf4e..1213a35ab 100644 --- a/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +++ b/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb @@ -12,7 +12,7 @@ describe "Taggable Method Generation" do before(:each) do clean_database! - RAILS_3 ? TaggableModel.tag_types = [] : TaggableModel.write_inheritable_attribute(:tag_types, []) + TaggableModel.tag_types = [] TaggableModel.acts_as_taggable_on(:tags, :languages, :skills, :needs, :offerings) @taggable = TaggableModel.new(:name => "Bob Jones") end @@ -28,7 +28,7 @@ it "should create an instance attribute for tag types" do @taggable.should respond_to(:tag_types) end - + it "should have all tag types" do @taggable.tag_types.should == [:tags, :languages, :skills, :needs, :offerings] end @@ -45,7 +45,7 @@ @taggable.should respond_to(:tag_list, :skill_list, :language_list) @taggable.should respond_to(:tag_list=, :skill_list=, :language_list=) end - + it "should generate a tag_list accessor, that includes owned tags, for each tag type" do @taggable.should respond_to(:all_tags_list, :all_skills_list, :all_languages_list) end @@ -57,17 +57,17 @@ @inherited_same = InheritingTaggableModel.new(:name => "inherited same") @inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different") end - + it "should pass on tag contexts to STI-inherited models" do @inherited_same.should respond_to(:tag_list, :skill_list, :language_list) @inherited_different.should respond_to(:tag_list, :skill_list, :language_list) end - + it "should have tag contexts added in altered STI models" do @inherited_different.should respond_to(:part_list) end end - + describe "Reloading" do it "should save a model instantiated by Model.find" do taggable = TaggableModel.create!(:name => "Taggable") @@ -81,66 +81,66 @@ taggable1 = TaggableModel.create!(:name => "Taggable 1") taggable2 = TaggableModel.create!(:name => "Taggable 2") taggable3 = TaggableModel.create!(:name => "Taggable 3") - + taggable1.tag_list = "one, two" taggable1.save - + taggable2.tag_list = "three, four" taggable2.save - + taggable3.tag_list = "one, four" taggable3.save - + taggable1.find_related_tags.should include(taggable3) taggable1.find_related_tags.should_not include(taggable2) end - + it "should find related objects based on tag names on context - non standard id" do taggable1 = NonStandardIdTaggableModel.create!(:name => "Taggable 1") taggable2 = NonStandardIdTaggableModel.create!(:name => "Taggable 2") taggable3 = NonStandardIdTaggableModel.create!(:name => "Taggable 3") - + taggable1.tag_list = "one, two" taggable1.save - + taggable2.tag_list = "three, four" taggable2.save - + taggable3.tag_list = "one, four" taggable3.save - + taggable1.find_related_tags.should include(taggable3) taggable1.find_related_tags.should_not include(taggable2) end - + it "should find other related objects based on tag names on context" do taggable1 = TaggableModel.create!(:name => "Taggable 1") taggable2 = OtherTaggableModel.create!(:name => "Taggable 2") taggable3 = OtherTaggableModel.create!(:name => "Taggable 3") - + taggable1.tag_list = "one, two" taggable1.save - + taggable2.tag_list = "three, four" taggable2.save - + taggable3.tag_list = "one, four" taggable3.save - + taggable1.find_related_tags_for(OtherTaggableModel).should include(taggable3) taggable1.find_related_tags_for(OtherTaggableModel).should_not include(taggable2) end - + it "should not include the object itself in the list of related objects" do taggable1 = TaggableModel.create!(:name => "Taggable 1") taggable2 = TaggableModel.create!(:name => "Taggable 2") - + taggable1.tag_list = "one" taggable1.save - + taggable2.tag_list = "one, two" taggable2.save - + taggable1.find_related_tags.should include(taggable2) taggable1.find_related_tags.should_not include(taggable1) end @@ -148,13 +148,13 @@ it "should not include the object itself in the list of related objects - non standard id" do taggable1 = NonStandardIdTaggableModel.create!(:name => "Taggable 1") taggable2 = NonStandardIdTaggableModel.create!(:name => "Taggable 2") - + taggable1.tag_list = "one" taggable1.save - + taggable2.tag_list = "one, two" taggable2.save - + taggable1.find_related_tags.should include(taggable2) taggable1.find_related_tags.should_not include(taggable1) end @@ -165,48 +165,48 @@ taggable1 = TaggableModel.create!(:name => "Taggable 1") taggable2 = TaggableModel.create!(:name => "Taggable 2") taggable3 = TaggableModel.create!(:name => "Taggable 3") - + taggable1.offering_list = "one, two" taggable1.save! - + taggable2.need_list = "one, two" taggable2.save! - + taggable3.offering_list = "one, two" taggable3.save! - + taggable1.find_matching_contexts(:offerings, :needs).should include(taggable2) taggable1.find_matching_contexts(:offerings, :needs).should_not include(taggable3) end - + it "should find other related objects with tags of matching contexts" do taggable1 = TaggableModel.create!(:name => "Taggable 1") taggable2 = OtherTaggableModel.create!(:name => "Taggable 2") taggable3 = OtherTaggableModel.create!(:name => "Taggable 3") - + taggable1.offering_list = "one, two" taggable1.save - + taggable2.need_list = "one, two" taggable2.save - + taggable3.offering_list = "one, two" taggable3.save - + taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should include(taggable2) taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should_not include(taggable3) end - + it "should not include the object itself in the list of related objects" do taggable1 = TaggableModel.create!(:name => "Taggable 1") taggable2 = TaggableModel.create!(:name => "Taggable 2") - + taggable1.tag_list = "one" taggable1.save - + taggable2.tag_list = "one, two" taggable2.save - + taggable1.find_related_tags.should include(taggable2) taggable1.find_related_tags.should_not include(taggable1) end @@ -240,67 +240,67 @@ }.should_not raise_error end end - + describe 'Caching' do before(:each) do - @taggable = CachedModel.new(:name => "Bob Jones") + @taggable = CachedModel.new(:name => "Bob Jones") @another_taggable = OtherCachedModel.new(:name => "John Smith") end - + it "should add saving of tag lists and cached tag lists to the instance" do @taggable.should respond_to(:save_cached_tag_list) @another_taggable.should respond_to(:save_cached_tag_list) - + @taggable.should respond_to(:save_tags) - end + end it "should add cached tag lists to the instance if cached column is not present" do TaggableModel.new(:name => "Art Kram").should_not respond_to(:save_cached_tag_list) end - + it "should generate a cached column checker for each tag type" do CachedModel.should respond_to(:caching_tag_list?) OtherCachedModel.should respond_to(:caching_language_list?) - end - + end + it 'should not have cached tags' do - @taggable.cached_tag_list.should be_blank - @another_taggable.cached_language_list.should be_blank + @taggable.cached_tag_list.should be_blank + @another_taggable.cached_language_list.should be_blank end - + it 'should cache tags' do @taggable.update_attributes(:tag_list => 'awesome, epic') @taggable.cached_tag_list.should == 'awesome, epic' - + @another_taggable.update_attributes(:language_list => 'ruby, .net') - @another_taggable.cached_language_list.should == 'ruby, .net' + @another_taggable.cached_language_list.should == 'ruby, .net' end - + it 'should keep the cache' do @taggable.update_attributes(:tag_list => 'awesome, epic') - @taggable = CachedModel.find(@taggable) + @taggable = CachedModel.find(@taggable) @taggable.save! - @taggable.cached_tag_list.should == 'awesome, epic' + @taggable.cached_tag_list.should == 'awesome, epic' end - + it 'should update the cache' do @taggable.update_attributes(:tag_list => 'awesome, epic') @taggable.update_attributes(:tag_list => 'awesome') - @taggable.cached_tag_list.should == 'awesome' + @taggable.cached_tag_list.should == 'awesome' end - + it 'should remove the cache' do @taggable.update_attributes(:tag_list => 'awesome, epic') @taggable.update_attributes(:tag_list => '') - @taggable.cached_tag_list.should be_blank + @taggable.cached_tag_list.should be_blank end - + it 'should have a tag list' do @taggable.update_attributes(:tag_list => 'awesome, epic') @taggable = CachedModel.find(@taggable.id) @taggable.tag_list.sort.should == %w(awesome epic).sort end - + it 'should keep the tag list' do @taggable.update_attributes(:tag_list => 'awesome, epic') @taggable = CachedModel.find(@taggable.id) @@ -353,12 +353,12 @@ end end end - - describe "taggings" do + + describe "taggings" do before(:each) do @taggable = TaggableModel.new(:name => "Art Kram") end - + it 'should return [] taggings' do @taggable.taggings.should == [] end diff --git a/spec/acts_as_taggable_on/utils_spec.rb b/spec/acts_as_taggable_on/utils_spec.rb index 5b6f067b1..34fc1a8ad 100644 --- a/spec/acts_as_taggable_on/utils_spec.rb +++ b/spec/acts_as_taggable_on/utils_spec.rb @@ -4,16 +4,15 @@ describe "like_operator" do before(:each) do clean_database! - TaggableModel.write_inheritable_attribute(:tag_types, []) TaggableModel.acts_as_taggable_on(:tags, :languages, :skills, :needs, :offerings) @taggable = TaggableModel.new(:name => "Bob Jones") end - + it "should return 'ILIKE' when the adapter is PostgreSQL" do TaggableModel.connection.stub(:adapter_name).and_return("PostgreSQL") TaggableModel.send(:like_operator).should == "ILIKE" end - + it "should return 'LIKE' when the adapter is not PostgreSQL" do TaggableModel.connection.stub(:adapter_name).and_return("MySQL") TaggableModel.send(:like_operator).should == "LIKE"