acts-as-taggable-on 3.2.1 → 3.4.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +21 -1
  3. data/Appraisals +8 -6
  4. data/CHANGELOG.md +99 -10
  5. data/README.md +78 -11
  6. data/acts-as-taggable-on.gemspec +2 -4
  7. data/db/migrate/4_add_missing_taggable_index.rb +9 -0
  8. data/gemfiles/activerecord_3.2.gemfile +0 -1
  9. data/gemfiles/activerecord_4.0.gemfile +1 -2
  10. data/gemfiles/activerecord_4.1.gemfile +1 -2
  11. data/gemfiles/activerecord_4.2.gemfile +16 -0
  12. data/gemfiles/activerecord_edge.gemfile +0 -1
  13. data/lib/acts-as-taggable-on.rb +40 -21
  14. data/lib/acts_as_taggable_on/default_parser.rb +79 -0
  15. data/lib/acts_as_taggable_on/generic_parser.rb +19 -0
  16. data/lib/acts_as_taggable_on/tag.rb +6 -1
  17. data/lib/acts_as_taggable_on/tag_list.rb +20 -79
  18. data/lib/acts_as_taggable_on/tag_list_parser.rb +21 -0
  19. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/cache.rb +1 -0
  20. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/collection.rb +3 -1
  21. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/core.rb +87 -51
  22. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/ownership.rb +1 -1
  23. data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/related.rb +6 -6
  24. data/lib/acts_as_taggable_on/taggable.rb +7 -8
  25. data/lib/acts_as_taggable_on/tagging.rb +7 -1
  26. data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
  27. data/lib/acts_as_taggable_on/utils.rb +26 -50
  28. data/lib/acts_as_taggable_on/version.rb +1 -1
  29. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +1 -1
  30. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +1 -0
  31. data/spec/acts_as_taggable_on/caching_spec.rb +1 -0
  32. data/spec/acts_as_taggable_on/default_parser_spec.rb +47 -0
  33. data/spec/acts_as_taggable_on/generic_parser_spec.rb +14 -0
  34. data/spec/acts_as_taggable_on/related_spec.rb +1 -0
  35. data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +1 -0
  36. data/spec/acts_as_taggable_on/tag_list_parser_spec.rb +46 -0
  37. data/spec/acts_as_taggable_on/tag_list_spec.rb +23 -31
  38. data/spec/acts_as_taggable_on/tag_spec.rb +54 -38
  39. data/spec/acts_as_taggable_on/taggable/dirty_spec.rb +127 -0
  40. data/spec/acts_as_taggable_on/taggable_spec.rb +84 -164
  41. data/spec/acts_as_taggable_on/tagger_spec.rb +1 -1
  42. data/spec/acts_as_taggable_on/tagging_spec.rb +37 -1
  43. data/spec/acts_as_taggable_on/tags_helper_spec.rb +1 -0
  44. data/spec/acts_as_taggable_on/utils_spec.rb +6 -11
  45. data/spec/internal/app/models/cached_model_with_array.rb +1 -1
  46. data/spec/internal/app/models/models.rb +2 -2
  47. data/spec/internal/db/schema.rb +2 -2
  48. data/spec/spec_helper.rb +0 -1
  49. data/spec/support/0-helpers.rb +32 -0
  50. data/spec/support/database_cleaner.rb +4 -0
  51. metadata +29 -52
  52. data/spec/bm.rb +0 -52
  53. data/spec/schema.rb +0 -82
  54. /data/lib/acts_as_taggable_on/{acts_as_taggable_on/compatibility.rb → compatibility.rb} +0 -0
  55. /data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/dirty.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bbd5e8b1bc5588e5fa1f7c52d650d51284426c46
4
- data.tar.gz: 8310137e6ed880ac050af6a67e0afb648720c0a8
3
+ metadata.gz: 1d8fbbfcf90748ab7a565ca2d911de6cff93a5d6
4
+ data.tar.gz: bcdadfcc7559b5d1e1cbe41214493366a700b6e6
5
5
  SHA512:
