simple_taggable 0.0.1
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 +7 -0
- data/.gitignore +24 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +64 -0
- data/Rakefile +16 -0
- data/lib/generators/simple_taggable/install.rb +11 -0
- data/lib/generators/templates/create_taggings.rb +11 -0
- data/lib/generators/templates/create_tags.rb +9 -0
- data/lib/simple_taggable.rb +110 -0
- data/lib/simple_taggable/models/tag.rb +9 -0
- data/lib/simple_taggable/models/tagging.rb +10 -0
- data/lib/simple_taggable/tag_list.rb +65 -0
- data/lib/simple_taggable/version.rb +3 -0
- data/simple_taggable.gemspec +32 -0
- data/spec/db/migrate/10_create_users.rb +9 -0
- data/spec/simple_taggable/models/tag_spec.rb +13 -0
- data/spec/simple_taggable/models/tagging_spec.rb +26 -0
- data/spec/simple_taggable/tag_list_spec.rb +103 -0
- data/spec/simple_taggable_spec.rb +151 -0
- data/spec/spec_helper.rb +42 -0
- metadata +212 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 6a6ae1582e94c1e213bb8e4454568a8e4693f419
|
|
4
|
+
data.tar.gz: dbba33d4e612aa0879005ec33c2d934c6528c654
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7304fd7c748221860977a42e66408fd0c847c00faea359f7fc8350a66ef4ed3ee96d6f254a76e347044330ec31747f113da2248ef24f76b4c053e08205680a06
|
|
7
|
+
data.tar.gz: e4bc7cbb394620cb5f36c9292c374cdfe335835792e59c8f3b9c8047d99cd5867d5dac1e8795ed5e046aa3f5f857949d181c2a5b63093610e6c4ce07d2690bea
|
data/.gitignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
.bundle
|
|
4
|
+
.config
|
|
5
|
+
.yardoc
|
|
6
|
+
Gemfile.lock
|
|
7
|
+
InstalledFiles
|
|
8
|
+
_yardoc
|
|
9
|
+
coverage
|
|
10
|
+
doc/
|
|
11
|
+
lib/bundler/man
|
|
12
|
+
pkg
|
|
13
|
+
rdoc
|
|
14
|
+
spec/reports
|
|
15
|
+
test/tmp
|
|
16
|
+
test/version_tmp
|
|
17
|
+
tmp
|
|
18
|
+
*.bundle
|
|
19
|
+
*.so
|
|
20
|
+
*.o
|
|
21
|
+
*.a
|
|
22
|
+
mkmf.log
|
|
23
|
+
|
|
24
|
+
spec/db/migrate
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 joker1007
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# simple\_taggable
|
|
2
|
+
[](https://travis-ci.org/joker1007/simple_taggable)
|
|
3
|
+
[](https://coveralls.io/r/joker1007/simple_taggable)
|
|
4
|
+
[](https://codeclimate.com/github/joker1007/simple_taggable)
|
|
5
|
+
|
|
6
|
+
This is Hyper simple tagging plugin for ActiveRecord.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Add this line to your application's Gemfile:
|
|
11
|
+
|
|
12
|
+
gem 'simple_taggable'
|
|
13
|
+
|
|
14
|
+
And then execute:
|
|
15
|
+
|
|
16
|
+
$ bundle
|
|
17
|
+
|
|
18
|
+
Or install it yourself as:
|
|
19
|
+
|
|
20
|
+
$ gem install simple_taggable
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
class User < ActiveRecord::Base
|
|
26
|
+
include SimpleTaggable
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
user = User.new(name: "joker1007")
|
|
30
|
+
user.tag_list.add("Ruby")
|
|
31
|
+
user.tag_list << "CoffeeScript"
|
|
32
|
+
user.save!
|
|
33
|
+
|
|
34
|
+
# tagged_with scope
|
|
35
|
+
User.tagged_with("Ruby") # eq [user]
|
|
36
|
+
User.tagged_with("Ruby", exclude: true) # eq []
|
|
37
|
+
User.tagged_with("CoffeeScript") # eq [user]
|
|
38
|
+
|
|
39
|
+
User.tagged_with("Ruby", "CoffeeScript") # eq [user]
|
|
40
|
+
User.tagged_with("Ruby", "CoffeeScript", exclude: true) # eq []
|
|
41
|
+
User.tagged_with("Ruby", "CoffeeScript", match_all: true) # eq [user]
|
|
42
|
+
User.tagged_with("Ruby", "JavaScript") # eq [user]
|
|
43
|
+
User.tagged_with("Ruby", "JavaScript", exclude: true) # eq []
|
|
44
|
+
User.tagged_with("Ruby", "JavaScript", match_all: true) # eq []
|
|
45
|
+
|
|
46
|
+
# Direct tag_list assign
|
|
47
|
+
user.tag_list = "Ruby"
|
|
48
|
+
|
|
49
|
+
# or
|
|
50
|
+
|
|
51
|
+
user.tag_list = ["Ruby"]
|
|
52
|
+
|
|
53
|
+
# or
|
|
54
|
+
|
|
55
|
+
user.tag_list = SimpleTaggable::TagList.new("Ruby")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Contributing
|
|
59
|
+
|
|
60
|
+
1. Fork it ( https://github.com/[my-github-username]/simple_taggable/fork )
|
|
61
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
62
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
63
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
64
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "rspec/core/rake_task"
|
|
3
|
+
|
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
5
|
+
|
|
6
|
+
task :default => :spec
|
|
7
|
+
|
|
8
|
+
namespace :test do
|
|
9
|
+
desc "copy migrations to spec/db/migrate"
|
|
10
|
+
task :copy_migrations => "spec/db/migrate" do
|
|
11
|
+
cp "lib/generators/templates/create_tags.rb", "spec/db/migrate/1_create_tags.rb"
|
|
12
|
+
cp "lib/generators/templates/create_taggings.rb", "spec/db/migrate/2_create_taggings.rb"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
directory "spec/db/migrate"
|
|
16
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
|
|
3
|
+
class SimpleTaggable::InstallGenerator < Rails::Generators::Base
|
|
4
|
+
source_root File.expand_path('../../templates', __FILE__)
|
|
5
|
+
|
|
6
|
+
desc "This generator creates migrations for simple_taggable"
|
|
7
|
+
def create_migration_file
|
|
8
|
+
copy_file "create_tags.rb", "db/migrate/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_create_tags.rb"
|
|
9
|
+
copy_file "create_taggings.rb", "db/migrate/#{(Time.now.utc + 1).strftime("%Y%m%d%H%M%S")}_create_taggings.rb"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class CreateTaggings < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :taggings do |t|
|
|
4
|
+
t.references :tag, index: true
|
|
5
|
+
t.references :taggable, polymorphic: true
|
|
6
|
+
|
|
7
|
+
t.datetime :created_at
|
|
8
|
+
end
|
|
9
|
+
add_index :taggings, [:taggable_type, :taggable_id]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require "simple_taggable/version"
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
require "generators/simple_taggable/install"
|
|
6
|
+
require "simple_taggable/tag_list"
|
|
7
|
+
require "simple_taggable/models/tag"
|
|
8
|
+
require "simple_taggable/models/tagging"
|
|
9
|
+
|
|
10
|
+
require "active_support/concern"
|
|
11
|
+
|
|
12
|
+
module SimpleTaggable
|
|
13
|
+
extend ActiveSupport::Concern
|
|
14
|
+
|
|
15
|
+
included do
|
|
16
|
+
has_many :taggings, as: :taggable, class_name: "SimpleTaggable::Models::Tagging", dependent: :destroy
|
|
17
|
+
has_many :tags, through: :taggings, class_name: "SimpleTaggable::Models::Tag"
|
|
18
|
+
|
|
19
|
+
scope :tagged_with, ->(*tag_name, match_all: false, exclude: false) {
|
|
20
|
+
raise "`tagged_with` cannot use :match_all and :exclude at the same time" if match_all && exclude
|
|
21
|
+
tag_scope = SimpleTaggable::Models::Tag.where(name: tag_name)
|
|
22
|
+
|
|
23
|
+
if exclude
|
|
24
|
+
users = User.joins(:tags).merge(tag_scope).group(%W("#{table_name}"."id"))
|
|
25
|
+
where.not(id: users.pluck(:id))
|
|
26
|
+
else
|
|
27
|
+
User.joins(:tags).merge(tag_scope).group(%W("#{table_name}"."id")).tap do |scope|
|
|
28
|
+
break scope.having("count(*) == ?", tag_name.length) if match_all
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
after_save :__sync_tags__
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module ClassMethods
|
|
37
|
+
def inherited(child)
|
|
38
|
+
super
|
|
39
|
+
child.instance_variable_set("@__tag_filters__", __tag_filters__.dup)
|
|
40
|
+
child.instance_variable_set("@__tag_converters__", __tag_converters__.dup)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def add_tag_filter(filter_proc, &block)
|
|
44
|
+
pr = filter_proc || block
|
|
45
|
+
self.__tag_filters__ << pr
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def reset_tag_filters
|
|
49
|
+
__tag_filters__.clear
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add_tag_converter(converter_proc, &block)
|
|
53
|
+
pr = converter_proc || block
|
|
54
|
+
self.__tag_converters__ << pr
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def reset_tag_converters
|
|
58
|
+
__tag_converters__.clear
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# internal
|
|
62
|
+
def __tag_filters__
|
|
63
|
+
@__tag_filters__ ||= []
|
|
64
|
+
@__tag_filters__
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# internal
|
|
68
|
+
def __tag_converters__
|
|
69
|
+
@__tag_converters__ ||= []
|
|
70
|
+
@__tag_converters__
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def tag_list
|
|
75
|
+
@tag_list ||= SimpleTaggable::TagList.new(
|
|
76
|
+
tags.pluck(:name),
|
|
77
|
+
filters: self.class.__tag_filters__,
|
|
78
|
+
converters: self.class.__tag_converters__,
|
|
79
|
+
)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def tag_list=(tag_list)
|
|
83
|
+
case tag_list
|
|
84
|
+
when TagList
|
|
85
|
+
@tag_list = tag_list
|
|
86
|
+
when Array, String
|
|
87
|
+
@tag_list = SimpleTaggable::TagList.new(
|
|
88
|
+
tag_list,
|
|
89
|
+
filters: self.class.__tag_filters__,
|
|
90
|
+
converters: self.class.__tag_converters__,
|
|
91
|
+
)
|
|
92
|
+
else
|
|
93
|
+
raise TypeError.new("tag_list is not TagList object")
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def __sync_tags__
|
|
100
|
+
current_tags = tags.to_a
|
|
101
|
+
tags = tag_list.map do |tag_name|
|
|
102
|
+
SimpleTaggable::Models::Tag.find_or_initialize_by(name: tag_name)
|
|
103
|
+
end
|
|
104
|
+
new_tags = tags - current_tags
|
|
105
|
+
old_tags = current_tags - tags
|
|
106
|
+
|
|
107
|
+
self.tags << new_tags
|
|
108
|
+
taggings.where(tag_id: old_tags.map(&:id)).destroy_all
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
|
2
|
+
require "active_support/core_ext/array"
|
|
3
|
+
|
|
4
|
+
module SimpleTaggable
|
|
5
|
+
class TagList
|
|
6
|
+
include Enumerable
|
|
7
|
+
|
|
8
|
+
delegate \
|
|
9
|
+
:[],
|
|
10
|
+
:each,
|
|
11
|
+
:length,
|
|
12
|
+
:size,
|
|
13
|
+
:count,
|
|
14
|
+
:include?,
|
|
15
|
+
:empty?,
|
|
16
|
+
:clear,
|
|
17
|
+
:to_s,
|
|
18
|
+
to: :raw_data
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def [](*tags)
|
|
22
|
+
new(*tags)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(*tags, filters: [], converters: [])
|
|
27
|
+
@raw_data = []
|
|
28
|
+
|
|
29
|
+
@filters = filters.freeze
|
|
30
|
+
@converters = converters.freeze
|
|
31
|
+
|
|
32
|
+
tags.flatten.each {|tag| add(tag) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def add(*tags)
|
|
36
|
+
tags.flatten.each do |t|
|
|
37
|
+
tag = @converters.inject(t.to_s) do |pre_tag, converter|
|
|
38
|
+
converter.call(self, pre_tag)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if @filters.all? { |filter| filter.call(self, tag) }
|
|
42
|
+
@raw_data << tag
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
@raw_data.uniq!
|
|
46
|
+
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
alias :<< :add
|
|
50
|
+
|
|
51
|
+
def to_a
|
|
52
|
+
@raw_data.deep_dup
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def inspect
|
|
56
|
+
"SimpleTaggable::TagList#{raw_data.inspect}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def raw_data
|
|
62
|
+
@raw_data
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'simple_taggable/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "simple_taggable"
|
|
8
|
+
spec.version = SimpleTaggable::VERSION
|
|
9
|
+
spec.authors = ["joker1007"]
|
|
10
|
+
spec.email = ["kakyoin.hierophant@gmail.com"]
|
|
11
|
+
spec.summary = %q{Hyper Simple tagging plugin for ActiveRecord}
|
|
12
|
+
spec.description = %q{Hyper Simple tagging plugin for ActiveRecord}
|
|
13
|
+
spec.homepage = ""
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_runtime_dependency "activerecord", "~> 4"
|
|
22
|
+
spec.add_runtime_dependency "activesupport", "~> 4"
|
|
23
|
+
spec.add_runtime_dependency "railties", "~> 4"
|
|
24
|
+
|
|
25
|
+
spec.add_development_dependency "bundler", ">= 1.5"
|
|
26
|
+
spec.add_development_dependency "rake"
|
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.0.0.beta"
|
|
28
|
+
spec.add_development_dependency "database_cleaner"
|
|
29
|
+
spec.add_development_dependency "sqlite3"
|
|
30
|
+
spec.add_development_dependency "shoulda-matchers"
|
|
31
|
+
spec.add_development_dependency "coveralls"
|
|
32
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SimpleTaggable::Models::Tag do
|
|
4
|
+
it "is created given name" do
|
|
5
|
+
described_class.create!(name: "タグ")
|
|
6
|
+
expect(described_class.first.name).to eq "タグ"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "is invalid given duplicate name" do
|
|
10
|
+
described_class.create!(name: "タグ")
|
|
11
|
+
expect(described_class.new(name: "タグ")).not_to be_valid
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SimpleTaggable::Models::Tagging do
|
|
4
|
+
it { should belong_to(:tag) }
|
|
5
|
+
it { should belong_to(:taggable) }
|
|
6
|
+
|
|
7
|
+
it "is created given tag and taggable" do
|
|
8
|
+
tag = SimpleTaggable::Models::Tag.create!(name: "タグ")
|
|
9
|
+
user = User.create!(name: "joker1007")
|
|
10
|
+
SimpleTaggable::Models::Tagging.create!(tag: tag, taggable: user)
|
|
11
|
+
expect(SimpleTaggable::Models::Tagging.first.tag).to eq tag
|
|
12
|
+
expect(SimpleTaggable::Models::Tagging.first.taggable).to eq user
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "is not creatable no taggable" do
|
|
16
|
+
tag = SimpleTaggable::Models::Tag.create!(name: "タグ")
|
|
17
|
+
tagging = SimpleTaggable::Models::Tagging.create(tag: tag)
|
|
18
|
+
expect(tagging).not_to be_persisted
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "is not creatable no tag" do
|
|
22
|
+
user = User.create!(name: "joker1007")
|
|
23
|
+
tagging = SimpleTaggable::Models::Tagging.create(taggable: user)
|
|
24
|
+
expect(tagging).not_to be_persisted
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SimpleTaggable::TagList do
|
|
4
|
+
it "is Enumerable" do
|
|
5
|
+
expect(subject.class.ancestors).to include(Enumerable)
|
|
6
|
+
expect(subject).to be_respond_to(:each)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
let(:tag_list) { SimpleTaggable::TagList.new }
|
|
10
|
+
|
|
11
|
+
describe "Constructor" do
|
|
12
|
+
it "should receive initial tags" do
|
|
13
|
+
tag_list = SimpleTaggable::TagList.new("init1", "init2")
|
|
14
|
+
expect(tag_list.length).to eq(2)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should receive initial tags as Array" do
|
|
18
|
+
tag_list = SimpleTaggable::TagList.new(["init1", "init2"])
|
|
19
|
+
expect(tag_list.length).to eq(2)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "SimpleTaggable::TagList[tag]" do
|
|
23
|
+
it "creates instance" do
|
|
24
|
+
tag_list = SimpleTaggable::TagList["init1", "init2"]
|
|
25
|
+
expect(tag_list.length).to eq(2)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "#add" do
|
|
31
|
+
it "should add one tag" do
|
|
32
|
+
expect { tag_list.add("Tag1") }
|
|
33
|
+
.to change { tag_list.length }.from(0).to(1)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should receive multi tags" do
|
|
37
|
+
expect { tag_list.add("Tag1", "Tag2") }
|
|
38
|
+
.to change { tag_list.length }.from(0).to(2)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should not change if added duplicate tag" do
|
|
42
|
+
tag_list.add("Tag1")
|
|
43
|
+
expect { tag_list.add("Tag1") }
|
|
44
|
+
.not_to change { tag_list.length }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "Index access" do
|
|
49
|
+
it "should return tag string" do
|
|
50
|
+
tag_list.add("Tag1")
|
|
51
|
+
expect(tag_list[0]).to eq "Tag1"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe "Filtering" do
|
|
56
|
+
context "Given filters return false" do
|
|
57
|
+
it "filter out tags" do
|
|
58
|
+
tag_list = SimpleTaggable::TagList.new(filters: [
|
|
59
|
+
->(_, tag) { tag != "NoAdd" }
|
|
60
|
+
])
|
|
61
|
+
|
|
62
|
+
tag_list.add("Tag1", "NoAdd")
|
|
63
|
+
expect(tag_list).to match_array(["Tag1"])
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should receive multi filters" do
|
|
68
|
+
tag_list = SimpleTaggable::TagList.new(filters: [
|
|
69
|
+
->(_, tag) { tag != "NoAdd" },
|
|
70
|
+
->(tl, tag) { tl.length < 2 },
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
tag_list.add("Tag1", "NoAdd", "Tag2", "Tag3")
|
|
74
|
+
expect(tag_list).to match_array(["Tag1", "Tag2"])
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe "Converting" do
|
|
79
|
+
it "convert added tag" do
|
|
80
|
+
tag_list = SimpleTaggable::TagList.new(converters: [
|
|
81
|
+
->(_, tag) { tag.upcase },
|
|
82
|
+
->(_, tag) { tag[0..1] },
|
|
83
|
+
])
|
|
84
|
+
|
|
85
|
+
tag_list.add("foo", "bar", "baz")
|
|
86
|
+
expect(tag_list).to match_array(["FO", "BA"])
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "convert tag before filter" do
|
|
90
|
+
tag_list = SimpleTaggable::TagList.new(
|
|
91
|
+
filters: [
|
|
92
|
+
->(_, tag) { tag =~ /_1\Z/ },
|
|
93
|
+
],
|
|
94
|
+
converters: [
|
|
95
|
+
->(_, tag) { tag + "_1" },
|
|
96
|
+
],
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
tag_list.add("foo")
|
|
100
|
+
expect(tag_list).to match_array(["foo_1"])
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SimpleTaggable do
|
|
4
|
+
describe "including class" do
|
|
5
|
+
subject { User.new }
|
|
6
|
+
|
|
7
|
+
it { should have_many(:taggings) }
|
|
8
|
+
it { should have_many(:tags).through(:taggings) }
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
let(:joker1007) { User.create(name: "joker1007") }
|
|
12
|
+
let(:tag1) { SimpleTaggable::Models::Tag.create(name: "Tag1") }
|
|
13
|
+
let(:tag2) { SimpleTaggable::Models::Tag.create(name: "Tag2") }
|
|
14
|
+
|
|
15
|
+
describe "Named Scope" do
|
|
16
|
+
describe ".tagged_with" do
|
|
17
|
+
let(:joseph) { User.create(name: "joseph") }
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
joker1007.tags << [tag1, tag2]
|
|
21
|
+
joseph.tags << tag2
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should return relation which has given tag string" do
|
|
25
|
+
expect(User.tagged_with("Tag1")).to eq [joker1007]
|
|
26
|
+
expect(User.tagged_with("Tag2")).to match_array [joker1007, joseph]
|
|
27
|
+
expect(User.tagged_with("Tag2", "Tag1")).to match_array [joker1007, joseph]
|
|
28
|
+
expect(User.tagged_with("Tag1", "Tag3")).to eq [joker1007]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "Given match_all option" do
|
|
32
|
+
it "should return relation which has given all tag string" do
|
|
33
|
+
expect(User.tagged_with("Tag2", "Tag1", match_all: true)).to eq [joker1007]
|
|
34
|
+
expect(User.tagged_with("Tag1", "Tag3", match_all: true)).to be_empty
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "Given exclude option" do
|
|
39
|
+
it "should return relation which has no given tag string" do
|
|
40
|
+
expect(User.tagged_with("Tag1", exclude: true)).to eq [joseph]
|
|
41
|
+
expect(User.tagged_with("Tag2", exclude: true)).to be_empty
|
|
42
|
+
expect(User.tagged_with("Tag3", exclude: true)).to match_array [joker1007, joseph]
|
|
43
|
+
expect(User.tagged_with("Tag1", "Tag3", exclude: true)).to eq [joseph]
|
|
44
|
+
expect(User.tagged_with("Tag1", "Tag2", exclude: true)).to be_empty
|
|
45
|
+
expect(User.tagged_with("Tag2", "Tag3", exclude: true)).to be_empty
|
|
46
|
+
expect(User.tagged_with("Tag1", "Tag2", "Tag3", exclude: true)).to be_empty
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "Given match_all and exclude" do
|
|
51
|
+
it "should raise RuntimeError" do
|
|
52
|
+
expect { User.tagged_with("Tag1", exclude: true, match_all: true) }
|
|
53
|
+
.to raise_error(RuntimeError)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe "#tag_list" do
|
|
60
|
+
before do
|
|
61
|
+
joker1007.tags << [tag1, tag2]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should return TagList that is initialized by self.tags" do
|
|
65
|
+
reloaded = User.find(joker1007.id)
|
|
66
|
+
expect(reloaded.tag_list).to match_array SimpleTaggable::TagList.new("Tag1", "Tag2")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "filters and converters" do
|
|
70
|
+
class TagFilteredUser < User
|
|
71
|
+
add_tag_filter ->(tag_list, tag) { tag != "FILTERED" }
|
|
72
|
+
add_tag_filter ->(tag_list, tag) { tag != "filtered" }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class TagConvertedUser < User
|
|
76
|
+
add_tag_filter ->(tag_list, tag) { tag != "FILTERED" }
|
|
77
|
+
add_tag_converter ->(tag_list, tag) { tag.upcase }
|
|
78
|
+
add_tag_converter ->(tag_list, tag) { tag.gsub(/FOO/, "BAR") }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class InheritedUser < TagConvertedUser
|
|
82
|
+
reset_tag_converters
|
|
83
|
+
add_tag_filter ->(tag_list, tag) { tag != "FILTERED" }
|
|
84
|
+
add_tag_converter ->(tag_list, tag) { tag.downcase }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "use filter given add_tag_filter method, when initialize TagList" do
|
|
88
|
+
tag_filtered_user = TagFilteredUser.new(name: "jotaro")
|
|
89
|
+
tag_filtered_user.tag_list.add("Tag1", "FILTERED", "filtered")
|
|
90
|
+
expect(tag_filtered_user.tag_list).to match_array SimpleTaggable::TagList.new("Tag1")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "use converter given add_tag_converter method, when initialize TagList" do
|
|
94
|
+
inherited_user = InheritedUser.new(name: "jotaro")
|
|
95
|
+
inherited_user.tag_list.add("Tag1", "FILTERED")
|
|
96
|
+
expect(inherited_user.tag_list).to match_array SimpleTaggable::TagList.new("tag1", "filtered")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "inherit parent filters and converters" do
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe "#tag_list=" do
|
|
105
|
+
it" should set TagList" do
|
|
106
|
+
expect(joker1007.tag_list).to be_empty
|
|
107
|
+
joker1007.tag_list = SimpleTaggable::TagList.new("Tag1")
|
|
108
|
+
expect(joker1007.tag_list).to match_array SimpleTaggable::TagList.new("Tag1")
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "can receive Array" do
|
|
112
|
+
expect(joker1007.tag_list).to be_empty
|
|
113
|
+
joker1007.tag_list = ["Tag1"]
|
|
114
|
+
expect(joker1007.tag_list).to match_array SimpleTaggable::TagList.new("Tag1")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "can receive String" do
|
|
118
|
+
expect(joker1007.tag_list).to be_empty
|
|
119
|
+
joker1007.tag_list = "Tag1"
|
|
120
|
+
expect(joker1007.tag_list).to match_array SimpleTaggable::TagList.new("Tag1")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "raise ArgumentError if given not TagList nor Array object" do
|
|
124
|
+
expect { joker1007.tag_list = 1 }.to raise_error(TypeError)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
context "After save" do
|
|
129
|
+
before do
|
|
130
|
+
joker1007.tags << tag1
|
|
131
|
+
joker1007.instance_variable_set("@tag_list", nil)
|
|
132
|
+
joker1007.tag_list << "Tag2"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "create new tags included by tag_list" do
|
|
136
|
+
expect(joker1007.tag_list).to match_array SimpleTaggable::TagList.new("Tag1", "Tag2")
|
|
137
|
+
|
|
138
|
+
expect { joker1007.save! }.to change { joker1007.reload; joker1007.tags.size }
|
|
139
|
+
.from(1).to(2)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "delete old tags included by tag_list" do
|
|
143
|
+
joker1007.tag_list.clear
|
|
144
|
+
expect(joker1007.tag_list).to be_empty
|
|
145
|
+
|
|
146
|
+
expect { joker1007.save! }.to change { joker1007.reload; joker1007.tags.size }
|
|
147
|
+
.from(1).to(0)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
2
|
+
require "coveralls"
|
|
3
|
+
Coveralls.wear!
|
|
4
|
+
|
|
5
|
+
require "active_record"
|
|
6
|
+
|
|
7
|
+
ActiveRecord::Base.establish_connection(
|
|
8
|
+
adapter: "sqlite3",
|
|
9
|
+
database: ":memory:"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
require 'simple_taggable'
|
|
13
|
+
|
|
14
|
+
# Test Class
|
|
15
|
+
class User < ActiveRecord::Base
|
|
16
|
+
include SimpleTaggable
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
ActiveRecord::Migration.verbose = false
|
|
20
|
+
ActiveRecord::Migrator.migrate File.expand_path("../db/migrate", __FILE__), nil
|
|
21
|
+
|
|
22
|
+
I18n.enforce_available_locales = false # suppress warning
|
|
23
|
+
|
|
24
|
+
require 'database_cleaner'
|
|
25
|
+
require "shoulda-matchers"
|
|
26
|
+
|
|
27
|
+
RSpec.configure do |config|
|
|
28
|
+
config.order = :random
|
|
29
|
+
|
|
30
|
+
config.before(:suite) do
|
|
31
|
+
DatabaseCleaner.strategy = :transaction
|
|
32
|
+
DatabaseCleaner.clean_with(:truncation)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
config.before(:each) do
|
|
36
|
+
DatabaseCleaner.start
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
config.after(:each) do
|
|
40
|
+
DatabaseCleaner.clean
|
|
41
|
+
end
|
|
42
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: simple_taggable
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- joker1007
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-04-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activerecord
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '4'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activesupport
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '4'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '4'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: railties
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '4'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '4'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: bundler
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.5'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.5'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rake
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rspec
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 3.0.0.beta
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 3.0.0.beta
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: database_cleaner
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: sqlite3
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: shoulda-matchers
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: coveralls
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
description: Hyper Simple tagging plugin for ActiveRecord
|
|
154
|
+
email:
|
|
155
|
+
- kakyoin.hierophant@gmail.com
|
|
156
|
+
executables: []
|
|
157
|
+
extensions: []
|
|
158
|
+
extra_rdoc_files: []
|
|
159
|
+
files:
|
|
160
|
+
- ".gitignore"
|
|
161
|
+
- ".rspec"
|
|
162
|
+
- ".travis.yml"
|
|
163
|
+
- Gemfile
|
|
164
|
+
- LICENSE.txt
|
|
165
|
+
- README.md
|
|
166
|
+
- Rakefile
|
|
167
|
+
- lib/generators/simple_taggable/install.rb
|
|
168
|
+
- lib/generators/templates/create_taggings.rb
|
|
169
|
+
- lib/generators/templates/create_tags.rb
|
|
170
|
+
- lib/simple_taggable.rb
|
|
171
|
+
- lib/simple_taggable/models/tag.rb
|
|
172
|
+
- lib/simple_taggable/models/tagging.rb
|
|
173
|
+
- lib/simple_taggable/tag_list.rb
|
|
174
|
+
- lib/simple_taggable/version.rb
|
|
175
|
+
- simple_taggable.gemspec
|
|
176
|
+
- spec/db/migrate/10_create_users.rb
|
|
177
|
+
- spec/simple_taggable/models/tag_spec.rb
|
|
178
|
+
- spec/simple_taggable/models/tagging_spec.rb
|
|
179
|
+
- spec/simple_taggable/tag_list_spec.rb
|
|
180
|
+
- spec/simple_taggable_spec.rb
|
|
181
|
+
- spec/spec_helper.rb
|
|
182
|
+
homepage: ''
|
|
183
|
+
licenses:
|
|
184
|
+
- MIT
|
|
185
|
+
metadata: {}
|
|
186
|
+
post_install_message:
|
|
187
|
+
rdoc_options: []
|
|
188
|
+
require_paths:
|
|
189
|
+
- lib
|
|
190
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - ">="
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '0'
|
|
195
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
|
+
requirements:
|
|
197
|
+
- - ">="
|
|
198
|
+
- !ruby/object:Gem::Version
|
|
199
|
+
version: '0'
|
|
200
|
+
requirements: []
|
|
201
|
+
rubyforge_project:
|
|
202
|
+
rubygems_version: 2.2.2
|
|
203
|
+
signing_key:
|
|
204
|
+
specification_version: 4
|
|
205
|
+
summary: Hyper Simple tagging plugin for ActiveRecord
|
|
206
|
+
test_files:
|
|
207
|
+
- spec/db/migrate/10_create_users.rb
|
|
208
|
+
- spec/simple_taggable/models/tag_spec.rb
|
|
209
|
+
- spec/simple_taggable/models/tagging_spec.rb
|
|
210
|
+
- spec/simple_taggable/tag_list_spec.rb
|
|
211
|
+
- spec/simple_taggable_spec.rb
|
|
212
|
+
- spec/spec_helper.rb
|