mongoid-tag-collectible 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +48 -0
- data/.travis.yml +12 -1
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +118 -0
- data/Gemfile +13 -3
- data/README.md +10 -8
- data/Rakefile +5 -2
- data/examples/readme.rb +9 -5
- data/lib/mongoid-tag-collectible.rb +1 -0
- data/lib/mongoid-tag-collectible/mongoid.rb +15 -0
- data/lib/mongoid-tag-collectible/tag.rb +36 -33
- data/lib/mongoid-tag-collectible/tagged.rb +45 -28
- data/lib/mongoid-tag-collectible/version.rb +1 -1
- data/mongoid-tag-collectible.gemspec +9 -9
- data/spec/config/{mongoid.yml → mongoid3.yml} +0 -0
- data/spec/config/mongoid4.yml +8 -0
- data/spec/config/mongoid5.yml +8 -0
- data/spec/mongoid-tag-collectible/namespaced_tagged_spec.rb +39 -0
- data/spec/mongoid-tag-collectible/tag_spec.rb +76 -72
- data/spec/mongoid-tag-collectible/tagged_spec.rb +19 -19
- data/spec/mongoid-tag-collectible/version_spec.rb +2 -2
- data/spec/spec_helper.rb +3 -0
- data/spec/support/mongoid.rb +33 -7
- data/spec/support/namespaced_test_tagged.rb +9 -0
- data/spec/support/test_tagged.rb +2 -0
- metadata +23 -24
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f9915b934fae0ee5810a6d72b8106bd55dd29691
|
4
|
+
data.tar.gz: 72e63db41368654708207f18379b8bf1d0ce32ef
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0eda709bc5c84620606a643fcfea7e0747bbb5f4ffa3274864b6e79ad8907420831bf24fe84e0664c83ab176058fea1fe28de333be3780fbe5686da73da1424a
|
7
|
+
data.tar.gz: b36152f22e637be6508e260b02e9ac43482a1292c5d7b37058fbd2019cc0d7313dc6793a809f489fd3f88c201b775f6299b5131c8741b139d6b62566186ac1f9
|
data/.rubocop.yml
ADDED
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
+
# on 2015-07-07 09:21:20 -0400 using RuboCop version 0.32.1.
|
3
|
+
# The point is for the user to remove these configuration records
|
4
|
+
# one by one as the offenses are removed from the code base.
|
5
|
+
# Note that changes in the inspected code, or installation of new
|
6
|
+
# versions of RuboCop, may require this file to be generated again.
|
7
|
+
|
8
|
+
# Offense count: 1
|
9
|
+
Metrics/CyclomaticComplexity:
|
10
|
+
Max: 8
|
11
|
+
|
12
|
+
# Offense count: 14
|
13
|
+
# Configuration parameters: AllowURI, URISchemes.
|
14
|
+
Metrics/LineLength:
|
15
|
+
Max: 123
|
16
|
+
|
17
|
+
# Offense count: 1
|
18
|
+
# Configuration parameters: CountComments.
|
19
|
+
Metrics/MethodLength:
|
20
|
+
Max: 11
|
21
|
+
|
22
|
+
# Offense count: 1
|
23
|
+
Metrics/PerceivedComplexity:
|
24
|
+
Max: 8
|
25
|
+
|
26
|
+
# Offense count: 3
|
27
|
+
# Cop supports --auto-correct.
|
28
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
29
|
+
Style/BracesAroundHashParameters:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
# Offense count: 7
|
33
|
+
Style/Documentation:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
# Offense count: 1
|
37
|
+
Style/DoubleNegation:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
# Offense count: 1
|
41
|
+
# Configuration parameters: Exclude.
|
42
|
+
Style/FileName:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
# Offense count: 1
|
46
|
+
# Configuration parameters: MinBodyLength.
|
47
|
+
Style/GuardClause:
|
48
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
### 0.2.0 (08/12/2015)
|
2
|
+
|
3
|
+
* Implemented RuboCop, Ruby-style linter - [@dblock](https://github.com/dblock).
|
4
|
+
* Added support for Mongoid 4 and Mongoid 5 Beta - [@dblock](https://github.com/dblock).
|
5
|
+
* Added support for namespaced classes - [@dblock](https://github.com/dblock).
|
6
|
+
|
1
7
|
### 0.1.0 (06/26/2013)
|
2
8
|
|
3
9
|
* Initial public release, written on a plane from SF to NYC - [@dblock](https://github.com/dblock).
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
Contributing to Mongoid-Tag-Collectible
|
2
|
+
=======================================
|
3
|
+
|
4
|
+
Mongoid-Tag-Collectible is work of [many of contributors](https://github.com/dblock/mongoid-tag-collectible/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/dblock/mongoid-tag-collectible/pulls), [propose features, ask questions and discuss issues](https://github.com/dblock/mongoid-tag-collectible/issues).
|
5
|
+
|
6
|
+
#### Fork the Project
|
7
|
+
|
8
|
+
Fork the [project on Github](https://github.com/dblock/mongoid-tag-collectible) and check out your copy.
|
9
|
+
|
10
|
+
```
|
11
|
+
git clone https://github.com/contributor/mongoid-tag-collectible.git
|
12
|
+
cd mongoid-tag-collectible
|
13
|
+
git remote add upstream https://github.com/dblock/mongoid-tag-collectible.git
|
14
|
+
```
|
15
|
+
|
16
|
+
#### Create a Topic Branch
|
17
|
+
|
18
|
+
Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
|
19
|
+
|
20
|
+
```
|
21
|
+
git checkout master
|
22
|
+
git pull upstream master
|
23
|
+
git checkout -b my-feature-branch
|
24
|
+
```
|
25
|
+
|
26
|
+
#### Bundle Install and Test
|
27
|
+
|
28
|
+
Ensure that you can build the project and run tests.
|
29
|
+
|
30
|
+
```
|
31
|
+
bundle install
|
32
|
+
bundle exec rake
|
33
|
+
```
|
34
|
+
|
35
|
+
#### Write Tests
|
36
|
+
|
37
|
+
Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [spec/mongoid-tag-collectible](spec/mongoid-tag-collectible).
|
38
|
+
|
39
|
+
We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
|
40
|
+
|
41
|
+
#### Write Code
|
42
|
+
|
43
|
+
Implement your feature or bug fix.
|
44
|
+
|
45
|
+
Ruby style is enforced with [Rubocop](https://github.com/bbatsov/rubocop), run `bundle exec rubocop` and fix any style issues highlighted.
|
46
|
+
|
47
|
+
Make sure that `bundle exec rake` completes without errors.
|
48
|
+
|
49
|
+
#### Write Documentation
|
50
|
+
|
51
|
+
Document any external behavior in the [README](README.md).
|
52
|
+
|
53
|
+
#### Update Changelog
|
54
|
+
|
55
|
+
Add a line to [CHANGELOG](CHANGELOG.md) under *Next Release*. Make it look like every other line, including your name and link to your Github account.
|
56
|
+
|
57
|
+
#### Commit Changes
|
58
|
+
|
59
|
+
Make sure git knows your name and email address:
|
60
|
+
|
61
|
+
```
|
62
|
+
git config --global user.name "Your Name"
|
63
|
+
git config --global user.email "contributor@example.com"
|
64
|
+
```
|
65
|
+
|
66
|
+
Writing good commit logs is important. A commit log should describe what changed and why.
|
67
|
+
|
68
|
+
```
|
69
|
+
git add ...
|
70
|
+
git commit
|
71
|
+
```
|
72
|
+
|
73
|
+
#### Push
|
74
|
+
|
75
|
+
```
|
76
|
+
git push origin my-feature-branch
|
77
|
+
```
|
78
|
+
|
79
|
+
#### Make a Pull Request
|
80
|
+
|
81
|
+
Go to https://github.com/contributor/mongoid-tag-collectible and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days.
|
82
|
+
|
83
|
+
#### Rebase
|
84
|
+
|
85
|
+
If you've been working on a change for a while, rebase with upstream/master.
|
86
|
+
|
87
|
+
```
|
88
|
+
git fetch upstream
|
89
|
+
git rebase upstream/master
|
90
|
+
git push origin my-feature-branch -f
|
91
|
+
```
|
92
|
+
|
93
|
+
#### Update CHANGELOG Again
|
94
|
+
|
95
|
+
Update the [CHANGELOG](CHANGELOG.md) with the pull request number. A typical entry looks as follows.
|
96
|
+
|
97
|
+
```
|
98
|
+
* [#123](https://github.com/dblock/mongoid-tag-collectible/pull/123): Reticulated splines - [@contributor](https://github.com/contributor).
|
99
|
+
```
|
100
|
+
|
101
|
+
Amend your previous commit and force push the changes.
|
102
|
+
|
103
|
+
```
|
104
|
+
git commit --amend
|
105
|
+
git push origin my-feature-branch -f
|
106
|
+
```
|
107
|
+
|
108
|
+
#### Check on Your Pull Request
|
109
|
+
|
110
|
+
Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
|
111
|
+
|
112
|
+
#### Be Patient
|
113
|
+
|
114
|
+
It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there!
|
115
|
+
|
116
|
+
#### Thank You
|
117
|
+
|
118
|
+
Please do know that we really appreciate and value your time and work. We love you, really.
|
data/Gemfile
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
-
source
|
1
|
+
source 'http://rubygems.org'
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
case version = ENV['MONGOID_VERSION'] || '~> 4.0'
|
6
|
+
when /4/
|
7
|
+
gem 'mongoid', '~> 4.0'
|
8
|
+
when /3/
|
9
|
+
gem 'mongoid', '~> 3.1'
|
10
|
+
else
|
11
|
+
gem 'mongoid', version
|
12
|
+
end
|
13
|
+
|
14
|
+
gem 'rspec'
|
15
|
+
gem 'rake'
|
16
|
+
gem 'rubocop', '0.32.1'
|
data/README.md
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
Mongoid::TagCollectible
|
2
2
|
=======================
|
3
3
|
|
4
|
-
[![
|
4
|
+
[![Gem Version](http://img.shields.io/gem/v/mongoid-tag-collectible.svg)](http://badge.fury.io/rb/mongoid-tag-collectible)
|
5
|
+
[![Build Status](http://img.shields.io/travis/dblock/mongoid-tag-collectible.svg)](https://travis-ci.org/dblock/mongoid-tag-collectible)
|
6
|
+
[![Dependency Status](https://gemnasium.com/dblock/mongoid-tag-collectible.svg)](https://gemnasium.com/dblock/mongoid-tag-collectible)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/dblock/mongoid-tag-collectible.svg)](https://codeclimate.com/github/dblock/mongoid-tag-collectible)
|
5
8
|
|
6
9
|
Easily maintain a collection of `Tag` instances with aggregate counts from your model's `tags`.
|
7
10
|
|
11
|
+
### Compatibility
|
12
|
+
|
13
|
+
This gem supports Mongoid 3, Mongoid 4 and Mongoid 5 Beta.
|
14
|
+
|
8
15
|
### Install
|
9
16
|
|
10
17
|
Add `mongoid-tag-collectible` to your Gemfile.
|
@@ -67,15 +74,10 @@ end
|
|
67
74
|
|
68
75
|
### Contribute
|
69
76
|
|
70
|
-
|
71
|
-
|
72
|
-
* Fork this project.
|
73
|
-
* Make changes, write tests.
|
74
|
-
* Updated CHANGELOG.
|
75
|
-
* Make a pull request, bonus points for topic branches.
|
77
|
+
See [CONTRIBUTING](CONTRIBUTING.md).
|
76
78
|
|
77
79
|
### Copyright and License
|
78
80
|
|
79
|
-
Copyright Daniel Doubrovkine and Contributors, Artsy Inc., 2013
|
81
|
+
Copyright Daniel Doubrovkine and Contributors, Artsy Inc., 2013-2015
|
80
82
|
|
81
83
|
[MIT License](LICENSE.md)
|
data/Rakefile
CHANGED
@@ -7,7 +7,10 @@ require 'rspec/core'
|
|
7
7
|
require 'rspec/core/rake_task'
|
8
8
|
|
9
9
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
10
|
-
spec.pattern = FileList[
|
10
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
11
11
|
end
|
12
12
|
|
13
|
-
|
13
|
+
require 'rubocop/rake_task'
|
14
|
+
RuboCop::RakeTask.new(:rubocop)
|
15
|
+
|
16
|
+
task default: [:rubocop, :spec]
|
data/examples/readme.rb
CHANGED
@@ -16,12 +16,12 @@ class Thing
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def downcase_tags
|
19
|
-
tags
|
19
|
+
tags.map(&:downcase) if tags
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
Thing.create!(tags: %w(funny red))
|
24
|
+
Thing.create!(tags: %w(funny yellow))
|
25
25
|
|
26
26
|
funny_tag = ThingTag.where(name: 'funny').first
|
27
27
|
puts funny_tag.name # funny
|
@@ -30,10 +30,14 @@ p funny_tag.tagged.to_a # thing1 and thing2
|
|
30
30
|
|
31
31
|
# rename a tag
|
32
32
|
ThingTag.find('funny').update_attributes!(name: 'sad')
|
33
|
-
p Thing.first.tags # [ '
|
33
|
+
p Thing.first.tags # [ 'red', 'sad' ]
|
34
34
|
|
35
35
|
# delete a tag
|
36
36
|
ThingTag.find('red').destroy
|
37
37
|
p Thing.first.tags # [ 'sad' ]
|
38
38
|
|
39
|
-
Mongoid.
|
39
|
+
if Mongoid::TagCollectible.mongoid3? || Mongoid::TagCollectible.mongoid4?
|
40
|
+
Mongoid.default_session.drop
|
41
|
+
else
|
42
|
+
Mongoid::Clients.default.database.drop
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module TagCollectible
|
3
|
+
def self.mongoid3?
|
4
|
+
Mongoid::VERSION =~ /^3\./
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.mongoid4?
|
8
|
+
Mongoid::VERSION =~ /^4\./
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.object_id?(value)
|
12
|
+
self.mongoid3? ? Moped::BSON::ObjectId.legal?(value) : BSON::ObjectId.legal?(value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,51 +1,54 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module TagCollectible
|
3
|
-
|
4
|
-
|
5
|
-
include Mongoid::Timestamps
|
3
|
+
module Tag
|
4
|
+
extend ActiveSupport::Concern
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
included do
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
field :name, type: String
|
11
|
+
index({ name: 1 }, unique: true)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
attr_accessor :renaming
|
13
|
+
field :count, type: Integer, default: 0
|
14
|
+
index(count: -1)
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
before_destroy :_remove_tags!
|
17
|
+
before_update :_rename_tag!
|
18
|
+
attr_accessor :renaming
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
def renaming?
|
21
|
+
!!renaming
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def tagged
|
25
|
+
tagged_class.where(tags: name)
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
super(value)
|
32
|
-
else
|
33
|
-
where(name: value).first
|
28
|
+
def _remove_tags!
|
29
|
+
tagged_class.remove_tag!(self[:name]) unless renaming?
|
34
30
|
end
|
35
|
-
end
|
36
31
|
|
37
|
-
|
32
|
+
def self.find(value)
|
33
|
+
if Mongoid::TagCollectible.object_id?(value)
|
34
|
+
super(value)
|
35
|
+
else
|
36
|
+
where(name: value).first
|
37
|
+
end
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
tag
|
40
|
+
private
|
41
|
+
|
42
|
+
def _rename_tag!
|
43
|
+
if !new_record? && name_changed?
|
44
|
+
self.class.where(name: name).each do |tag|
|
45
|
+
tag.renaming = true
|
46
|
+
tag.destroy
|
47
|
+
end
|
48
|
+
tagged_class.rename_tag!(name_was, name)
|
44
49
|
end
|
45
|
-
tagged_class.rename_tag!(name_was, name)
|
46
50
|
end
|
47
51
|
end
|
48
|
-
|
49
52
|
end
|
50
53
|
end
|
51
54
|
end
|
@@ -6,31 +6,43 @@ module Mongoid
|
|
6
6
|
included do
|
7
7
|
field :tags, type: Array, default: []
|
8
8
|
index({ tags: 1 })
|
9
|
-
scope :tagged, where(
|
9
|
+
scope :tagged, -> { where(:tags.nin => [nil, []], :tags.ne => nil) }
|
10
10
|
after_save :_update_tags!
|
11
11
|
after_destroy :_destroy_tags!
|
12
12
|
cattr_accessor :tag_class
|
13
13
|
|
14
|
-
klass = Class.new
|
14
|
+
klass = Class.new do
|
15
|
+
include Mongoid::TagCollectible::Tag
|
15
16
|
cattr_accessor :tagged_class
|
16
17
|
end
|
17
18
|
klass.tagged_class = self
|
18
|
-
klass.store_in collection: "#{
|
19
|
-
|
20
|
-
|
19
|
+
klass.store_in collection: "#{name.underscore.gsub('/', '_')}_tags"
|
20
|
+
mod_name = "::#{name}".gsub("::#{name.demodulize}", '')
|
21
|
+
mod_name = 'Object' if mod_name.blank?
|
22
|
+
mod_name.constantize.const_set "#{name}Tag".demodulize, klass
|
23
|
+
self.tag_class = "#{name}Tag".constantize
|
21
24
|
end
|
22
25
|
|
23
26
|
module ClassMethods
|
27
|
+
if Mongoid::TagCollectible.mongoid3? || Mongoid::TagCollectible.mongoid4?
|
28
|
+
def rename_tag!(old_tag, new_tag)
|
29
|
+
collection.where(tags: old_tag).update({ '$addToSet' => { tags: new_tag } }, multi: true)
|
30
|
+
self.remove_tag!(old_tag)
|
31
|
+
end
|
24
32
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
33
|
+
def remove_tag!(tag_name)
|
34
|
+
collection.where(tags: tag_name).update({ '$pull' => { tags: tag_name } }, multi: true)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
def rename_tag!(old_tag, new_tag)
|
38
|
+
collection.find(tags: old_tag).update_many({ '$addToSet' => { tags: new_tag } })
|
39
|
+
self.remove_tag!(old_tag)
|
40
|
+
end
|
29
41
|
|
30
|
-
|
31
|
-
|
42
|
+
def remove_tag!(tag_name)
|
43
|
+
collection.find(tags: tag_name).update_many({ '$pull' => { tags: tag_name } })
|
44
|
+
end
|
32
45
|
end
|
33
|
-
|
34
46
|
end
|
35
47
|
|
36
48
|
private
|
@@ -42,21 +54,32 @@ module Mongoid
|
|
42
54
|
# added tags
|
43
55
|
(after - before).each do |tag|
|
44
56
|
next unless tag && tag.length > 0
|
45
|
-
|
46
|
-
name: tag,
|
47
|
-
_type: self.tag_class.name
|
48
|
-
).upsert(
|
49
|
-
"$inc" => { count: 1 }
|
50
|
-
)
|
57
|
+
_update_tag!(tag, 1)
|
51
58
|
end
|
52
59
|
# removed tags
|
53
60
|
(before - after).each do |tag|
|
54
61
|
next unless tag && tag.length > 0
|
55
|
-
|
62
|
+
_update_tag!(tag, -1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if Mongoid::TagCollectible.mongoid3? || Mongoid::TagCollectible.mongoid4?
|
67
|
+
def _update_tag!(tag, count)
|
68
|
+
tag_class.collection.find(
|
56
69
|
name: tag,
|
57
|
-
_type:
|
70
|
+
_type: tag_class.name
|
58
71
|
).upsert(
|
59
|
-
|
72
|
+
'$inc' => { count: count }
|
73
|
+
)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
def _update_tag!(tag, count)
|
77
|
+
tag_class.collection.find(
|
78
|
+
name: tag,
|
79
|
+
_type: tag_class.name
|
80
|
+
).update_one(
|
81
|
+
{ '$inc' => { count: count } },
|
82
|
+
upsert: true
|
60
83
|
)
|
61
84
|
end
|
62
85
|
end
|
@@ -64,15 +87,9 @@ module Mongoid
|
|
64
87
|
def _destroy_tags!
|
65
88
|
tags.each do |tag|
|
66
89
|
next unless tag && tag.length > 0
|
67
|
-
|
68
|
-
name: tag,
|
69
|
-
_type: self.tag_class.name
|
70
|
-
).upsert(
|
71
|
-
"$inc" => { count: -1 }
|
72
|
-
)
|
90
|
+
_update_tag!(tag, -1)
|
73
91
|
end
|
74
92
|
end
|
75
|
-
|
76
93
|
end
|
77
94
|
end
|
78
95
|
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
2
2
|
require 'mongoid-tag-collectible/version'
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
|
-
s.name =
|
5
|
+
s.name = 'mongoid-tag-collectible'
|
6
6
|
s.version = Mongoid::TagCollectible::VERSION
|
7
|
-
s.authors = [
|
8
|
-
s.email =
|
7
|
+
s.authors = ['Daniel Doubrovkine']
|
8
|
+
s.email = 'dblock@dblock.org'
|
9
9
|
s.platform = Gem::Platform::RUBY
|
10
10
|
s.required_rubygems_version = '>= 1.3.6'
|
11
11
|
s.files = `git ls-files`.split("\n")
|
12
|
-
s.require_paths = [
|
13
|
-
s.homepage =
|
14
|
-
s.licenses = [
|
12
|
+
s.require_paths = ['lib']
|
13
|
+
s.homepage = 'http://github.com/dblock/mongoid-tag-collectible'
|
14
|
+
s.licenses = ['MIT']
|
15
15
|
s.summary = "Easily maintain a collection of Tag instances with aggregate counts from your model's tags."
|
16
|
-
s.add_dependency
|
17
|
-
s.add_dependency
|
16
|
+
s.add_dependency 'mongoid', '>= 3.0.0'
|
17
|
+
s.add_dependency 'activesupport'
|
18
18
|
end
|
File without changes
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongoid::TagCollectible::Tagged do
|
4
|
+
let(:instance) { Namespaced::TestTagged.create! }
|
5
|
+
describe 'tag_class' do
|
6
|
+
it 'defines tag_class' do
|
7
|
+
expect(instance.class.tag_class).to eq(Namespaced::TestTaggedTag)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
describe 'rename_tag' do
|
11
|
+
context "doesn't match an existing tag" do
|
12
|
+
it 'is the same' do
|
13
|
+
old_tags = instance.class.all.map(&:tags)
|
14
|
+
instance.class.rename_tag! 'Yellow', 'yellow'
|
15
|
+
expect(instance.class.all.map(&:tags)).to eq old_tags
|
16
|
+
end
|
17
|
+
end
|
18
|
+
context 'matches an existing tag' do
|
19
|
+
it 'is different' do
|
20
|
+
instance.tags = %w(Yellow Mellow)
|
21
|
+
instance.save!
|
22
|
+
old_tags = instance.class.all.map(&:tags)
|
23
|
+
instance.class.rename_tag! 'Yellow', 'Blue'
|
24
|
+
expect(instance.class.all.map(&:tags)).not_to eq old_tags
|
25
|
+
expect(instance.reload.tags).to include 'Blue'
|
26
|
+
expect(instance.tags).to include 'Mellow'
|
27
|
+
expect(instance.tags).not_to include 'Yellow'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
describe 'remove_tag!' do
|
32
|
+
it 'deletes tag' do
|
33
|
+
instance.tags = %w(Yellow Mellow)
|
34
|
+
instance.save!
|
35
|
+
instance.class.remove_tag!('Yellow')
|
36
|
+
expect(instance.class.find(instance.id).tags).to eq(['Mellow'])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -2,125 +2,129 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe Mongoid::TagCollectible::Tag do
|
5
|
-
describe
|
6
|
-
it
|
7
|
-
TestTaggedTag.collection.name.
|
5
|
+
describe 'tag' do
|
6
|
+
it 'stores tags in a collection name defined by the class' do
|
7
|
+
expect(TestTaggedTag.collection.name).to eq('test_tagged_tags')
|
8
8
|
end
|
9
9
|
end
|
10
|
-
describe
|
10
|
+
describe 'without tags' do
|
11
11
|
it "generates no entries in 'tags' when tags is nil" do
|
12
12
|
TestTagged.create!
|
13
|
-
TestTaggedTag.all.size.
|
13
|
+
expect(TestTaggedTag.all.size).to eq(0)
|
14
14
|
end
|
15
15
|
it "generates no entries in 'tags' when tags is empty" do
|
16
16
|
TestTagged.create!(tags: [])
|
17
|
-
TestTaggedTag.all.size.
|
17
|
+
expect(TestTaggedTag.all.size).to eq(0)
|
18
18
|
end
|
19
19
|
it "generates no entries in 'tags' when tags contains an empty or nil value" do
|
20
|
-
TestTagged.create!(tags: [
|
21
|
-
TestTaggedTag.all.size.
|
20
|
+
TestTagged.create!(tags: ['', nil])
|
21
|
+
expect(TestTaggedTag.all.size).to eq(0)
|
22
22
|
end
|
23
23
|
end
|
24
|
-
describe
|
25
|
-
it
|
24
|
+
describe 'with tags' do
|
25
|
+
it 'find by id' do
|
26
26
|
TestTagged.create!(tags: ['one'])
|
27
|
-
TestTaggedTag.find(TestTaggedTag.first.id).
|
27
|
+
expect(TestTaggedTag.find(TestTaggedTag.first.id)).to be_a TestTaggedTag
|
28
28
|
end
|
29
|
-
it
|
29
|
+
it 'find by tag' do
|
30
30
|
TestTagged.create!(tags: ['one'])
|
31
|
-
TestTaggedTag.find('one').
|
31
|
+
expect(TestTaggedTag.find('one')).to be_a TestTaggedTag
|
32
32
|
end
|
33
|
-
it
|
33
|
+
it 'generates a tags collection that is case-sensitive' do
|
34
34
|
TestTagged.create!(tags: ['one'])
|
35
35
|
TestTagged.create!(tags: ['One'])
|
36
|
-
TestTagged.create!(name:
|
37
|
-
TestTaggedTag.count.
|
36
|
+
TestTagged.create!(name: 'whatever')
|
37
|
+
expect(TestTaggedTag.count).to eq(2)
|
38
38
|
end
|
39
|
-
it
|
40
|
-
TestTagged.create!(tags: [
|
41
|
-
TestTagged.create!(tags:
|
39
|
+
it 'generates a tags collection with the tag with several tags' do
|
40
|
+
TestTagged.create!(tags: ['one'])
|
41
|
+
TestTagged.create!(tags: %w(one two))
|
42
42
|
tags = TestTaggedTag.all.desc(:count)
|
43
|
-
tags.size.
|
44
|
-
tags[0].name.
|
45
|
-
tags[0].count.
|
46
|
-
tags[1].name.
|
47
|
-
tags[1].count.
|
48
|
-
end
|
49
|
-
it
|
50
|
-
TestTaggedTag.create!(name:
|
51
|
-
|
43
|
+
expect(tags.size).to eq(2)
|
44
|
+
expect(tags[0].name).to eq('one')
|
45
|
+
expect(tags[0].count).to eq(2)
|
46
|
+
expect(tags[1].name).to eq('two')
|
47
|
+
expect(tags[1].count).to eq(1)
|
48
|
+
end
|
49
|
+
it 'prevents duplicates' do
|
50
|
+
TestTaggedTag.create!(name: 'one')
|
51
|
+
if Mongoid::TagCollectible.mongoid3? || Mongoid::TagCollectible.mongoid4?
|
52
|
+
expect { TestTaggedTag.create!(name: 'one') }.to raise_error Moped::Errors::OperationFailure, /duplicate key error/
|
53
|
+
else
|
54
|
+
expect { TestTaggedTag.create!(name: 'one') }.to raise_error Mongo::Error::OperationFailure, /duplicate key error/
|
55
|
+
end
|
52
56
|
end
|
53
57
|
end
|
54
|
-
describe
|
58
|
+
describe 'incrementally' do
|
55
59
|
before(:each) do
|
56
|
-
@instance1 = TestTagged.create!(tags: [
|
57
|
-
@instance2 = TestTagged.create!(tags:
|
60
|
+
@instance1 = TestTagged.create!(tags: ['one'])
|
61
|
+
@instance2 = TestTagged.create!(tags: %w(one two))
|
58
62
|
@tags_before = TestTaggedTag.all.desc(:count)
|
59
63
|
end
|
60
|
-
it
|
61
|
-
TestTagged.create!(tags:
|
64
|
+
it 'increments an existing tag by 1 when a tagged instance is added' do
|
65
|
+
TestTagged.create!(tags: %w(one two three))
|
62
66
|
tags_after = TestTaggedTag.all.desc(:count)
|
63
|
-
tags_after.size.
|
67
|
+
expect(tags_after.size).to eq(3)
|
64
68
|
# 'one'
|
65
|
-
tags_after[0].id.
|
66
|
-
tags_after[0].name.
|
67
|
-
tags_after[0].count.
|
69
|
+
expect(tags_after[0].id).to eq(@tags_before[0].id)
|
70
|
+
expect(tags_after[0].name).to eq('one')
|
71
|
+
expect(tags_after[0].count).to eq(3)
|
68
72
|
# 'two'
|
69
|
-
tags_after[1].id.
|
70
|
-
tags_after[1].name.
|
71
|
-
tags_after[1].count.
|
73
|
+
expect(tags_after[1].id).to eq(@tags_before[1].id)
|
74
|
+
expect(tags_after[1].name).to eq('two')
|
75
|
+
expect(tags_after[1].count).to eq(2)
|
72
76
|
# 'three'
|
73
|
-
tags_after[2].name.
|
74
|
-
tags_after[2].count.
|
77
|
+
expect(tags_after[2].name).to eq('three')
|
78
|
+
expect(tags_after[2].count).to eq(1)
|
75
79
|
end
|
76
|
-
it
|
80
|
+
it 'decrements an existing tag by 1 and removes tags with zero when a tagged instance is removed' do
|
77
81
|
@instance2.destroy
|
78
82
|
tags_after = TestTaggedTag.all.desc(:count)
|
79
|
-
tags_after.size.
|
80
|
-
tags_after[0].id.
|
81
|
-
tags_after[0].name.
|
82
|
-
tags_after[0].count.
|
83
|
-
tags_after[1].id.
|
84
|
-
tags_after[1].name.
|
85
|
-
tags_after[1].count.
|
83
|
+
expect(tags_after.size).to eq(2)
|
84
|
+
expect(tags_after[0].id).to eq(@tags_before[0].id)
|
85
|
+
expect(tags_after[0].name).to eq('one')
|
86
|
+
expect(tags_after[0].count).to eq(1)
|
87
|
+
expect(tags_after[1].id).to eq(@tags_before[1].id)
|
88
|
+
expect(tags_after[1].name).to eq('two')
|
89
|
+
expect(tags_after[1].count).to eq(0)
|
86
90
|
end
|
87
91
|
end
|
88
|
-
describe
|
89
|
-
it
|
92
|
+
describe 'renaming' do
|
93
|
+
it 'renames all instances of tag' do
|
90
94
|
instance = TestTagged.create!(tags: ['one'])
|
91
95
|
TestTaggedTag.where(name: 'one').first.update_attributes!(name: 'two')
|
92
|
-
instance.reload.tags.
|
93
|
-
TestTaggedTag.count.
|
96
|
+
expect(instance.reload.tags).to eq(['two'])
|
97
|
+
expect(TestTaggedTag.count).to eq(1)
|
94
98
|
end
|
95
|
-
it
|
96
|
-
instance = TestTagged.create!(tags:
|
99
|
+
it 'avoids duplicate tags when renaming to an existing tag' do
|
100
|
+
instance = TestTagged.create!(tags: %w(one two))
|
97
101
|
TestTaggedTag.where(name: 'one').first.update_attributes!(name: 'two')
|
98
|
-
TestTaggedTag.count.
|
99
|
-
instance.reload.tags.
|
102
|
+
expect(TestTaggedTag.count).to eq(1)
|
103
|
+
expect(instance.reload.tags).to eq(['two'])
|
100
104
|
end
|
101
|
-
it
|
102
|
-
instance1 = TestTagged.create!(tags:
|
105
|
+
it 'preserves renamed tags when TestTaggedTag.update! is called' do
|
106
|
+
instance1 = TestTagged.create!(tags: %w(one two))
|
103
107
|
instance2 = TestTagged.create!(tags: ['two'])
|
104
108
|
instance3 = TestTagged.create!(tags: ['one'])
|
105
109
|
TestTaggedTag.where(name: 'one').first.update_attributes!(name: 'two')
|
106
|
-
[instance1, instance2, instance3].each{ |a| a.reload.tags.
|
107
|
-
TestTaggedTag.where(name: 'two').count.
|
108
|
-
TestTaggedTag.where(name: 'one').count.
|
109
|
-
[instance1, instance2, instance3].each{ |a| a.reload.tags.
|
110
|
-
TestTaggedTag.where(name: 'two').count.
|
111
|
-
TestTaggedTag.where(name: 'one').count.
|
110
|
+
[instance1, instance2, instance3].each { |a| expect(a.reload.tags).to eq(['two']) }
|
111
|
+
expect(TestTaggedTag.where(name: 'two').count).to eq(1)
|
112
|
+
expect(TestTaggedTag.where(name: 'one').count).to eq(0)
|
113
|
+
[instance1, instance2, instance3].each { |a| expect(a.reload.tags).to eq(['two']) }
|
114
|
+
expect(TestTaggedTag.where(name: 'two').count).to eq(1)
|
115
|
+
expect(TestTaggedTag.where(name: 'one').count).to eq(0)
|
112
116
|
end
|
113
117
|
end
|
114
|
-
describe
|
115
|
-
it
|
118
|
+
describe 'instances' do
|
119
|
+
it 'returns all matching tagged instances' do
|
116
120
|
TestTagged.create!(tags: ['one'])
|
117
121
|
TestTagged.create!(tags: ['one'])
|
118
122
|
tag = TestTaggedTag.first
|
119
|
-
tag.tagged.count.
|
120
|
-
tag.tagged.each { |a| a.
|
123
|
+
expect(tag.tagged.count).to eq(2)
|
124
|
+
tag.tagged.each { |a| expect(a).to be_a TestTagged }
|
121
125
|
end
|
122
|
-
it
|
123
|
-
TestTaggedTag.new.tagged.count.
|
126
|
+
it 'returns a non-nil result if there are no matching tagged instances' do
|
127
|
+
expect(TestTaggedTag.new.tagged.count).to eq(0)
|
124
128
|
end
|
125
129
|
end
|
126
130
|
end
|
@@ -2,38 +2,38 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Mongoid::TagCollectible::Tagged do
|
4
4
|
let(:instance) { TestTagged.create! }
|
5
|
-
describe
|
6
|
-
it
|
7
|
-
instance.class.tag_class.
|
5
|
+
describe 'tag_class' do
|
6
|
+
it 'defines tag_class' do
|
7
|
+
expect(instance.class.tag_class).to eq(TestTaggedTag)
|
8
8
|
end
|
9
9
|
end
|
10
|
-
describe
|
10
|
+
describe 'rename_tag' do
|
11
11
|
context "doesn't match an existing tag" do
|
12
|
-
it
|
13
|
-
old_tags = instance.class.all.map
|
12
|
+
it 'is the same' do
|
13
|
+
old_tags = instance.class.all.map(&:tags)
|
14
14
|
instance.class.rename_tag! 'Yellow', 'yellow'
|
15
|
-
instance.class.all.map
|
15
|
+
expect(instance.class.all.map(&:tags)).to eq old_tags
|
16
16
|
end
|
17
17
|
end
|
18
|
-
context
|
19
|
-
it
|
20
|
-
instance.tags =
|
18
|
+
context 'matches an existing tag' do
|
19
|
+
it 'is different' do
|
20
|
+
instance.tags = %w(Yellow Mellow)
|
21
21
|
instance.save!
|
22
|
-
old_tags = instance.class.all.map
|
22
|
+
old_tags = instance.class.all.map(&:tags)
|
23
23
|
instance.class.rename_tag! 'Yellow', 'Blue'
|
24
|
-
instance.class.all.map
|
25
|
-
instance.reload.tags.
|
26
|
-
instance.tags.
|
27
|
-
instance.tags.
|
24
|
+
expect(instance.class.all.map(&:tags)).not_to eq old_tags
|
25
|
+
expect(instance.reload.tags).to include 'Blue'
|
26
|
+
expect(instance.tags).to include 'Mellow'
|
27
|
+
expect(instance.tags).not_to include 'Yellow'
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
-
describe
|
32
|
-
it
|
33
|
-
instance.tags =
|
31
|
+
describe 'remove_tag!' do
|
32
|
+
it 'deletes tag' do
|
33
|
+
instance.tags = %w(Yellow Mellow)
|
34
34
|
instance.save!
|
35
35
|
instance.class.remove_tag!('Yellow')
|
36
|
-
instance.class.find(instance.id).tags.
|
36
|
+
expect(instance.class.find(instance.id).tags).to eq(['Mellow'])
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/mongoid.rb
CHANGED
@@ -1,16 +1,42 @@
|
|
1
|
-
ENV[
|
1
|
+
ENV['MONGOID_ENV'] = 'test'
|
2
2
|
|
3
|
-
Mongoid.
|
3
|
+
if Mongoid::TagCollectible.mongoid3?
|
4
|
+
Mongoid.load! 'spec/config/mongoid3.yml'
|
5
|
+
elsif Mongoid::TagCollectible.mongoid4?
|
6
|
+
Mongoid.load! 'spec/config/mongoid4.yml'
|
7
|
+
else
|
8
|
+
Mongoid.load! 'spec/config/mongoid5.yml'
|
9
|
+
end
|
4
10
|
|
5
11
|
RSpec.configure do |config|
|
6
|
-
config.before(:
|
12
|
+
config.before(:all) do
|
13
|
+
@indexes = []
|
14
|
+
klass = TestTagged.tag_class
|
15
|
+
if Mongoid::TagCollectible.mongoid3?
|
16
|
+
TestTagged.tag_class.index_options.each_pair do |name, options|
|
17
|
+
@indexes << [klass, name, options]
|
18
|
+
end
|
19
|
+
else
|
20
|
+
klass.index_specifications.each do |index_specification|
|
21
|
+
@indexes << [klass, index_specification.key, index_specification.options]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
config.before do
|
7
26
|
Mongoid.purge!
|
8
|
-
|
9
|
-
|
27
|
+
@indexes.each do |klass, name, options|
|
28
|
+
if Mongoid::TagCollectible.mongoid3? || Mongoid::TagCollectible.mongoid4?
|
29
|
+
klass.collection.indexes.create(name, options)
|
30
|
+
else
|
31
|
+
klass.collection.indexes.create_one(name, options)
|
32
|
+
end
|
10
33
|
end
|
11
34
|
end
|
12
35
|
config.after(:all) do
|
13
|
-
Mongoid.
|
36
|
+
if Mongoid::TagCollectible.mongoid3? || Mongoid::TagCollectible.mongoid4?
|
37
|
+
Mongoid.default_session.drop
|
38
|
+
else
|
39
|
+
Mongoid::Clients.default.database.drop
|
40
|
+
end
|
14
41
|
end
|
15
42
|
end
|
16
|
-
|
data/spec/support/test_tagged.rb
CHANGED
metadata
CHANGED
@@ -1,46 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-tag-collectible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Daniel Doubrovkine
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-08-12 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: mongoid
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 3.0.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 3.0.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: activesupport
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
description:
|
@@ -49,55 +44,59 @@ executables: []
|
|
49
44
|
extensions: []
|
50
45
|
extra_rdoc_files: []
|
51
46
|
files:
|
52
|
-
- .gitignore
|
53
|
-
- .rspec
|
54
|
-
- .
|
47
|
+
- ".gitignore"
|
48
|
+
- ".rspec"
|
49
|
+
- ".rubocop.yml"
|
50
|
+
- ".rubocop_todo.yml"
|
51
|
+
- ".travis.yml"
|
55
52
|
- CHANGELOG.md
|
53
|
+
- CONTRIBUTING.md
|
56
54
|
- Gemfile
|
57
55
|
- LICENSE.md
|
58
56
|
- README.md
|
59
57
|
- Rakefile
|
60
58
|
- examples/readme.rb
|
61
59
|
- lib/mongoid-tag-collectible.rb
|
60
|
+
- lib/mongoid-tag-collectible/mongoid.rb
|
62
61
|
- lib/mongoid-tag-collectible/tag.rb
|
63
62
|
- lib/mongoid-tag-collectible/tagged.rb
|
64
63
|
- lib/mongoid-tag-collectible/version.rb
|
65
64
|
- lib/mongoid_tag_collectible.rb
|
66
65
|
- mongoid-tag-collectible.gemspec
|
67
|
-
- spec/config/
|
66
|
+
- spec/config/mongoid3.yml
|
67
|
+
- spec/config/mongoid4.yml
|
68
|
+
- spec/config/mongoid5.yml
|
69
|
+
- spec/mongoid-tag-collectible/namespaced_tagged_spec.rb
|
68
70
|
- spec/mongoid-tag-collectible/tag_spec.rb
|
69
71
|
- spec/mongoid-tag-collectible/tagged_spec.rb
|
70
72
|
- spec/mongoid-tag-collectible/version_spec.rb
|
71
73
|
- spec/spec_helper.rb
|
72
74
|
- spec/support/mongoid.rb
|
75
|
+
- spec/support/namespaced_test_tagged.rb
|
73
76
|
- spec/support/test_tagged.rb
|
74
77
|
homepage: http://github.com/dblock/mongoid-tag-collectible
|
75
78
|
licenses:
|
76
79
|
- MIT
|
80
|
+
metadata: {}
|
77
81
|
post_install_message:
|
78
82
|
rdoc_options: []
|
79
83
|
require_paths:
|
80
84
|
- lib
|
81
85
|
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
86
|
requirements:
|
84
|
-
- -
|
87
|
+
- - ">="
|
85
88
|
- !ruby/object:Gem::Version
|
86
89
|
version: '0'
|
87
|
-
segments:
|
88
|
-
- 0
|
89
|
-
hash: -3407508302417476120
|
90
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
-
none: false
|
92
91
|
requirements:
|
93
|
-
- -
|
92
|
+
- - ">="
|
94
93
|
- !ruby/object:Gem::Version
|
95
94
|
version: 1.3.6
|
96
95
|
requirements: []
|
97
96
|
rubyforge_project:
|
98
|
-
rubygems_version:
|
97
|
+
rubygems_version: 2.2.2
|
99
98
|
signing_key:
|
100
|
-
specification_version:
|
99
|
+
specification_version: 4
|
101
100
|
summary: Easily maintain a collection of Tag instances with aggregate counts from
|
102
101
|
your model's tags.
|
103
102
|
test_files: []
|