Skip to content

Commit

Permalink
mbleigh#80 added force_parameterize and force_lowercase. added setup
Browse files Browse the repository at this point in the history
  • Loading branch information
artemk committed Jan 8, 2012
1 parent bb7774f commit 7086b00
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 116 deletions.
13 changes: 10 additions & 3 deletions README.rdoc
Expand Up @@ -181,13 +181,20 @@ CSS:
.css3 { font-size: 1.4em; }
.css4 { font-size: 1.6em; }

== Remove unused tags
== Configuration

If you would like to remove unused tag objects after removing taggings, add

ActsAsTaggableOn::Tag.remove_unused = true
ActsAsTaggableOn.remove_unused_tags = true

If you want force tags to be saved downcased:

ActsAsTaggableOn.force_lowercase = true

If you want tags to be saved parametrized (you can redefine to_param as well):

ActsAsTaggableOn.force_parameterize = true

to initializer file.

== Contributors

Expand Down
2 changes: 1 addition & 1 deletion acts-as-taggable-on.gemspec
Expand Up @@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
gem.homepage = ''

gem.add_runtime_dependency 'rails', '~> 3.0'
gem.add_development_dependency 'rspec', '~> 2.5'
gem.add_development_dependency 'rspec', '~> 2.6'
gem.add_development_dependency 'ammeter', '~> 0.1.3'
gem.add_development_dependency 'sqlite3'
gem.add_development_dependency 'mysql2', '~> 0.3.7'
Expand Down
26 changes: 25 additions & 1 deletion lib/acts-as-taggable-on.rb
Expand Up @@ -6,6 +6,29 @@

$LOAD_PATH.unshift(File.dirname(__FILE__))

module ActsAsTaggableOn
mattr_accessor :delimiter
@@delimiter = ','

mattr_accessor :force_lowercase
@@force_lowercase = false

mattr_accessor :force_parameterize
@@force_parameterize = false

mattr_accessor :remove_unused_tags
self.remove_unused_tags = false

def self.glue
@@delimiter.ends_with?(" ") ? @@delimiter : "#{@@delimiter} "
end

def self.setup
yield self
end
end


require "acts_as_taggable_on/utils"

require "acts_as_taggable_on/taggable"
Expand All @@ -31,4 +54,5 @@

if defined?(ActionView::Base)
ActionView::Base.send :include, ActsAsTaggableOn::TagsHelper
end
end

3 changes: 0 additions & 3 deletions lib/acts_as_taggable_on/tag.rb
Expand Up @@ -2,9 +2,6 @@ module ActsAsTaggableOn
class Tag < ::ActiveRecord::Base
include ActsAsTaggableOn::Utils

cattr_accessor :remove_unused
self.remove_unused = false

attr_accessible :name

### ASSOCIATIONS:
Expand Down
25 changes: 13 additions & 12 deletions lib/acts_as_taggable_on/tag_list.rb
@@ -1,32 +1,30 @@
require 'active_support/core_ext/module/delegation'

module ActsAsTaggableOn
class TagList < Array
cattr_accessor :delimiter
self.delimiter = ','

attr_accessor :owner

def initialize(*args)
add(*args)
end

##
# Returns a new TagList using the given tag string.
#
# Example:
# tag_list = TagList.from("One , Two, Three")
# tag_list # ["One", "Two", "Three"]
def self.from(string)
glue = delimiter.ends_with?(" ") ? delimiter : "#{delimiter} "
string = string.join(glue) if string.respond_to?(:join)
string = string.join(ActsAsTaggableOn.glue) if string.respond_to?(:join)

new.tap do |tag_list|
string = string.to_s.dup