6
- metadata.gz: 1ba873f7c016fac3ddbbad4f8ff7b946bb7ffca89074b4db76f63d58c241e01726d18fcd502a7e60fe31b635f6f1fae5d5c26dce911211db07a9c8506e07d13b
7
- data.tar.gz: 098fd2268afe38cd7278a8908e6c11b1aeba8370754224730510d71a336130b89831051640fac2af432171c09f51e346b18c141e2d97553a68efc680a6afa680
6
+ metadata.gz: 8af6b4c5ca019197c14bf67980889f0639f61fd7d53333316b6202d9c00bbbac3533bb77a6b055706c13f24102ed8d30064675dd4609f932a3413a54dbd7e674
7
+ data.tar.gz: 103300024612ce7fd41600b58158aa05edee3c672cec7c611bdab5bdacb7d98b59aa78e7c0418e753b990c9be6962da56a5b4acf999dbbf5047f9d2aadc26ab2
data/.travis.yml CHANGED
@@ -3,15 +3,19 @@ rvm:
3
3
  - 2.0.0
4
4
  - 2.1.1
5
5
  - rbx-2
6
+ - ruby-head
7
+
6
8
  env:
7
9
  - DB=sqlite3
8
10
  - DB=mysql
9
11
  - DB=postgresql
12
+
10
13
  gemfile:
11
14
  - gemfiles/activerecord_3.2.gemfile
12
15
  - gemfiles/activerecord_4.0.gemfile
13
16
  - gemfiles/activerecord_4.1.gemfile
14
17
  - gemfiles/activerecord_edge.gemfile
18
+
15
19
  cache: bundler
16
20
  script: bundle exec rake
17
21
  before_install: gem install bundler
@@ -20,4 +24,20 @@ matrix:
20
24
  fast_finish: true
21
25
  allow_failures:
22
26
  - gemfile: gemfiles/activerecord_edge.gemfile
23
- - rvm: rbx-2
27
+ - rvm: rbx-2
28
+ - rvm: ruby-head
29
+ exclude:
30
+ - rvm: 1.9.3
31
+ gemfile: gemfiles/activerecord_4.0.gemfile
32
+ - rvm: 1.9.3
33
+ gemfile: gemfiles/activerecord_4.1.gemfile
34
+ - rvm: 1.9.3
35
+ gemfile: gemfiles/activerecord_edge.gemfile
36
+ - rvm: rbx-2
37
+ gemfile: gemfiles/activerecord_3.2.gemfile
38
+ - rvm: ruby-head
39
+ gemfile: gemfiles/activerecord_3.2.gemfile
40
+ - rvm: ruby-head
41
+ gemfile: gemfiles/activerecord_4.0.gemfile
42
+ - rvm: ruby-head
43
+ gemfile: gemfiles/activerecord_4.1.gemfile
data/Appraisals CHANGED
@@ -1,20 +1,22 @@
1
1
  appraise "activerecord-3.2" do
2
2
  gem "activerecord", "~> 3.2"
3
- gem "actionpack", "~> 3.2"
4
3
  end
5
4
 
6
5
  appraise "activerecord-4.0" do
7
- gem "activerecord", "~> 4.0"
8
- gem "actionpack", "~> 4.0"
6
+ gem "activerecord", "~> 4.0.0"
9
7
  end
10
8
 
11
9
  appraise "activerecord-4.1" do
12
- gem "activerecord", "~> 4.1"
13
- gem "actionpack", "~> 4.1"
10
+ gem "activerecord", "~> 4.1.0"
11
+ end
12
+
13
+ appraise "activerecord-4.2" do
14
+ gem "railties", ">= 4.2.0.beta1"
15
+ gem "activerecord", ">= 4.2.0.beta1"
16
+ gem "rack", ">= 1.6.0.beta"
14
17
  end
15
18
 
16
19
  appraise "activerecord-edge" do
17
20
  gem "activerecord", github: "rails/rails"
18
- gem "actionpack", github: "rails/rails"
19
21
  gem 'arel', github: 'rails/arel'
20
22
  end
data/CHANGELOG.md CHANGED
@@ -4,21 +4,110 @@ Each change should fall into categories that would affect whether the release is
4
4
 
5
5
  As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch. And _misc_ is either minor or patch, the difference being kind of fuzzy for the purposes of history. Adding tests would be patch level.
6
6
 
