simple_taggable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ - 2.0.0
5
+
6
+ before_script:
7
+ - bundle exec rake test:copy_migrations
8
+
9
+ notifications:
10
+ email:
11
+ on_success: change
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simple_taggable.gemspec
4
+ gemspec
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
+ [![Build Status](https://travis-ci.org/joker1007/simple_taggable.svg?branch=master)](https://travis-ci.org/joker1007/simple_taggable)
3
+ [![Coverage Status](https://coveralls.io/repos/joker1007/simple_taggable/badge.png)](https://coveralls.io/r/joker1007/simple_taggable)
4
+ [![Code Climate](https://codeclimate.com/github/joker1007/simple_taggable.png)](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,9 @@
1
+ class CreateTags < ActiveRecord::Migration
2
+ def change
3
+ create_table :tags do |t|
4
+ t.string :name, index: true, unique: true
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ 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,9 @@
1
+ module SimpleTaggable
2
+ module Models
3
+ class Tag < ::ActiveRecord::Base
4
+ validates_uniqueness_of :name
5
+
6
+ has_many :taggings
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module SimpleTaggable
2
+ module Models
3
+ class Tagging < ::ActiveRecord::Base
4
+ belongs_to :tag
5
+ belongs_to :taggable, polymorphic: true
6
+
7
+ validates_presence_of :tag, :taggable
8
+ end
9
+ end
10
+ 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,3 @@
1
+ module SimpleTaggable
2
+ VERSION = "0.0.1"
3
+ 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,9 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ 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
@@ -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