# Parse the quoted tags
string.gsub!(/(\A|#{delimiter})\s*"(.*?)"\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
string.gsub!(/(\A|#{delimiter})\s*'(.*?)'\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
string.gsub!(/(\A|#{ActsAsTaggableOn.delimiter})\s*"(.*?)"\s*(#{ActsAsTaggableOn.delimiter}\s*|\z)/) { tag_list << $2; $3 }
string.gsub!(/(\A|#{ActsAsTaggableOn.delimiter})\s*'(.*?)'\s*(#{ActsAsTaggableOn.delimiter}\s*|\z)/) { tag_list << $2; $3 }

tag_list.add(string.split(delimiter))
tag_list.add(string.split(ActsAsTaggableOn.delimiter))
end
end

Expand Down Expand Up @@ -69,16 +67,19 @@ def to_s
tags.send(:clean!)

tags.map do |name|
name.include?(delimiter) ? "\"#{name}\"" : name
end.join(delimiter.ends_with?(" ") ? delimiter : "#{delimiter} ")
name.include?(ActsAsTaggableOn.delimiter) ? "\"#{name}\"" : name
end.join(ActsAsTaggableOn.glue)
end

private

# Remove whitespace, duplicates, and blanks.
def clean!
reject!(&:blank?)
map!(&:strip)
map!(&:downcase) if ActsAsTaggableOn.force_lowercase
map!(&:parameterize) if ActsAsTaggableOn.force_parameterize

uniq!
end

Expand Down
2 changes: 1 addition & 1 deletion lib/acts_as_taggable_on/tagging.rb
Expand Up @@ -24,7 +24,7 @@ class Tagging < ::ActiveRecord::Base #:nodoc:
private

def remove_unused_tags
if Tag.remove_unused
if ActsAsTaggableOn.remove_unused_tags
if tag.taggings.count.zero?
tag.destroy
end
Expand Down
32 changes: 32 additions & 0 deletions spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb
Expand Up @@ -453,4 +453,36 @@
@taggable.taggings.should == []
end
end

describe "@@remove_unused_tags" do
before do
@taggable = TaggableModel.create(:name => "Bob Jones")
@tag = ActsAsTaggableOn::Tag.create(:name => "awesome")

@tagging = ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags')
end

context "if set to true" do
before do
ActsAsTaggableOn.remove_unused_tags = true
end

it "should remove unused tags after removing taggings" do
@tagging.destroy
ActsAsTaggableOn::Tag.find_by_name("awesome").should be_nil
end
end

context "if set to false" do
before do
ActsAsTaggableOn.remove_unused_tags = false
end

it "should not remove unused tags after removing taggings" do
@tagging.destroy
ActsAsTaggableOn::Tag.find_by_name("awesome").should == @tag
end
end
end

end
149 changes: 84 additions & 65 deletions spec/acts_as_taggable_on/tag_list_spec.rb
@@ -1,74 +1,93 @@
require File.expand_path('../../spec_helper', __FILE__)

describe ActsAsTaggableOn::TagList do
before(:each) do
@tag_list = ActsAsTaggableOn::TagList.new("awesome","radical")
end

it "should be an array" do
@tag_list.is_a?(Array).should be_true
end

it "should be able to be add a new tag word" do
@tag_list.add("cool")
@tag_list.include?("cool").should be_true
end

it "should be able to add delimited lists of words" do
@tag_list.add("cool, wicked", :parse => true)
@tag_list.include?("cool").should be_true
@tag_list.include?("wicked").should be_true
end

it "should be able to add delimited list of words with quoted delimiters" do
@tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
@tag_list.include?("cool, wicked").should be_true
@tag_list.include?("really cool, really wicked").should be_true
end

it "should be able to handle other uses of quotation marks correctly" do
@tag_list.add("john's cool car, mary's wicked toy", :parse => true)
@tag_list.include?("john's cool car").should be_true
@tag_list.include?("mary's wicked toy").should be_true
end

it "should be able to add an array of words" do
@tag_list.add(["cool", "wicked"], :parse => true)
@tag_list.include?("cool").should be_true
@tag_list.include?("wicked").should be_true
end

it "should be able to remove words" do
@tag_list.remove("awesome")
@tag_list.include?("awesome").should be_false
end

it "should be able to remove delimited lists of words" do
@tag_list.remove("awesome, radical", :parse => true)
@tag_list.should be_empty
end

it "should be able to remove an array of words" do
@tag_list.remove(["awesome", "radical"], :parse => true)
@tag_list.should be_empty
let(:tag_list) { ActsAsTaggableOn::TagList.new("awesome","radical") }

it { should be_kind_of Array }

it "#from should return empty array if empty array is passed" do
ActsAsTaggableOn::TagList.from([]).should be_empty
end

it "should give a delimited list of words when converted to string" do
@tag_list.to_s.should == "awesome, radical"

describe "#add" do
it "should be able to be add a new tag word" do
tag_list.add("cool")
tag_list.include?("cool").should be_true
end

it "should be able to add delimited lists of words" do
tag_list.add("cool, wicked", :parse => true)
tag_list.should include("cool", "wicked")
end

it "should be able to add delimited list of words with quoted delimiters" do
tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
tag_list.should include("cool, wicked", "really cool, really wicked")
end

it "should be able to handle other uses of quotation marks correctly" do
tag_list.add("john's cool car, mary's wicked toy", :parse => true)
tag_list.should include("john's cool car", "mary's wicked toy")
end

it "should be able to add an array of words" do
tag_list.add(["cool", "wicked"], :parse => true)
tag_list.should include("cool", "wicked")
end

it "should quote escape tags with commas in them" do
tag_list.add("cool","rad,bodacious")
tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
end

end

it "should quote escape tags with commas in them" do
@tag_list.add("cool","rad,bodacious")
@tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""

describe "#remove" do
it "should be able to remove words" do
tag_list.remove("awesome")
tag_list.should_not include("awesome")
end

it "should be able to remove delimited lists of words" do
tag_list.remove("awesome, radical", :parse => true)
tag_list.should be_empty
end

it "should be able to remove an array of words" do
tag_list.remove(["awesome", "radical"], :parse => true)
tag_list.should be_empty
end
end

it "#from should return empty array if empty array is passed" do
ActsAsTaggableOn::TagList.from([]).should == []

describe "#to_s" do
it "should give a delimited list of words when converted to string" do
tag_list.to_s.should == "awesome, radical"
end

it "should be able to call to_s on a frozen tag list" do
tag_list.freeze
lambda { tag_list.add("cool","rad,bodacious") }.should raise_error
lambda { tag_list.to_s }.should_not raise_error
end
end

it "should be able to call to_s on a frozen tag list" do
@tag_list.freeze
lambda { @tag_list.add("cool","rad,bodacious") }.should raise_error
lambda { @tag_list.to_s }.should_not raise_error

describe "cleaning" do
it "should parameterize if force_parameterize is set to true" do
ActsAsTaggableOn.force_parameterize = true
tag_list = ActsAsTaggableOn::TagList.new("awesome()","radical)(cc")

tag_list.to_s.should == "awesome, radical-cc"
ActsAsTaggableOn.force_parameterize = false
end

it "should lowercase if force_lowercase is set to true" do
ActsAsTaggableOn.force_lowercase = true

tag_list = ActsAsTaggableOn::TagList.new("aweSomE","RaDicaL")
tag_list.to_s.should == "awesome, radical"

ActsAsTaggableOn.force_lowercase = false
end

end
end
30 changes: 0 additions & 30 deletions spec/acts_as_taggable_on/tag_spec.rb
Expand Up @@ -120,35 +120,5 @@
end

end

describe ".remove_unused" do
before do
@taggable = TaggableModel.create(:name => "Bob Jones")
@tag = ActsAsTaggableOn::Tag.create(:name => "awesome")

@tagging = ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags')
end

context "if set to true" do
before do
ActsAsTaggableOn::Tag.remove_unused = true
end

it "should remove unused tags after removing taggings" do
@tagging.destroy
ActsAsTaggableOn::Tag.find_by_name("awesome").should be_nil
end
end

context "if set to false" do
before do
ActsAsTaggableOn::Tag.remove_unused = false
end

it "should not remove unused tags after removing taggings" do
@tagging.destroy
ActsAsTaggableOn::Tag.find_by_name("awesome").should == @tag
end
end
end
end

0 comments on commit 7086b00

Please sign in to comment.