7
- ### Master [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.1.0...master)
7
+ ### Master [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.0...master)
8
+
9
+ * Breaking Changes
10
+ * Features
11
+ * Fixes
12
+ * Performance
13
+ * Misc
14
+
15
+ ### [3.4.0 / 2014-08-29](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.3.0...v3.4.0)
16
+
17
+ * Features
18
+ * [@ProGM Support for custom parsers for tags](https://github.com/mbleigh/acts-as-taggable-on/pull/579)
19
+ * [@damzcodes #577 Popular feature](https://github.com/mbleigh/acts-as-taggable-on/pull/577)
20
+ * Fixes
21
+ * [@twalpole Update for rails edge (4.2)](https://github.com/mbleigh/acts-as-taggable-on/pull/583)
22
+ * Performance
23
+ * [@dontfidget #587 Use pluck instead of select](https://github.com/mbleigh/acts-as-taggable-on/pull/587)
24
+
25
+ ### [3.3.0 / 2014-07-08](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.2.6...v3.3.0)
8
26
 
9
- * Breaking Changes
10
27
  * Features
11
- * [@chess #413 Hook to support STI subclasses of Tag in save_tags](https://github.com/mbleigh/acts-as-taggable-on/pull/413)
28
+ * [@felipeclopes #488 Support for `start_at` and `end_at` restrictions when selecting tags](https://github.com/mbleigh/acts-as-taggable-on/pull/488)
29
+
12
30
  * Fixes
13
- * [@jdelStrother #515 Rename Compatibility methods to reduce chance of conflicts ](https://github.com/mbleigh/acts-as-taggable-on/pull/515)
14
- * [@seuros #512 fix for << method](https://github.com/mbleigh/acts-as-taggable-on/pull/512)
15
- * [@sonots #510 fix IN subquery error for mysql](https://github.com/mbleigh/acts-as-taggable-on/pull/510)
16
- * [@jonseaberg #499 fix for race condition when multiple processes try to add the same tag](https://github.com/mbleigh/acts-as-taggable-on/pull/499)
17
- * [@leklund #496 Fix for distinct and postgresql json columns errors](https://github.com/mbleigh/acts-as-taggable-on/pull/496)
18
- * [@thatbettina & @plexus #394 Multiple quoted tags](https://github.com/mbleigh/acts-as-taggable-on/pull/496)
31
+ * [@tonytonyjan #560 Fix for `ActsAsTaggableOn.remove_unused_tags` doesn't work](https://github.com/mbleigh/acts-as-taggable-on/pull/560)
32
+ * [@ThearkInn #555 Fix for `tag_cloud` helper to generate correct css tags](https://github.com/mbleigh/acts-as-taggable-on/pull/555)
33
+
19
34
  * Performance
35
+ * [@pcai #556 Add back taggables index in the taggins table](https://github.com/mbleigh/acts-as-taggable-on/pull/556)
36
+
37
+
38
+ ### [3.2.6 / 2014-05-28](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.2.5...v3.2.6)
39
+
40
+ * Fixes
41
+ * [@seuros #548 Fix dirty marking when tags are not ordered](https://github.com/mbleigh/acts-as-taggable-on/issues/548)
42
+
43
+ * Misc
44
+ * [@seuros Remove actionpack dependency](https://github.com/mbleigh/acts-as-taggable-on/commit/5d20e0486c892fbe21af42fdcd79d0b6ebe87ed4)
45
+ * [@seuros #547 Add tests for update_attributes](https://github.com/mbleigh/acts-as-taggable-on/issues/547)
46
+
47
+
48
+ ### [3.2.5 / 2014-05-25](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.2.4...v3.2.5)
49
+
50
+ * Fixes
51
+ * [@seuros #546 Fix autoload bug. Now require engine file instead of autoloading it](https://github.com/mbleigh/acts-as-taggable-on/issues/546)
52
+
53
+
54
+ ### [3.2.4 / 2014-05-24](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.2.3...v3.2.4)
55
+
56
+ * Fixes
57
+ * [@seuros #544 Fix incorrect query generation related to `GROUP BY` SQL statement](https://github.com/mbleigh/acts-as-taggable-on/issues/544)
58
+
59
+ * Misc
60
+ * [@seuros #545 Remove `ammeter` development dependency](https://github.com/mbleigh/acts-as-taggable-on/pull/545)
61
+ * [@seuros #545 Deprecate `TagList.from` in favor of `TagListParser.parse`](https://github.com/mbleigh/acts-as-taggable-on/pull/545)
62
+ * [@seuros #543 Introduce lazy loading](https://github.com/mbleigh/acts-as-taggable-on/pull/543)
63
+ * [@seuros #541 Deprecate ActsAsTaggableOn::Utils](https://github.com/mbleigh/acts-as-taggable-on/pull/541)
64
+
65
+
66
+ ### [3.2.3 / 2014-05-16](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.2.2...v3.2.3)
67
+
68
+ * Fixes
69
+ * [@seuros #540 Fix for tags removal (it was affecting all records with the same tag)](https://github.com/mbleigh/acts-as-taggable-on/pull/540)
70
+ * [@akcho8 #535 Fix for `options` Hash passed to methods from being deleted by those methods](https://github.com/mbleigh/acts-as-taggable-on/pull/535)
71
+
72
+
73
+ ### [3.2.2 / 2014-05-07](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.2.1...v3.2.2)
74
+
75
+ * Breaking Changes
76
+ * [@seuros #526 Taggable models are not extended with ActsAsTaggableOn::Utils anymore](https://github.com/mbleigh/acts-as-taggable-on/pull/526)
77
+
78
+ * Fixes
79
+ * [@seuros #536 Add explicit conversion of tags to strings (when assigning tags)](https://github.com/mbleigh/acts-as-taggable-on/pull/536)
80
+
81
+ * Misc
82
+ * [@seuros #526 Delete outdated benchmark script](https://github.com/mbleigh/acts-as-taggable-on/pull/526)
83
+ * [@seuros #525 Fix tests so that they pass with MySQL](https://github.com/mbleigh/acts-as-taggable-on/pull/525)
84
+
85
+
86
+ ### [3.2.1 / 2014-05-06](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.2.0...v3.2.1)
87
+
20
88
  * Misc
21
- * [@seuros #511 Rspec 3](https://github.com/mbleigh/acts-as-taggable-on/pull/511)
89
+ * [@seuros #523 Run tests loading only ActiveRecord (without the full Rails stack)](https://github.com/mbleigh/acts-as-taggable-on/pull/523)
90
+ * [@seuros #523 Remove activesupport dependency](https://github.com/mbleigh/acts-as-taggable-on/pull/523)
91
+ * [@seuros #523 Introduce database_cleaner in specs](https://github.com/mbleigh/acts-as-taggable-on/pull/523)
92
+ * [@seuros #520 Tag_list cleanup](https://github.com/mbleigh/acts-as-taggable-on/pull/520)
93
+
94
+
95
+ ### [3.2.0 / 2014-05-01](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.1.1...v3.2.0)
96
+
97
+ * Breaking Changes
98
+ * ActsAsTaggableOn::Tag is not extend with ActsAsTaggableOn::Utils anymore
99
+ * Features
100
+ * [@chess #413 Hook to support STI subclasses of Tag in save_tags](https://github.com/mbleigh/acts-as-taggable-on/pull/413)
101
+ * Fixes
102
+ * [@jdelStrother #515 Rename Compatibility methods to reduce chance of conflicts ](https://github.com/mbleigh/acts-as-taggable-on/pull/515)
103
+ * [@seuros #512 fix for << method](https://github.com/mbleigh/acts-as-taggable-on/pull/512)
104
+ * [@sonots #510 fix IN subquery error for mysql](https://github.com/mbleigh/acts-as-taggable-on/pull/510)
105
+ * [@jonseaberg #499 fix for race condition when multiple processes try to add the same tag](https://github.com/mbleigh/acts-as-taggable-on/pull/499)
106
+ * [@leklund #496 Fix for distinct and postgresql json columns errors](https://github.com/mbleigh/acts-as-taggable-on/pull/496)
107
+ * [@thatbettina & @plexus #394 Multiple quoted tags](https://github.com/mbleigh/acts-as-taggable-on/pull/496)
108
+ * Performance
109
+ * Misc
110
+ * [@seuros #511 Rspec 3](https://github.com/mbleigh/acts-as-taggable-on/pull/511)
22
111
 
23
112
  ### [3.1.0 / 2014-03-31](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.0.1...v3.1.0)
24
113
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # ActsAsTaggableOn
2
2
  [![Build Status](https://secure.travis-ci.org/mbleigh/acts-as-taggable-on.png)](http://travis-ci.org/mbleigh/acts-as-taggable-on)
3
3
  [![Code Climate](https://codeclimate.com/github/mbleigh/acts-as-taggable-on.png)](https://codeclimate.com/github/mbleigh/acts-as-taggable-on)
4
- [![Inline docs](http://inch-pages.github.io/github/mbleigh/acts-as-taggable-on.png)](http://inch-pages.github.io/github/mbleigh/acts-as-taggable-on)
4
+ [![Inline docs](http://inch-ci.org/github/mbleigh/acts-as-taggable-on.png)](http://inch-ci.org/github/mbleigh/acts-as-taggable-on)
5
5
 
6
6
  This plugin was originally based on Acts as Taggable on Steroids by Jonathan Viney.
7
7
  It has evolved substantially since that point, but all credit goes to him for the
@@ -70,6 +70,12 @@ class User < ActiveRecord::Base
70
70
  acts_as_taggable_on :skills, :interests
71
71
  end
72
72
 
73
+ class UsersController < ApplicationController
74
+ def user_params
75
+ params.require(:user).permit(:name, :tag_list) ## Rails 4 strong params usage
76
+ end
77
+ end
78
+
73
79
  @user = User.new(:name => "Bobby")
74
80
  ```
75
81
 
@@ -135,11 +141,13 @@ these methods are added to the model: `skill_list`(and `skill_list.add`, `skill_
135
141
  # => ["joking", "clowning", "boxing", "coding"]
136
142
 
137
143
  @another_user = User.new(:name => "Alice")
138
- @another_story.skill_list.add("joking")
139
- @another_story.save
144
+ @another_user.skill_list.add("clowning")
145
+ @another_user.save
140
146
 
141
147
  User.skill_counts
142
- => [#<ActsAsTaggableOn::Tag id: 1, name: "joking", taggings_count: 2>, #<ActsAsTaggableOn::Tag id: 2, name: "clowning", taggings_count: 1>, ...]
148
+ => [#<ActsAsTaggableOn::Tag id: 1, name: "joking", taggings_count: 1>,
149
+ #<ActsAsTaggableOn::Tag id: 2, name: "clowning", taggings_count: 2>,
150
+ #<ActsAsTaggableOn::Tag id: 3, name: "boxing", taggings_count: 1>]
143
151
  ```
144
152
 
145
153
  To preserve the order in which tags are created use `acts_as_ordered_taggable`:
@@ -162,6 +170,22 @@ end
162
170
  @user.tag_list # => ["north", "east", "south", "west"]
163
171
  ```
164
172
 
173
+ ### Finding most or least used tags
174
+
175
+ You can find the most or least used tags by using:
176
+
177
+ ```ruby
178
+ ActsAsTaggableOn::Tag.most_used
179
+ ActsAsTaggableOn::Tag.least_used
180
+ ```
181
+
182
+ You can also filter the results by passing the method a limit, however the default limit is 50.
183
+
184
+ ```ruby
185
+ ActsAsTaggableOn::Tag.most_used(10)
186
+ ActsAsTaggableOn::Tag.least_used(10)
187
+ ```
188
+
165
189
  ### Finding Tagged Objects
166
190
 
167
191
  Acts As Taggable On uses scopes to create an association for tags.
@@ -176,22 +200,23 @@ end
176
200
  User.tagged_with("awesome").by_join_date
177
201
  User.tagged_with("awesome").by_join_date.paginate(:page => params[:page], :per_page => 20)
178
202
 
179
- # Find a user with matching all tags, not just one:
203
+ # Find users that matches all given tags:
180
204
  User.tagged_with(["awesome", "cool"], :match_all => true)
181
205
 
182
- # Find a user with any of the tags:
206
+ # Find users with any of the specified tags:
183
207
  User.tagged_with(["awesome", "cool"], :any => true)
184
208
 
185
- # Find a user that not tags with awesome or cool:
209
+ # Find users that has not been tagged with awesome or cool:
186
210
  User.tagged_with(["awesome", "cool"], :exclude => true)
187
211
 
188
- # Find a user with any of tags based on context:
212
+ # Find users with any of the tags based on context:
189
213
  User.tagged_with(['awesome', 'cool'], :on => :tags, :any => true).tagged_with(['smart', 'shy'], :on => :skills, :any => true)
190
214
  ```
191
215
 
192
- You can also use `:wild => true` option along with `:any` or `:exclude` option. It will looking for `%awesome%` and `%cool%` in sql.
216
+ You can also use `:wild => true` option along with `:any` or `:exclude` option. It will be looking for `%awesome%` and `%cool%` in SQL.
217
+
218
+ __Tip:__ `User.tagged_with([])` or `User.tagged_with('')` will return `[]`, an empty set of records.
193
219
 
194
- __Tip:__ `User.tagged_with([])` or `User.tagged_with('')` will return `[]`, but not all records.
195
220
 
196
221
  ### Relationships
197
222
 
@@ -229,6 +254,43 @@ to allow for dynamic tag contexts (this could be user generated tag contexts!)
229
254
  User.tagged_with("same", :on => :customs) # => [@user]
230
255
  ```
231
256
 
257
+ ### Tag Parsers
258
+
259
+ If you want to change how tags are parsed, you can define a your own implementation:
260
+
261
+ ```ruby
262
+ class MyParser < ActsAsTaggableOn::GenericParser
263
+ def parse
264
+ TagList.new.tap do |tag_list|
265
+ tag_list.add @tag_list.split('|')
266
+ end
267
+ end
268
+ end
269
+ ```
270
+
271
+ Now you can use this parser, passing it as parameter:
272
+
273
+ ```ruby
274
+ @user = User.new(:name => "Bobby")
275
+ @user.tag_list = "east, south"
276
+ @user.tag_list.add("north|west", parser: MyParser)
277
+ @user.tag_list # => ["north", "east", "south", "west"]
278
+
279
+ # Or also:
280
+ @user.tag_list.parser = MyParser
281
+ @user.tag_list.add("north|west")
282
+ @user.tag_list # => ["north", "east", "south", "west"]
283
+ ```
284
+
285
+ Or change it globally:
286
+
287
+ ```ruby
288
+ ActsAsTaggable.default_parser = MyParser
289
+ @user = User.new(:name => "Bobby")
290
+ @user.tag_list = "east|south"
291
+ @user.tag_list # => ["east", "south"]
292
+ ```
293
+
232
294
  ### Tag Ownership
233
295
 
234
296
  Tags can have owners:
@@ -273,7 +335,7 @@ Photo.tagged_with("paris", :on => :locations, :owned_by => @some_user)
273
335
  To construct tag clouds, the frequency of each tag needs to be calculated.
274
336
  Because we specified `acts_as_taggable_on` on the `User` class, we can
275
337
  get a calculation of all the tag counts by using `User.tag_counts_on(:customs)`. But what if we wanted a tag count for
276
- an single user's posts? To achieve this we call tag_counts on the association:
338
+ a single user's posts? To achieve this we call tag_counts on the association:
277
339
 
278
340
  ```ruby
279
341
  User.find(:first).posts.tag_counts_on(:tags)
@@ -360,6 +422,11 @@ We have a long list of valued contributors. [Check them all](https://github.com/
360
422
 
361
423
  * [Joost Baaij](https://github.com/tilsammans)
362
424
 
425
+ ## TODO
426
+
427
+ - Write benchmark script
428
+ - Resolve concurrency issues
429
+
363
430
  ## Testing
364
431
 
365
432
  Acts As Taggable On uses RSpec for its test coverage. Inside the gem
@@ -22,17 +22,15 @@ Gem::Specification.new do |gem|
22
22
  gem.post_install_message = File.read('UPGRADING.md')
23
23
  end
24
24
 
25
- gem.add_runtime_dependency 'activerecord', ['>= 3', '< 5']
26
- gem.add_runtime_dependency 'actionpack', ['>= 3', '< 5']
25
+ gem.add_runtime_dependency 'activerecord', ['>= 3.2', '< 5']
27
26
 
28
27
  gem.add_development_dependency 'sqlite3'
29
28
  gem.add_development_dependency 'mysql2', '~> 0.3.7'
30
29
  gem.add_development_dependency 'pg'
31
30
 
32
- gem.add_development_dependency 'rspec-rails' , '~> 3.0.0.beta'
31
+ gem.add_development_dependency 'rspec-rails'
33
32
  gem.add_development_dependency 'rspec-its'
34
33
  gem.add_development_dependency 'rspec'
35
- gem.add_development_dependency 'ammeter'
36
34
  gem.add_development_dependency 'barrier'
37
35
  gem.add_development_dependency 'database_cleaner'
38
36
  end
@@ -0,0 +1,9 @@
1
+ class AddMissingTaggableIndex < ActiveRecord::Migration
2
+ def self.up
3
+ add_index :taggings, [:taggable_id, :taggable_type, :context]
4
+ end
5
+
6
+ def self.down
7
+ remove_index :taggings, [:taggable_id, :taggable_type, :context]
8
+ end
9
+ end
@@ -3,7 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "activerecord", "~> 3.2"
6
- gem "actionpack", "~> 3.2"
7
6
 
8
7
  group :local_development do
9
8
  gem "guard"
@@ -2,8 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 4.0"
6
- gem "actionpack", "~> 4.0"
5
+ gem "activerecord", "~> 4.0.0"
7
6
 
8
7
  group :local_development do
9
8
  gem "guard"
@@ -2,8 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 4.1"
6
- gem "actionpack", "~> 4.1"
5
+ gem "activerecord", "~> 4.1.0"
7
6
 
8
7
  group :local_development do
9
8
  gem "guard"
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "railties", ">= 4.2.0.beta1"
6
+ gem "activerecord", ">= 4.2.0.beta1"
7
+ gem "rack", ">= 1.6.0.beta"
8
+
9
+ group :local_development do
10
+ gem "guard"
11
+ gem "guard-rspec"
12
+ gem "appraisal"
13
+ gem "rake"
14
+ end
15
+
16
+ gemspec :path => "../"
@@ -3,7 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "activerecord", :github => "rails/rails"
6
- gem "actionpack", :github => "rails/rails"
7
6
  gem "arel", :github => "rails/arel"
8
7
 
9
8
  group :local_development do
@@ -1,11 +1,38 @@
1
1
  require 'active_record'
2
2
  require 'active_record/version'
3
3
  require 'active_support/core_ext/module'
4
- require 'action_view'
4
+
5
+ require_relative 'acts_as_taggable_on/engine' if defined?(Rails)
5
6
 
6
7
  require 'digest/sha1'
7
8
 
8
9
  module ActsAsTaggableOn
10
+ extend ActiveSupport::Autoload
11
+
12
+ autoload :Tag
13
+ autoload :TagList
14
+ autoload :GenericParser
15
+ autoload :DefaultParser
16
+ autoload :TagListParser
17
+ autoload :Taggable
18
+ autoload :Tagger
19
+ autoload :Tagging
20
+ autoload :TagsHelper
21
+ autoload :VERSION
22
+
23
+ autoload_under 'taggable' do
24
+ autoload :Cache
25
+ autoload :Collection
26
+ autoload :Core
27
+ autoload :Dirty
28
+ autoload :Ownership
29
+ autoload :Related
30
+ end
31
+
32
+ autoload :Utils
33
+ autoload :Compatibility
34
+
35
+
9
36
  class DuplicateTagError < StandardError
10
37
  end
11
38
 
@@ -16,7 +43,7 @@ module ActsAsTaggableOn
16
43
 
17
44
  def self.method_missing(method_name, *args, &block)
18
45
  @configuration.respond_to?(method_name) ?
19
- @configuration.send(method_name, *args, &block) : super
46
+ @configuration.send(method_name, *args, &block) : super
20
47
  end
21
48
 
22
49
  def self.respond_to?(method_name, include_private=false)
@@ -31,7 +58,7 @@ module ActsAsTaggableOn
31
58
 
32
59
  class Configuration
33
60
  attr_accessor :delimiter, :force_lowercase, :force_parameterize,
34
- :strict_case_match, :remove_unused_tags
61
+ :strict_case_match, :remove_unused_tags, :default_parser
35
62
 
36
63
  def initialize
37
64
  @delimiter = ','
@@ -39,30 +66,22 @@ module ActsAsTaggableOn
39
66
  @force_parameterize = false
40
67
  @strict_case_match = false
41
68
  @remove_unused_tags = false
69
+ @default_parser = DefaultParser
70
+ end
71
+
72
+ def delimiter=(string)
73
+ ActiveRecord::Base.logger.warn <<WARNING
74
+ ActsAsTaggableOn.delimiter is deprecated \
75
+ and will be removed from v4.0+, use \
76
+ a ActsAsTaggableOn.default_parser instead
77
+ WARNING
78
+ @delimiter = string
42
79
  end
43
80
  end
44
81
 
45
82
  setup
46
83
  end
47
84
 
48
- require 'acts_as_taggable_on/utils'
49
-
50
- require 'acts_as_taggable_on/taggable'
51
- require 'acts_as_taggable_on/acts_as_taggable_on/compatibility'
52
- require 'acts_as_taggable_on/acts_as_taggable_on/core'
53
- require 'acts_as_taggable_on/acts_as_taggable_on/collection'
54
- require 'acts_as_taggable_on/acts_as_taggable_on/cache'
55
- require 'acts_as_taggable_on/acts_as_taggable_on/ownership'
56
- require 'acts_as_taggable_on/acts_as_taggable_on/related'
57
- require 'acts_as_taggable_on/acts_as_taggable_on/dirty'
58
-
59
- require 'acts_as_taggable_on/tagger'
60
- require 'acts_as_taggable_on/tag'
61
- require 'acts_as_taggable_on/tag_list'
62
- require 'acts_as_taggable_on/tags_helper'
63
- require 'acts_as_taggable_on/tagging'
64
- require 'acts_as_taggable_on/engine'
65
-
66
85
  ActiveSupport.on_load(:active_record) do
67
86
  extend ActsAsTaggableOn::Compatibility
68
87
  extend ActsAsTaggableOn::Taggable
@@ -0,0 +1,79 @@
1
+ module ActsAsTaggableOn
2
+ ##
3
+ # Returns a new TagList using the given tag string.
4
+ #
5
+ # Example:
6
+ # tag_list = ActsAsTaggableOn::DefaultParser.parse("One , Two, Three")
7
+ # tag_list # ["One", "Two", "Three"]
8
+ class DefaultParser < GenericParser
9
+
10
+ def parse
11
+ string = @tag_list
12
+
13
+ string = string.join(ActsAsTaggableOn.glue) if string.respond_to?(:join)
14
+ TagList.new.tap do |tag_list|
15
+ string = string.to_s.dup
16
+
17
+ string.gsub!(double_quote_pattern) {
18
+ # Append the matched tag to the tag list
19
+ tag_list << Regexp.last_match[2]
20
+ # Return the matched delimiter ($3) to replace the matched items
21
+ ''
22
+ }
23
+
24
+ string.gsub!(single_quote_pattern) {
25
+ # Append the matched tag ($2) to the tag list
26
+ tag_list << Regexp.last_match[2]
27
+ # Return an empty string to replace the matched items
28
+ ''
29
+ }
30
+
31
+ # split the string by the delimiter
32
+ # and add to the tag_list
33
+ tag_list.add(string.split(Regexp.new delimiter))
34
+ end
35
+ end
36
+
37
+
38
+ # private
39
+ def delimiter
40
+ # Parse the quoted tags
41
+ d = ActsAsTaggableOn.delimiter
42
+ # Separate multiple delimiters by bitwise operator
43
+ d = d.join('|') if d.kind_of?(Array)
44
+ d
45
+ end
46
+
47
+ # ( # Tag start delimiter ($1)
48
+ # \A | # Either string start or
49
+ # #{delimiter} # a delimiter
50
+ # )
51
+ # \s*" # quote (") optionally preceded by whitespace
52
+ # (.*?) # Tag ($2)
53
+ # "\s* # quote (") optionally followed by whitespace
54
+ # (?= # Tag end delimiter (not consumed; is zero-length lookahead)
55
+ # #{delimiter}\s* | # Either a delimiter optionally followed by whitespace or
56
+ # \z # string end
57
+ # )
58
+ def double_quote_pattern
59
+ /(\A|#{delimiter})\s*"(.*?)"\s*(?=#{delimiter}\s*|\z)/
60
+ end
61
+
62
+ # ( # Tag start delimiter ($1)
63
+ # \A | # Either string start or
64
+ # #{delimiter} # a delimiter
65
+ # )
66
+ # \s*' # quote (') optionally preceded by whitespace
67
+ # (.*?) # Tag ($2)
68
+ # '\s* # quote (') optionally followed by whitespace
69
+ # (?= # Tag end delimiter (not consumed; is zero-length lookahead)
70
+ # #{delimiter}\s* | d # Either a delimiter optionally followed by whitespace or
71
+ # \z # string end
72
+ # )
73
+ def single_quote_pattern
74
+ /(\A|#{delimiter})\s*'(.*?)'\s*(?=#{delimiter}\s*|\z)/
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,19 @@
1
+ module ActsAsTaggableOn
2
+ ##
3
+ # Returns a new TagList using the given tag string.
4
+ #
5
+ # Example:
6
+ # tag_list = ActsAsTaggableOn::GenericParser.new.parse("One , Two, Three")
7
+ # tag_list # ["One", "Two", "Three"]
8
+ class GenericParser
9
+ def initialize(tag_list)
10
+ @tag_list = tag_list
11
+ end
12
+
13
+ def parse
14
+ TagList.new.tap do |tag_list|
15
+ tag_list.add @tag_list.split(',').map(&:strip).reject(&:empty?)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # encoding: utf-8
2
2
  module ActsAsTaggableOn
3
3
  class Tag < ::ActiveRecord::Base
4
4
 
@@ -20,6 +20,8 @@ module ActsAsTaggableOn
20
20
  end
21
21
 
22
22
  ### SCOPES:
23
+ scope :most_used, ->(limit = 20) { order('taggings_count desc').limit(limit) }
24
+ scope :least_used, ->(limit = 20) { order('taggings_count asc').limit(limit) }
23
25
 
24
26
  def self.named(name)
25
27
  if ActsAsTaggableOn.strict_case_match
@@ -101,6 +103,9 @@ module ActsAsTaggableOn
101
103
  end
102
104
 
103
105
  class << self
106
+
107
+
108
+
104
109
  private
105
110
 
106
111
  def comparable_name(str)