acts_as_taggable_on 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +9 -0
  5. data/Appraisals +7 -0
  6. data/Gemfile +5 -0
  7. data/Guardfile +5 -0
  8. data/LICENSE.md +20 -0
  9. data/README.md +309 -0
  10. data/Rakefile +13 -0
  11. data/UPGRADING +7 -0
  12. data/acts_as_taggable_on.gemspec +35 -0
  13. data/db/migrate/1_acts_as_taggable_on_migration.rb +30 -0
  14. data/db/migrate/2_add_missing_unique_indices.rb +21 -0
  15. data/gemfiles/rails_3.gemfile +8 -0
  16. data/gemfiles/rails_4.gemfile +8 -0
  17. data/lib/acts_as_taggable_on.rb +61 -0
  18. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +82 -0
  19. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +187 -0
  20. data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +34 -0
  21. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +394 -0
  22. data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +37 -0
  23. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +135 -0
  24. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +84 -0
  25. data/lib/acts_as_taggable_on/engine.rb +6 -0
  26. data/lib/acts_as_taggable_on/tag.rb +119 -0
  27. data/lib/acts_as_taggable_on/tag_list.rb +101 -0
  28. data/lib/acts_as_taggable_on/taggable.rb +105 -0
  29. data/lib/acts_as_taggable_on/tagger.rb +76 -0
  30. data/lib/acts_as_taggable_on/tagging.rb +34 -0
  31. data/lib/acts_as_taggable_on/tags_helper.rb +15 -0
  32. data/lib/acts_as_taggable_on/utils.rb +34 -0
  33. data/lib/acts_as_taggable_on/version.rb +4 -0
  34. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +265 -0
  35. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +114 -0
  36. data/spec/acts_as_taggable_on/caching_spec.rb +77 -0
  37. data/spec/acts_as_taggable_on/related_spec.rb +143 -0
  38. data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +187 -0
  39. data/spec/acts_as_taggable_on/tag_list_spec.rb +126 -0
  40. data/spec/acts_as_taggable_on/tag_spec.rb +211 -0
  41. data/spec/acts_as_taggable_on/taggable_spec.rb +623 -0
  42. data/spec/acts_as_taggable_on/tagger_spec.rb +137 -0
  43. data/spec/acts_as_taggable_on/tagging_spec.rb +28 -0
  44. data/spec/acts_as_taggable_on/tags_helper_spec.rb +44 -0
  45. data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
  46. data/spec/bm.rb +52 -0
  47. data/spec/database.yml.sample +19 -0
  48. data/spec/models.rb +58 -0
  49. data/spec/schema.rb +65 -0
  50. data/spec/spec_helper.rb +87 -0
  51. metadata +248 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MzM5YzBmZjg5YWM2NTg1YzM3YWFkNTExYjQwMGY2YTc3ZmRkYmU4Yg==
