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.
- checksums.yaml +4 -4
- data/.travis.yml +21 -1
- data/Appraisals +8 -6
- data/CHANGELOG.md +99 -10
- data/README.md +78 -11
- data/acts-as-taggable-on.gemspec +2 -4
- data/db/migrate/4_add_missing_taggable_index.rb +9 -0
- data/gemfiles/activerecord_3.2.gemfile +0 -1
- data/gemfiles/activerecord_4.0.gemfile +1 -2
- data/gemfiles/activerecord_4.1.gemfile +1 -2
- data/gemfiles/activerecord_4.2.gemfile +16 -0
- data/gemfiles/activerecord_edge.gemfile +0 -1
- data/lib/acts-as-taggable-on.rb +40 -21
- data/lib/acts_as_taggable_on/default_parser.rb +79 -0
- data/lib/acts_as_taggable_on/generic_parser.rb +19 -0
- data/lib/acts_as_taggable_on/tag.rb +6 -1
- data/lib/acts_as_taggable_on/tag_list.rb +20 -79
- data/lib/acts_as_taggable_on/tag_list_parser.rb +21 -0
- data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/cache.rb +1 -0
- data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/collection.rb +3 -1
- data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/core.rb +87 -51
- data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/ownership.rb +1 -1
- data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/related.rb +6 -6
- data/lib/acts_as_taggable_on/taggable.rb +7 -8
- data/lib/acts_as_taggable_on/tagging.rb +7 -1
- data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
- data/lib/acts_as_taggable_on/utils.rb +26 -50
- data/lib/acts_as_taggable_on/version.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +1 -0
- data/spec/acts_as_taggable_on/caching_spec.rb +1 -0
- data/spec/acts_as_taggable_on/default_parser_spec.rb +47 -0
- data/spec/acts_as_taggable_on/generic_parser_spec.rb +14 -0
- data/spec/acts_as_taggable_on/related_spec.rb +1 -0
- data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +1 -0
- data/spec/acts_as_taggable_on/tag_list_parser_spec.rb +46 -0
- data/spec/acts_as_taggable_on/tag_list_spec.rb +23 -31
- data/spec/acts_as_taggable_on/tag_spec.rb +54 -38
- data/spec/acts_as_taggable_on/taggable/dirty_spec.rb +127 -0
- data/spec/acts_as_taggable_on/taggable_spec.rb +84 -164
- data/spec/acts_as_taggable_on/tagger_spec.rb +1 -1
- data/spec/acts_as_taggable_on/tagging_spec.rb +37 -1
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +1 -0
- data/spec/acts_as_taggable_on/utils_spec.rb +6 -11
- data/spec/internal/app/models/cached_model_with_array.rb +1 -1
- data/spec/internal/app/models/models.rb +2 -2
- data/spec/internal/db/schema.rb +2 -2
- data/spec/spec_helper.rb +0 -1
- data/spec/support/0-helpers.rb +32 -0
- data/spec/support/database_cleaner.rb +4 -0
- metadata +29 -52
- data/spec/bm.rb +0 -52
- data/spec/schema.rb +0 -82
- /data/lib/acts_as_taggable_on/{acts_as_taggable_on/compatibility.rb → compatibility.rb} +0 -0
- /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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d8fbbfcf90748ab7a565ca2d911de6cff93a5d6
|
|
4
|
+
data.tar.gz: bcdadfcc7559b5d1e1cbe41214493366a700b6e6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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.
|
|
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
|
-
* [@
|
|
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
|
-
* [@
|
|
14
|
-
* [@
|
|
15
|
-
|
|
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 #
|
|
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
|
[](http://travis-ci.org/mbleigh/acts-as-taggable-on)
|
|
3
3
|
[](https://codeclimate.com/github/mbleigh/acts-as-taggable-on)
|
|
4
|
-
[](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
|
-
@
|
|
139
|
-
@
|
|
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:
|
|
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
|
|
203
|
+
# Find users that matches all given tags:
|
|
180
204
|
User.tagged_with(["awesome", "cool"], :match_all => true)
|
|
181
205
|
|
|
182
|
-
# Find
|
|
206
|
+
# Find users with any of the specified tags:
|
|
183
207
|
User.tagged_with(["awesome", "cool"], :any => true)
|
|
184
208
|
|
|
185
|
-
# Find
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
data/acts-as-taggable-on.gemspec
CHANGED
|
@@ -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'
|
|
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,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 => "../"
|
data/lib/acts-as-taggable-on.rb
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
require 'active_record'
|
|
2
2
|
require 'active_record/version'
|
|
3
3
|
require 'active_support/core_ext/module'
|
|
4
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
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)
|