acts-as-taggable-on-padrino 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.rspec +2 -0
  2. data/CHANGELOG +29 -0
  3. data/Gemfile +15 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +194 -0
  6. data/Rakefile +33 -0
  7. data/VERSION +1 -0
  8. data/acts-as-taggable-on-padrino.gemspec +94 -0
  9. data/lib/acts-as-taggable-on-padrino.rb +41 -0
  10. data/lib/acts_as_taggable_on_padrino/tag.rb +72 -0
  11. data/lib/acts_as_taggable_on_padrino/taggable.rb +64 -0
  12. data/lib/acts_as_taggable_on_padrino/taggable/cache.rb +54 -0
  13. data/lib/acts_as_taggable_on_padrino/taggable/collection.rb +91 -0
  14. data/lib/acts_as_taggable_on_padrino/taggable/core.rb +244 -0
  15. data/lib/acts_as_taggable_on_padrino/taggable/ownership.rb +104 -0
  16. data/lib/acts_as_taggable_on_padrino/taggable/related.rb +60 -0
  17. data/lib/acts_as_taggable_on_padrino/taggable/tag_list.rb +96 -0
  18. data/lib/acts_as_taggable_on_padrino/tagger.rb +65 -0
  19. data/lib/acts_as_taggable_on_padrino/tagging.rb +29 -0
  20. data/lib/acts_as_taggable_on_padrino/tags_helper.rb +17 -0
  21. data/lib/tasks/generate_migration.rb +23 -0
  22. data/lib/tasks/templates/migration.rb +29 -0
  23. data/spec/acts_as_taggable_on_padrino/acts_as_taggable_on_spec.rb +263 -0
  24. data/spec/acts_as_taggable_on_padrino/acts_as_tagger_spec.rb +110 -0
  25. data/spec/acts_as_taggable_on_padrino/tag_list_spec.rb +70 -0
  26. data/spec/acts_as_taggable_on_padrino/tag_spec.rb +105 -0
  27. data/spec/acts_as_taggable_on_padrino/taggable_spec.rb +333 -0
  28. data/spec/acts_as_taggable_on_padrino/tagger_spec.rb +90 -0
  29. data/spec/acts_as_taggable_on_padrino/tagging_spec.rb +26 -0
  30. data/spec/acts_as_taggable_on_padrino/tags_helper_spec.rb +26 -0
  31. data/spec/bm.rb +52 -0
  32. data/spec/database.yml.sample +17 -0
  33. data/spec/models.rb +47 -0
  34. data/spec/schema.rb +57 -0
  35. data/spec/spec_helper.rb +60 -0
  36. data/uninstall.rb +1 -0
  37. metadata +175 -0
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --backtrace
data/CHANGELOG ADDED
@@ -0,0 +1,29 @@
1
+ == 2011-06-20
2
+
3
+ * Converted to Padrino compatible Gem
4
+
5
+ == 2010-02-17
6
+ * Converted the plugin to be compatible with Rails3
7
+
8
+ == 2009-12-02
9
+
10
+ * PostgreSQL is now supported (via morgoth)
11
+
12
+ == 2008-07-17
13
+
14
+ * Can now use a named_scope to find tags!
15
+
16
+ == 2008-06-23
17
+
18
+ * Can now find related objects of another class (tristanzdunn)
19
+ * Removed extraneous down migration cruft (azabaj)
20
+
21
+ == 2008-06-09
22
+
23
+ * Added support for Single Table Inheritance
24
+ * Adding gemspec and rails/init.rb for gemified plugin
25
+
26
+ == 2007-12-12
27
+
28
+ * Added ability to use dynamic tag contexts
29
+ * Fixed missing migration generator
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source :gemcutter
2
+
3
+ gem 'activerecord', '>= 3.0.0'
4
+
5
+ group :development, :test do
6
+ gem 'sqlite3-ruby', :require => 'sqlite3'
7
+ gem 'mysql'
8
+ gem 'pg'
9
+
10
+ gem 'jeweler'
11
+
12
+ gem 'rspec', '>= 2.0.0'
13
+ gem 'rcov'
14
+ gem 'database_cleaner'
15
+ end
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Michael Bleigh and Intridea Inc.
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.
data/README.rdoc ADDED
@@ -0,0 +1,194 @@
1
+ = ActsAsTaggableOn
2
+
3
+ This is a Padrino version of Ben Woosley's version of the below:
4
+
5
+ This plugin was originally based on Acts as Taggable on Steroids by Jonathan Viney.
6
+ It has evolved substantially since that point, but all credit goes to him for the
7
+ initial tagging functionality that so many people have used.
8
+
9
+ For instance, in a social network, a user might have tags that are called skills,
10
+ interests, sports, and more. There is no real way to differentiate between tags and
11
+ so an implementation of this type is not possible with acts as taggable on steroids.
12
+
13
+ Enter Acts as Taggable On. Rather than tying functionality to a specific keyword
14
+ (namely "tags"), acts as taggable on allows you to specify an arbitrary number of
15
+ tag "contexts" that can be used locally or in combination in the same way steroids
16
+ was used.
17
+
18
+ == Installation
19
+
20
+ 1) Add it to your Gemfile:
21
+ gem 'acts-as-taggable-on-padrino'
22
+
23
+ 2) Install it with bundler
24
+ bundle install
25
+
26
+ ==== Post Installation
27
+
28
+ From the root of your Padrino App:
29
+ 1. padrino rake taggable:create_migration
30
+ 2. padrino rake ar:migrate
31
+
32
+ == Testing
33
+
34
+ Acts As Taggable On uses RSpec for its test coverage. Inside the plugin
35
+ directory, you can run the specs with:
36
+
37
+ rake spec
38
+
39
+ If you already have RSpec on your application, the specs will run while using:
40
+
41
+ rake spec:plugins
42
+
43
+
44
+ == Usage
45
+
46
+ class User < ActiveRecord::Base
47
+ # Alias for <tt>acts_as_taggable_on :tags</tt>:
48
+ acts_as_taggable
49
+ acts_as_taggable_on :skills, :interests
50
+ end
51
+
52
+ @user = User.new(:name => "Bobby")
53
+ @user.tag_list = "awesome, slick, hefty" # this should be familiar
54
+ @user.skill_list = "joking, clowning, boxing" # but you can do it for any context!
55
+ @user.skill_list # => ["joking","clowning","boxing"] as TagList
56
+ @user.save
57
+
58
+ @user.tags # => [<Tag name:"awesome">,<Tag name:"slick">,<Tag name:"hefty">]
59
+ @user.skills # => [<Tag name:"joking">,<Tag name:"clowning">,<Tag name:"boxing">]
60
+
61
+ @frankie = User.create(:name => "Frankie", :skill_list => "joking, flying, eating")
62
+ User.skill_counts # => [<Tag name="joking" count=2>,<Tag name="clowning" count=1>...]
63
+ @frankie.skill_counts
64
+
65
+ === Finding Tagged Objects
66
+
67
+ Acts As Taggable On utilizes named_scopes to create an association for tags.
68
+ This way you can mix and match to filter down your results, and it also improves
69
+ compatibility with the will_paginate gem:
70
+
71
+ class User < ActiveRecord::Base
72
+ acts_as_taggable_on :tags
73
+ named_scope :by_join_date, :order => "created_at DESC"
74
+ end
75
+
76
+ User.tagged_with("awesome").by_date
77
+ User.tagged_with("awesome").by_date.paginate(:page => params[:page], :per_page => 20)
78
+
79
+ # Find a user with matching all tags, not just one
80
+ User.tagged_with(["awesome", "cool"], :match_all => :true)
81
+
82
+ # Find a user with any of the tags:
83
+ User.tagged_with(["awesome", "cool"], :any => true)
84
+
85
+ === Relationships
86
+
87
+ You can find objects of the same type based on similar tags on certain contexts.
88
+ Also, objects will be returned in descending order based on the total number of
89
+ matched tags.
90
+
91
+ @bobby = User.find_by_name("Bobby")
92
+ @bobby.skill_list # => ["jogging", "diving"]
93
+
94
+ @frankie = User.find_by_name("Frankie")
95
+ @frankie.skill_list # => ["hacking"]
96
+
97
+ @tom = User.find_by_name("Tom")
98
+ @tom.skill_list # => ["hacking", "jogging", "diving"]
99
+
100
+ @tom.find_related_skills # => [<User name="Bobby">,<User name="Frankie">]
101
+ @bobby.find_related_skills # => [<User name="Tom">]
102
+ @frankie.find_related_skills # => [<User name="Tom">]
103
+
104
+ === Dynamic Tag Contexts
105
+
106
+ In addition to the generated tag contexts in the definition, it is also possible
107
+ to allow for dynamic tag contexts (this could be user generated tag contexts!)
108
+
109
+ @user = User.new(:name => "Bobby")
110
+ @user.set_tag_list_on(:customs, "same, as, tag, list")
111
+ @user.tag_list_on(:customs) # => ["same","as","tag","list"]
112
+ @user.save
113
+ @user.tags_on(:customs) # => [<Tag name='same'>,...]
114
+ @user.tag_counts_on(:customs)
115
+ User.tagged_with("same", :on => :customs) # => [@user]
116
+
117
+ === Tag Ownership
118
+
119
+ Tags can have owners:
120
+
121
+ class User < ActiveRecord::Base
122
+ acts_as_tagger
123
+ end
124
+
125
+ class Photo < ActiveRecord::Base
126
+ acts_as_taggable_on :locations
127
+ end
128
+
129
+ @some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations)
130
+ @some_user.owned_taggings
131
+ @some_user.owned_tags
132
+ @some_photo.locations_from(@some_user)
133
+
134
+ === Tag cloud calculations
135
+
136
+ To construct tag clouds, the frequency of each tag needs to be calculated.
137
+ Because we specified +acts_as_taggable_on+ on the <tt>User</tt> class, we can
138
+ get a calculation of all the tag counts by using <tt>User.tag_counts_on(:customs)</tt>. But what if we wanted a tag count for
139
+ an single user's posts? To achieve this we call tag_counts on the association:
140
+
141
+ User.find(:first).posts.tag_counts_on(:tags)
142
+
143
+ A helper is included to assist with generating tag clouds.
144
+
145
+ Here is an example that generates a tag cloud.
146
+
147
+ Helper:
148
+
149
+ module PostsHelper
150
+ include ActsAsTaggableOn::TagsHelper
151
+ end
152
+
153
+ Controller:
154
+
155
+ class PostController < ApplicationController
156
+ def tag_cloud
157
+ @tags = Post.tag_counts_on(:tags)
158
+ end
159
+ end
160
+
161
+ View:
162
+
163
+ <% tag_cloud(@tags, %w(css1 css2 css3 css4)) do |tag, css_class| %>
164
+ <%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>
165
+ <% end %>
166
+
167
+ CSS:
168
+
169
+ .css1 { font-size: 1.0em; }
170
+ .css2 { font-size: 1.2em; }
171
+ .css3 { font-size: 1.4em; }
172
+ .css4 { font-size: 1.6em; }
173
+
174
+ == Contributors
175
+
176
+ * TomEric (i76) - Maintainer
177
+ * Michael Bleigh - Original Author
178
+ * Szymon Nowak - Rails 3.0 compatibility
179
+ * Jelle Vandebeeck - Rails 3.0 compatibility
180
+ * Brendan Lim - Related Objects
181
+ * Pradeep Elankumaran - Taggers
182
+ * Sinclair Bain - Patch King
183
+
184
+ === Patch Contributors
185
+
186
+ * tristanzdunn - Related objects of other classes
187
+ * azabaj - Fixed migrate down
188
+ * Peter Cooper - named_scope fix
189
+ * slainer68 - STI fix
190
+ * harrylove - migration instructions and fix-ups
191
+ * lawrencepit - cached tag work
192
+ * sobrinho - fixed tag_cloud helper
193
+
194
+ Copyright (c) 2007-2010 Michael Bleigh (http://mbleigh.com/) and Intridea Inc. (http://intridea.com/), released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ begin # Rspec 2.0
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc 'Default: run specs'
5
+ task :default => :spec
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.pattern = "spec/**/*_spec.rb"
8
+ end
9
+
10
+ RSpec::Core::RakeTask.new('rcov') do |t|
11
+ t.pattern = "spec/**/*_spec.rb"
12
+ t.rcov = true
13
+ t.rcov_opts = ['--exclude', 'spec']
14
+ end
15
+
16
+ rescue LoadError
17
+ puts "Rspec not available. Install it with: gem install rspec"
18
+ end
19
+
20
+ begin
21
+ require 'jeweler'
22
+ Jeweler::Tasks.new do |gemspec|
23
+ gemspec.name = "acts-as-taggable-on-padrino"
24
+ gemspec.summary = "ActsAsTaggableOnPadrino is a tagging plugin for Padrino that provides multiple tagging contexts on a single model."
25
+ gemspec.description = "With ActsAsTaggableOnPadrino, you could tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality."
26
+ gemspec.email = "john.knott@gmail.com"
27
+ gemspec.homepage = "http://github.com/johnknott/acts-as-taggable-on-padrino"
28
+ gemspec.authors = ["Michael Bleigh","John Knott"]
29
+ end
30
+ Jeweler::GemcutterTasks.new
31
+ rescue LoadError
32
+ puts "Jeweler not available. Install it with: gem install jeweler"
33
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,94 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{acts-as-taggable-on-padrino}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Bleigh", "John Knott"]
12
+ s.date = %q{2011-06-29}
13
+ s.description = %q{With ActsAsTaggableOnPadrino, you could tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality.}
14
+ s.email = %q{john.knott@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".rspec",
20
+ "CHANGELOG",
21
+ "Gemfile",
22
+ "MIT-LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "acts-as-taggable-on-padrino.gemspec",
27
+ "lib/acts-as-taggable-on-padrino.rb",
28
+ "lib/acts_as_taggable_on_padrino/tag.rb",
29
+ "lib/acts_as_taggable_on_padrino/taggable.rb",
30
+ "lib/acts_as_taggable_on_padrino/taggable/cache.rb",
31
+ "lib/acts_as_taggable_on_padrino/taggable/collection.rb",
32
+ "lib/acts_as_taggable_on_padrino/taggable/core.rb",
33
+ "lib/acts_as_taggable_on_padrino/taggable/ownership.rb",
34
+ "lib/acts_as_taggable_on_padrino/taggable/related.rb",
35
+ "lib/acts_as_taggable_on_padrino/taggable/tag_list.rb",
36
+ "lib/acts_as_taggable_on_padrino/tagger.rb",
37
+ "lib/acts_as_taggable_on_padrino/tagging.rb",
38
+ "lib/acts_as_taggable_on_padrino/tags_helper.rb",
39
+ "lib/tasks/generate_migration.rb",
40
+ "lib/tasks/templates/migration.rb",
41
+ "spec/acts_as_taggable_on_padrino/acts_as_taggable_on_spec.rb",
42
+ "spec/acts_as_taggable_on_padrino/acts_as_tagger_spec.rb",
43
+ "spec/acts_as_taggable_on_padrino/tag_list_spec.rb",
44
+ "spec/acts_as_taggable_on_padrino/tag_spec.rb",
45
+ "spec/acts_as_taggable_on_padrino/taggable_spec.rb",
46
+ "spec/acts_as_taggable_on_padrino/tagger_spec.rb",
47
+ "spec/acts_as_taggable_on_padrino/tagging_spec.rb",
48
+ "spec/acts_as_taggable_on_padrino/tags_helper_spec.rb",
49
+ "spec/bm.rb",
50
+ "spec/database.yml.sample",
51
+ "spec/models.rb",
52
+ "spec/schema.rb",
53
+ "spec/spec_helper.rb",
54
+ "uninstall.rb"
55
+ ]
56
+ s.homepage = %q{http://github.com/johnknott/acts-as-taggable-on-padrino}
57
+ s.require_paths = ["lib"]
58
+ s.rubygems_version = %q{1.6.2}
59
+ s.summary = %q{ActsAsTaggableOnPadrino is a tagging plugin for Padrino that provides multiple tagging contexts on a single model.}
60
+
61
+ if s.respond_to? :specification_version then
62
+ s.specification_version = 3
63
+
64
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
65
+ s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0"])
66
+ s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
67
+ s.add_development_dependency(%q<mysql>, [">= 0"])
68
+ s.add_development_dependency(%q<pg>, [">= 0"])
69
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
70
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0"])
71
+ s.add_development_dependency(%q<rcov>, [">= 0"])
72
+ s.add_development_dependency(%q<database_cleaner>, [">= 0"])
73
+ else
74
+ s.add_dependency(%q<activerecord>, [">= 3.0.0"])
75
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
76
+ s.add_dependency(%q<mysql>, [">= 0"])
77
+ s.add_dependency(%q<pg>, [">= 0"])
78
+ s.add_dependency(%q<jeweler>, [">= 0"])
79
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
80
+ s.add_dependency(%q<rcov>, [">= 0"])
81
+ s.add_dependency(%q<database_cleaner>, [">= 0"])
82
+ end
83
+ else
84
+ s.add_dependency(%q<activerecord>, [">= 3.0.0"])
85
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
86
+ s.add_dependency(%q<mysql>, [">= 0"])
87
+ s.add_dependency(%q<pg>, [">= 0"])
88
+ s.add_dependency(%q<jeweler>, [">= 0"])
89
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
90
+ s.add_dependency(%q<rcov>, [">= 0"])
91
+ s.add_dependency(%q<database_cleaner>, [">= 0"])
92
+ end
93
+ end
94
+
@@ -0,0 +1,41 @@
1
+ require "active_record"
2
+ require 'active_support/core_ext/class/attribute_accessors'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+
6
+ require "acts_as_taggable_on_padrino/taggable"
7
+ require "acts_as_taggable_on_padrino/taggable/core"
8
+ require "acts_as_taggable_on_padrino/taggable/collection"
9
+ require "acts_as_taggable_on_padrino/taggable/cache"
10
+ require "acts_as_taggable_on_padrino/taggable/ownership"
11
+ require "acts_as_taggable_on_padrino/taggable/related"
12
+ require "acts_as_taggable_on_padrino/taggable/tag_list"
13
+
14
+ require "acts_as_taggable_on_padrino/tagger"
15
+ require "acts_as_taggable_on_padrino/tag"
16
+ require "acts_as_taggable_on_padrino/tags_helper"
17
+ require "acts_as_taggable_on_padrino/tagging"
18
+
19
+ $LOAD_PATH.shift
20
+
21
+ ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
22
+ ActiveRecord::Base.extend ActsAsTaggableOn::Tagger
23
+ ActiveRecord::Base.extend ActsAsTaggableOn::Tag
24
+ ActiveRecord::Base.extend ActsAsTaggableOn::Tagging
25
+
26
+ if defined?(Padrino::Helpers::TagHelpers)
27
+ Padrino::Helpers::TagHelpers.send :include, ActsAsTaggableOn::TagsHelper
28
+ end
29
+
30
+ module ActsAsTaggableOn
31
+ def like_operator
32
+ @like_operator ||= (ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' ? 'ILIKE' : 'LIKE')
33
+ end
34
+ module_function :like_operator
35
+ end
36
+
37
+ begin
38
+ require 'padrino-gen'
39
+ Padrino::Tasks.files << Dir[File.dirname(__FILE__) + "/tasks/**/*.rb"]
40
+ rescue LoadError
41
+ end
@@ -0,0 +1,72 @@
1
+ module ActsAsTaggableOn
2
+ module Tag
3
+ def acts_as_tag(opts = {})
4
+ opts.assert_valid_keys :tagging
5
+ tagging_class_name = opts[:tagging] || 'Tagging'
6
+
7
+ class_eval do
8
+ attr_accessible :name
9
+
10
+ ### ASSOCIATIONS:
11
+
12
+ has_many :taggings, :dependent => :destroy, :class_name => tagging_class_name
13
+
14
+ ### VALIDATIONS:
15
+ validates_presence_of :name
16
+ validates_uniqueness_of :name
17
+
18
+ ### SCOPES:
19
+ scope :named, lambda {|name| where(["name #{ActsAsTaggableOn.like_operator} ?", name]) }
20
+ scope :named_any, lambda {|list| where(list.map { |tag| sanitize_sql(["name #{ActsAsTaggableOn.like_operator} ?", tag.to_s]) }.join(" OR ")) }
21
+ scope :named_like, lambda {|name| where(["name #{ActsAsTaggableOn.like_operator} ?", "%#{name}%"]) }
22
+ scope :named_like_any, lambda {|list| where(list.map { |tag| sanitize_sql(["name #{ActsAsTaggableOn.like_operator} ?", "%#{tag.to_s}%"]) }.join(" OR ")) }
23
+ end
24
+
25
+ include ActsAsTaggableOn::Tag::InstanceMethods
26
+ extend ActsAsTaggableOn::Tag::ClassMethods
27
+ end
28
+
29
+ module ClassMethods
30
+ def find_or_create_with_like_by_name(name)
31
+ named_like(name).first || create(:name => name)
32
+ end
33
+
34
+ def find_or_create_all_with_like_by_name(*list)
35
+ list = list.flatten
36
+ return [] if list.empty?
37
+
38
+ existing_tags = named_any(list)
39
+ new_tag_names = list.reject do |name|
40
+ name = comparable_name(name)
41
+ existing_tags.any? { |tag| comparable_name(tag.name) == name }
42
+ end
43
+ created_tags = new_tag_names.map { |name| create(:name => name) }
44
+
45
+ existing_tags + created_tags
46
+ end
47
+
48
+ def names
49
+ all.map {|tag| tag.name }
50
+ end
51
+
52
+ private
53
+ def comparable_name(str)
54
+ RUBY_VERSION >= "1.9" ? str.downcase : str.mb_chars.downcase
55
+ end
56
+ end
57
+
58
+ module InstanceMethods
59
+ def ==(object)
60
+ super || (object.is_a?(self.class) && name == object.name)
61
+ end
62
+
63
+ def to_s
64
+ name
65
+ end
66
+
67
+ def count
68
+ read_attribute(:count).to_i
69
+ end
70
+ end
71
+ end
72
+ end