5
+ data.tar.gz: !binary |-
6
+ YmEzMjhkODU3MmQyN2NhNzk4MTBmYzdmMGI0NmY1N2FkOWQ4NWE4NQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NDMxNWQyMWNiN2FmMDU0Yzk1NTg2Y2E1NmU1ZWU1NTI4YjQ0YmMwNTdjZTcw
10
+ Y2U0YWVlM2IxZmMwYzUzNmY0MWZjNGM1OTkwNDhkNjIyMGY4YzNmNjM2MmMz
11
+ ODQzYzljZTk2MTA3YWIxNWI4OTkyNjVjMjZiOTMwNWJlN2M1MWE=
12
+ data.tar.gz: !binary |-
13
+ MTE1MTcxNzIxMmQ2ZTY5OTAxYmM5NzJmN2Y0ZTQ5MjM4NDY2NzU3NjYxYjI5
14
+ NjIwODI5YjM4ZDI5YWJiMzk0OGYzZjM2OTlkNmU0ZjlmOWRlZDRlOTZkYWU0
15
+ MmNmYWJiYTA0ZjQzZjIwNmI3NWE5ZjQ4YmZjZDNiMjc3ZjU2N2I=
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.log
2
+ *.sqlite3
3
+ /pkg/*
4
+ .bundle
5
+ .ruby-version
6
+ spec/database.yml
7
+ tmp*.sw?
8
+ *.sw?
9
+ tmp
10
+ *.gem
11
+ *.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --backtrace
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ script: "cp spec/database.yml.sample spec/database.yml && bundle install && bundle exec rake"
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ env:
6
+ - DB=sqlite3
7
+ - DB=mysql
8
+ - DB=postgresql
9
+ cache: bundler
data/Appraisals ADDED
@@ -0,0 +1,7 @@
1
+ appraise "rails-3" do
2
+ gem "rails", "3.2.13"
3
+ end
4
+
5
+ appraise "rails-4" do
6
+ gem "rails", "4.0.0.beta1"
7
+ end
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'appraisal'
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb})
3
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE.md 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.md ADDED
@@ -0,0 +1,309 @@
1
+ # ActsAsTaggableOn
2
+ [![Build Status](https://secure.travis-ci.org/mbleigh/acts-as-taggable-on.png)](http://travis-ci.org/mbleigh/acts-as-taggable-on)
3
+ [![Code Climate](https://codeclimate.com/github/mbleigh/acts-as-taggable-on.png)](https://codeclimate.com/github/mbleigh/acts-as-taggable-on)
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
+ ## Compatibility
19
+
20
+ Versions 2.x are compatible with Ruby 1.8.7+ and Rails 3.
21
+
22
+ Versions 2.4.1 and up are compatible with Rails 4 too (thanks to arabonradar and cwoodcox).
23
+
24
+ Versions 3.x (currently unreleased) are compatible with Ruby 1.9.3+ and Rails 3 and 4.
25
+
26
+ For an up-to-date roadmap, see https://github.com/mbleigh/acts-as-taggable-on/issues/milestones
27
+
28
+ ## Installation
29
+
30
+ To use it, add it to your Gemfile:
31
+
32
+ ```ruby
33
+ gem 'acts_as_taggable_on'
34
+ ```
35
+
36
+ and bundle:
37
+
38
+ ```ruby
39
+ bundle
40
+ ```
41
+
42
+ #### Post Installation
43
+
44
+ ```shell
45
+ rails generate acts_as_taggable_on:migration
46
+ rake db:migrate
47
+ ```
48
+
49
+ #### Upgrading
50
+
51
+ see [UPGRADING](UPGRADING)
52
+
53
+ ## Testing
54
+
55
+ Acts As Taggable On uses RSpec for its test coverage. Inside the gem
56
+ directory, you can run the specs with:
57
+
58
+ ```shell
59
+ bundle
60
+ cp spec/database.yml{.sample,}
61
+ rake spec
62
+ ```
63
+
64
+ If you want, add a `.ruby-version` file in the project root (and use rbenv or RVM) to work on a specific version of Ruby.
65
+
66
+ ## Usage
67
+
68
+ ```ruby
69
+ class User < ActiveRecord::Base
70
+ # Alias for acts_as_taggable_on :tags
71
+ acts_as_taggable
72
+ acts_as_taggable_on :skills, :interests
73
+ end
74
+
75
+ @user = User.new(:name => "Bobby")
76
+ @user.tag_list = "awesome, slick, hefty" # this should be familiar
77
+ @user.skill_list = "joking, clowning, boxing" # but you can do it for any context!
78
+
79
+ @user.tags # => [<Tag name:"awesome">,<Tag name:"slick">,<Tag name:"hefty">]
80
+ @user.skills # => [<Tag name:"joking">,<Tag name:"clowning">,<Tag name:"boxing">]
81
+ @user.skill_list # => ["joking","clowning","boxing"] as TagList
82
+
83
+ @user.tag_list.remove("awesome") # remove a single tag
84
+ @user.tag_list.remove("awesome, slick") # works with arrays too
85
+ @user.tag_list.add("awesomer") # add a single tag. alias for <<
86
+ @user.tag_list.add("awesomer, slicker") # also works with arrays
87
+
88
+ User.skill_counts # => [<Tag name="joking" count=2>,<Tag name="clowning" count=1>...]
89
+ ```
90
+
91
+ To preserve the order in which tags are created use `acts_as_ordered_taggable`:
92
+
93
+ ```ruby
94
+ class User < ActiveRecord::Base
95
+ # Alias for acts_as_ordered_taggable_on :tags
96
+ acts_as_ordered_taggable
97
+ acts_as_ordered_taggable_on :skills, :interests
98
+ end
99
+
100
+ @user = User.new(:name => "Bobby")
101
+ @user.tag_list = "east, south"
102
+ @user.save
103
+
104
+ @user.tag_list = "north, east, south, west"
105
+ @user.save
106
+
107
+ @user.reload
108
+ @user.tag_list # => ["north", "east", "south", "west"]
109
+ ```
110
+
111
+ ### Finding Tagged Objects
112
+
113
+ Acts As Taggable On uses scopes to create an association for tags.
114
+ This way you can mix and match to filter down your results.
115
+
116
+ ```ruby
117
+ class User < ActiveRecord::Base
118
+ acts_as_taggable_on :tags, :skills
119
+ scope :by_join_date, order("created_at DESC")
120
+ end
121
+
122
+ User.tagged_with("awesome").by_join_date
123
+ User.tagged_with("awesome").by_join_date.paginate(:page => params[:page], :per_page => 20)
124
+
125
+ # Find a user with matching all tags, not just one
126
+ User.tagged_with(["awesome", "cool"], :match_all => true)
127
+
128
+ # Find a user with any of the tags:
129
+ User.tagged_with(["awesome", "cool"], :any => true)
130
+
131
+ # Find a user that not tags with awesome or cool:
132
+ User.tagged_with(["awesome", "cool"], :exclude => true)
133
+
134
+ # Find a user with any of tags based on context:
135
+ User.tagged_with(['awesome, cool'], :on => :tags, :any => true).tagged_with(['smart', 'shy'], :on => :skills, :any => true)
136
+ ```
137
+
138
+ You can also use `:wild => true` option along with `:any` or `:exclude` option. It will looking for `%awesome%` and `%cool%` in sql.
139
+
140
+ __Tip:__ `User.tagged_with([])` or '' will return `[]`, but not all records.
141
+
142
+ ### Relationships
143
+
144
+ You can find objects of the same type based on similar tags on certain contexts.
145
+ Also, objects will be returned in descending order based on the total number of
146
+ matched tags.
147
+
148
+ ```ruby
149
+ @bobby = User.find_by_name("Bobby")
150
+ @bobby.skill_list # => ["jogging", "diving"]
151
+
152
+ @frankie = User.find_by_name("Frankie")
153
+ @frankie.skill_list # => ["hacking"]
154
+
155
+ @tom = User.find_by_name("Tom")
156
+ @tom.skill_list # => ["hacking", "jogging", "diving"]
157
+
158
+ @tom.find_related_skills # => [<User name="Bobby">,<User name="Frankie">]
159
+ @bobby.find_related_skills # => [<User name="Tom">]
160
+ @frankie.find_related_skills # => [<User name="Tom">]
161
+ ```
162
+
163
+ ### Dynamic Tag Contexts
164
+
165
+ In addition to the generated tag contexts in the definition, it is also possible
166
+ to allow for dynamic tag contexts (this could be user generated tag contexts!)
167
+
168
+ ```ruby
169
+ @user = User.new(:name => "Bobby")
170
+ @user.set_tag_list_on(:customs, "same, as, tag, list")
171
+ @user.tag_list_on(:customs) # => ["same","as","tag","list"]
172
+ @user.save
173
+ @user.tags_on(:customs) # => [<Tag name='same'>,...]
174
+ @user.tag_counts_on(:customs)
175
+ User.tagged_with("same", :on => :customs) # => [@user]
176
+ ```
177
+
178
+ ### Tag Ownership
179
+
180
+ Tags can have owners:
181
+
182
+ ```ruby
183
+ class User < ActiveRecord::Base
184
+ acts_as_tagger
185
+ end
186
+
187
+ class Photo < ActiveRecord::Base
188
+ acts_as_taggable_on :locations
189
+ end
190
+
191
+ @some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations)
192
+ @some_user.owned_taggings
193
+ @some_user.owned_tags
194
+ Photo.tagged_with("paris", :on => :locations, :owned_by => @some_user)
195
+ @some_photo.locations_from(@some_user) # => ["paris", "normandy"]
196
+ @some_photo.owner_tags_on(@some_user, :locations) # => [#<ActsAsTaggableOn::Tag id: 1, name: "paris">...]
197
+ @some_photo.owner_tags_on(nil, :locations) # => Ownerships equivalent to saying @some_photo.locations
198
+ @some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations, :skip_save => true) #won't save @some_photo object
199
+ ```
200
+
201
+ ### Dirty objects
202
+
203
+ ```ruby
204
+ @bobby = User.find_by_name("Bobby")
205
+ @bobby.skill_list # => ["jogging", "diving"]
206
+
207
+ @bobby.skill_list_changed? #=> false
208
+ @bobby.changes #=> {}
209
+
210
+ @bobby.skill_list = "swimming"
211
+ @bobby.changes.should == {"skill_list"=>["jogging, diving", ["swimming"]]}
212
+ @bobby.skill_list_changed? #=> true
213
+
214
+ @bobby.skill_list_change.should == ["jogging, diving", ["swimming"]]
215
+ ```
216
+
217
+ ### Tag cloud calculations
218
+
219
+ To construct tag clouds, the frequency of each tag needs to be calculated.
220
+ Because we specified `acts_as_taggable_on` on the `User` class, we can
221
+ get a calculation of all the tag counts by using `User.tag_counts_on(:customs)`. But what if we wanted a tag count for
222
+ an single user's posts? To achieve this we call tag_counts on the association:
223
+
224
+ ```ruby
225
+ User.find(:first).posts.tag_counts_on(:tags)
226
+ ```
227
+
228
+ A helper is included to assist with generating tag clouds.
229
+
230
+ Here is an example that generates a tag cloud.
231
+
232
+ Helper:
233
+
234
+ ```ruby
235
+ module PostsHelper
236
+ include ActsAsTaggableOn::TagsHelper
237
+ end
238
+ ```
239
+
240
+ Controller:
241
+
242
+ ```ruby
243
+ class PostController < ApplicationController
244
+ def tag_cloud
245
+ @tags = Post.tag_counts_on(:tags)
246
+ end
247
+ end
248
+ ```
249
+
250
+ View:
251
+
252
+ ```erb
253
+ <% tag_cloud(@tags, %w(css1 css2 css3 css4)) do |tag, css_class| %>
254
+ <%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>
255
+ <% end %>
256
+ ```
257
+
258
+ CSS:
259
+
260
+ ```css
261
+ .css1 { font-size: 1.0em; }
262
+ .css2 { font-size: 1.2em; }
263
+ .css3 { font-size: 1.4em; }
264
+ .css4 { font-size: 1.6em; }
265
+ ```
266
+
267
+ ## Configuration
268
+
269
+ If you would like to remove unused tag objects after removing taggings, add:
270
+
271
+ ```ruby
272
+ ActsAsTaggableOn.remove_unused_tags = true
273
+ ```
274
+
275
+ If you want force tags to be saved downcased:
276
+
277
+ ```ruby
278
+ ActsAsTaggableOn.force_lowercase = true
279
+ ```
280
+
281
+ If you want tags to be saved parametrized (you can redefine to_param as well):
282
+
283
+ ```ruby
284
+ ActsAsTaggableOn.force_parameterize = true
285
+ ```
286
+
287
+ If you would like tags to be case-sensitive and not use LIKE queries for creation:
288
+
289
+ ```ruby
290
+ ActsAsTaggableOn.strict_case_match = true
291
+ ```
292
+
293
+ If you want to change the default delimiter (it defaults to ','). You can also pass in an array of delimiters such as ([',', '|']):
294
+
295
+ ```ruby
296
+ ActsAsTaggableOn.delimiter = ','
297
+ ```
298
+
299
+ ## Contributors
300
+
301
+ We have a long list of valued contributors. [Check them all](https://github.com/mbleigh/acts-as-taggable-on/contributors)
302
+
303
+ ## Maintainer
304
+
305
+ * [Joost Baaij](https://github.com/tilsammans)
306
+
307
+ ## License
308
+
309
+ See [LICENSE](https://github.com/mbleigh/acts-as-taggable-on/blob/master/LICENSE.md)
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'appraisal'
4
+
5
+ desc 'Default: run specs'
6
+ task :default => :spec
7
+
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.pattern = "spec/**/*_spec.rb"
11
+ end
12
+
13
+ Bundler::GemHelper.install_tasks
data/UPGRADING ADDED
@@ -0,0 +1,7 @@
1
+ When upgrading
2
+
3
+ Re-run the migrations generator
4
+
5
+ rake railties:install:migrations FROM=acts_as_taggable_on_engine db:migrate
6
+
7
+ It will create any new migrations and skip existing ones
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'acts_as_taggable_on/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "acts_as_taggable_on"
8
+ gem.version = ActsAsTaggableOn::VERSION
9
+ gem.authors = ["Michael Bleigh", "Joost Baaij"]
10
+ gem.email = ["michael@intridea.com", "joost@spacebabies.nl"]
11
+ 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.}
12
+ gem.summary = "Advanced tagging for Rails."
13
+ gem.homepage = 'https://github.com/mbleigh/acts-as-taggable-on'
14
+ gem.license = "MIT"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ if File.exists?('UPGRADING')
22
+ gem.post_install_message = File.read('UPGRADING')
23
+ end
24
+
25
+ gem.add_runtime_dependency 'rails', ['>= 3', '< 5']
26
+
27
+ gem.add_development_dependency 'rspec-rails', '2.13.0' # 2.13.1 is broken
28
+ gem.add_development_dependency 'rspec', '~> 2.6'
29
+ gem.add_development_dependency 'ammeter'
30
+ gem.add_development_dependency 'sqlite3'
31
+ gem.add_development_dependency 'mysql2', '~> 0.3.7'
32
+ gem.add_development_dependency 'pg'
33
+ gem.add_development_dependency 'guard'
34
+ gem.add_development_dependency 'guard-rspec'
35
+ end