gutentag 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 41b7dca53fda65125a90143737854b6fefda5156
4
- data.tar.gz: b0a453c0aa5aa9f40455f3f656c4f74376cdf828
3
+ metadata.gz: a963454a3117dc737b8d4e70e8a02c22c2c2693e
4
+ data.tar.gz: bc7c540a51edbabb378370b9157451a29dcbbfdb
5
5
  SHA512:
6
- metadata.gz: 7331fcc7c2865f3eb6c9c734b7abcbe9e1ae16fc570868b978a78b6d26467ddf04235810f788dcec3e915faed6f7927009e2ccc4bbe0e7fc2e3473521cbcfa70
7
- data.tar.gz: 64b42b9c53f92897b833464b5040bc2fa698f39cbe31c8142d9f5367a137fdc23def53960da25e4ebae6e579bb2395f44586259b0033e9423d0b48eb1bf9b270
6
+ metadata.gz: aaf39b46f22f2348b87dbc8d574d17d5d2b5728810980c16b1c344d894900701ff3434e43f2794c6ce3ce2515039de6fe887161110ee0aa4f0aa54db8152b1b1
7
+ data.tar.gz: 835f63c380604816cd1e5014960f3e75e199f167705635f45cea36467c288b0da7e504c1fa4ad8d35763aec26714cb6a754d58821ed54a244ca906e39cac7d0d
data/.travis.yml CHANGED
@@ -2,7 +2,9 @@ language: ruby
2
2
  script: bundle exec appraisal rspec
3
3
  rvm:
4
4
  - 2.0.0
5
- - 2.2.0
5
+ - 2.2.2
6
+ - 2.3.3
7
+ - 2.4.0
6
8
  before_install:
7
9
  - gem install bundler
8
10
  before_script:
data/Appraisals CHANGED
@@ -1,15 +1,27 @@
1
1
  appraise 'rails_3_2' do
2
- gem 'rails', '~> 3.2.21'
3
- end if RUBY_VERSION < '2.2.0'
2
+ gem 'rails', '~> 3.2.22.5'
3
+ gem 'rack', '~> 1.0', :platforms => [:ruby_20, :ruby_21]
4
+ gem 'nokogiri', '~> 1.6.0', :platforms => [:ruby_20]
5
+ end if RUBY_VERSION.to_f < 2.2
4
6
 
5
7
  appraise 'rails_4_0' do
6
- gem 'rails', '~> 4.0.13'
7
- end
8
+ gem 'rails', '~> 4.0.13'
9
+ gem 'rack', '~> 1.0', :platforms => [:ruby_20, :ruby_21]
10
+ gem 'nokogiri', '~> 1.6.0', :platforms => [:ruby_20]
11
+ end if RUBY_VERSION.to_f < 2.4
8
12
 
9
13
  appraise 'rails_4_1' do
10
- gem 'rails', '~> 4.1.13'
11
- end
14
+ gem 'rails', '~> 4.1.16'
15
+ gem 'rack', '~> 1.0', :platforms => [:ruby_20, :ruby_21]
16
+ gem 'nokogiri', '~> 1.6.0', :platforms => [:ruby_20]
17
+ end if RUBY_VERSION.to_f < 2.4
12
18
 
13
19
  appraise 'rails_4_2' do
14
- gem 'rails', '~> 4.2.4'
15
- end
20
+ gem 'rails', '~> 4.2.7'
21
+ gem 'rack', '~> 1.0', :platforms => [:ruby_20, :ruby_21]
22
+ gem 'nokogiri', '~> 1.6.0', :platforms => [:ruby_20]
23
+ end if RUBY_VERSION.to_f < 2.4
24
+
25
+ appraise 'rails_5_0' do
26
+ gem 'rails', '~> 5.0.1'
27
+ end if RUBY_VERSION.to_f >= 2.2
data/Gemfile CHANGED
@@ -3,3 +3,5 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'test-unit', :platform => :ruby_22
6
+ gem 'rack', '~> 1.0' if RUBY_VERSION.to_f <= 2.1
7
+ gem 'nokogiri', '~> 1.6.0' if RUBY_VERSION.to_f <= 2.0
data/README.md CHANGED
@@ -12,7 +12,7 @@ This was built partly as a proof-of-concept, and partly to see how a tagging gem
12
12
 
13
13
  Get it into your Gemfile - and don't forget the version constraint!
14
14
 
15
- gem 'gutentag', '~> 0.7.0'
15
+ gem 'gutentag', '~> 0.8.0'
16
16
 
17
17
  Next: your tags get persisted to your database, so let's import and run the migrations to get the tables set up:
18
18
 
@@ -44,6 +44,14 @@ If you want to use Gutentag outside of Rails, you can. However, this means you l
44
44
 
45
45
  ## Upgrading
46
46
 
47
+ ### 0.8.0
48
+
49
+ No breaking changes.
50
+
51
+ ### 0.7.0
52
+
53
+ No breaking changes.
54
+
47
55
  ### 0.6.0
48
56
 
49
57
  Rails 4.2 is supported as of Gutentag 0.6.0 - but please note that due to internal changes in ActiveRecord, changes to tag_names will no longer be tracked by your model's dirty state. This feature will continue to work in Rails 3.2 through to 4.1 though.
@@ -80,6 +88,12 @@ Changes to tag_names are not persisted immediately - you must save your taggable
80
88
  article.tag_names << 'ruby'
81
89
  article.save
82
90
 
91
+ You can also query for instances with specified tags. This is OR logic, not AND - it'll match any instances that have *any* of the tags or tag names.
92
+
93
+ Article.tagged_with('tag1', 'tag2')
94
+ Article.tagged_with(Gutentag::Tag.where(name: ['tag1', 'tag2'])
95
+ # => [#<Article id: "123">]
96
+
83
97
  ## Contribution
84
98
 
85
99
  Please note that this project now has a [Contributor Code of Conduct](http://contributor-covenant.org/version/1/0/0/). By participating in this project you agree to abide by its terms.
@@ -8,7 +8,7 @@ class Gutentag::Tag < ActiveRecord::Base
8
8
 
9
9
  scope :by_weight, ->{ order('gutentag_tags.taggings_count DESC') }
10
10
 
11
- validates :name, :presence => true, :uniqueness => {:case_sensitive => false}
11
+ Gutentag.tag_validations.call self
12
12
 
13
13
  before_validation :normalise_name
14
14
 
@@ -3,6 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "test-unit", :platform => :ruby_22
6
- gem "rails", "~> 3.2.21"
6
+ gem "rack", "~> 1.0", :platforms => [:ruby_20, :ruby_21]
7
+ gem "rails", "~> 3.2.22.5"
8
+ gem "nokogiri", "~> 1.6.0", :platforms => [:ruby_20]
7
9
 
8
10
  gemspec :path => "../"
@@ -4,5 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "test-unit", :platform => :ruby_22
6
6
  gem "rails", "~> 4.0.13"
7
+ gem "rack", "~> 1.0", :platforms => [:ruby_20, :ruby_21]
8
+ gem "nokogiri", "~> 1.6.0", :platforms => [:ruby_20]
7
9
 
8
10
  gemspec :path => "../"
@@ -3,6 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "test-unit", :platform => :ruby_22
6
- gem "rails", "~> 4.1.13"
6
+ gem "rails", "~> 4.1.16"
7
+ gem "rack", "~> 1.0", :platforms => [:ruby_20, :ruby_21]
8
+ gem "nokogiri", "~> 1.6.0", :platforms => [:ruby_20]
7
9
 
8
10
  gemspec :path => "../"
@@ -3,6 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "test-unit", :platform => :ruby_22
6
- gem "rails", "~> 4.2.4"
6
+ gem "rails", "~> 4.2.7"
7
+ gem "rack", "~> 1.0", :platforms => [:ruby_20, :ruby_21]
8
+ gem "nokogiri", "~> 1.6.0", :platforms => [:ruby_20]
7
9
 
8
10
  gemspec :path => "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "test-unit", :platform => :ruby_22
6
+ gem "rails", "~> 5.0.1"
7
+
8
+ gemspec :path => "../"
data/gutentag.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = 'gutentag'
4
- s.version = '0.7.0'
4
+ s.version = '0.8.0'
5
5
  s.authors = ['Pat Allan']
6
6
  s.email = ['pat@freelancing-gods.com']
7
7
  s.homepage = 'https://github.com/pat/gutentag'
@@ -15,9 +15,9 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.add_runtime_dependency 'activerecord', '>= 3.2.0'
17
17
 
18
- s.add_development_dependency 'appraisal', '~> 1.0.2'
18
+ s.add_development_dependency 'appraisal', '~> 2.1.0'
19
19
  s.add_development_dependency 'bundler', '>= 1.7.12'
20
- s.add_development_dependency 'combustion', '0.5.1'
20
+ s.add_development_dependency 'combustion', '0.5.5'
21
21
  s.add_development_dependency 'rails'
22
22
  s.add_development_dependency 'rspec-rails', '~> 3.1'
23
23
  s.add_development_dependency 'sqlite3', '~> 1.3.7'
@@ -3,6 +3,8 @@ require 'active_support/concern'
3
3
  module Gutentag::ActiveRecord
4
4
  extend ActiveSupport::Concern
5
5
 
6
+ UNIQUENESS_METHOD = ActiveRecord::VERSION::MAJOR == 3 ? :uniq : :distinct
7
+
6
8
  module ClassMethods
7
9
  def has_many_tags
8
10
  has_many :taggings, :class_name => 'Gutentag::Tagging', :as => :taggable,
@@ -10,7 +12,13 @@ module Gutentag::ActiveRecord
10
12
  has_many :tags, :class_name => 'Gutentag::Tag',
11
13
  :through => :taggings
12
14
 
13
- after_save { |instance| Gutentag::Persistence.new(instance).persist }
15
+ after_save :persist_tags
16
+ end
17
+
18
+ def tagged_with(*tags)
19
+ joins(:tags).where(
20
+ Gutentag::Tag.table_name => {:name => Gutentag::TagNames.call(tags)}
21
+ ).public_send UNIQUENESS_METHOD
14
22
  end
15
23
  end
16
24
 
@@ -27,4 +35,10 @@ module Gutentag::ActiveRecord
27
35
 
28
36
  @tag_names = names
29
37
  end
38
+
39
+ private
40
+
41
+ def persist_tags
42
+ Gutentag::Persistence.new(self).persist
43
+ end
30
44
  end
@@ -0,0 +1,21 @@
1
+ class Gutentag::TagNames
2
+ def self.call(*names)
3
+ new(names).call
4
+ end
5
+
6
+ def initialize(names)
7
+ @names = names.flatten
8
+ end
9
+
10
+ def call
11
+ name_values.collect { |name| Gutentag::TagName.call name }
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :names
17
+
18
+ def name_values
19
+ names.collect { |name| name.respond_to?(:name) ? name.name : name.to_s }
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ class Gutentag::TagValidations
2
+ def self.call(klass)
3
+ new(klass).call
4
+ end
5
+
6
+ def initialize(klass)
7
+ @klass = klass
8
+ end
9
+
10
+ def call
11
+ klass.validates :name, :presence => true,
12
+ :uniqueness => {:case_sensitive => false}
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :klass
18
+ end
data/lib/gutentag.rb CHANGED
@@ -16,12 +16,22 @@ module Gutentag
16
16
  def self.normaliser=(normaliser)
17
17
  @normaliser = normaliser
18
18
  end
19
+
20
+ def self.tag_validations
21
+ @tag_validations ||= Gutentag::TagValidations
22
+ end
23
+
24
+ def self.tag_validations=(tag_validations)
25
+ @tag_validations = tag_validations
26
+ end
19
27
  end
20
28
 
21
29
  require 'gutentag/active_record'
22
30
  require 'gutentag/dirty'
23
31
  require 'gutentag/persistence'
24
32
  require 'gutentag/tag_name'
33
+ require 'gutentag/tag_names'
34
+ require 'gutentag/tag_validations'
25
35
 
26
36
  if ActiveRecord::VERSION::MAJOR == 3
27
37
  Gutentag.dirtier = Gutentag::Dirty
@@ -33,7 +43,7 @@ if defined?(Rails::Engine)
33
43
  require 'gutentag/engine'
34
44
  else
35
45
  require 'active_record'
36
- ActiveRecord::Base.include Gutentag::ActiveRecord
46
+ ActiveRecord::Base.send :include, Gutentag::ActiveRecord
37
47
  require File.expand_path(
38
48
  './../app/models/gutentag/tag', File.dirname(__FILE__)
39
49
  )
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Gutentag::ActiveRecord do
4
+ describe '.tagged_with' do
5
+ let!(:melborne_article) do
6
+ article = Article.create :title => 'Overview'
7
+ article.tag_names << 'melborne'
8
+ article.save!
9
+ article
10
+ end
11
+
12
+ let!(:oregon_article) do
13
+ article = Article.create
14
+ article.tag_names << 'oregon'
15
+ article.save!
16
+ article
17
+ end
18
+
19
+ let!(:melborne_oregon_article) do
20
+ article = Article.create
21
+ article.tag_names = %w(oregon melborne)
22
+ article.save!
23
+ article
24
+ end
25
+
26
+ context 'given a single tag name' do
27
+ subject { Article.tagged_with('melborne') }
28
+
29
+ it { expect(subject.count).to eq 2 }
30
+ it { is_expected.to include melborne_article, melborne_oregon_article }
31
+ it { is_expected.not_to include oregon_article }
32
+ end
33
+
34
+ context 'given a single tag name[symbol]' do
35
+ subject { Article.tagged_with(:melborne) }
36
+
37
+ it { expect(subject.count).to eq 2 }
38
+ it { is_expected.to include melborne_article, melborne_oregon_article }
39
+ it { is_expected.not_to include oregon_article }
40
+ end
41
+
42
+ context 'given multiple tag names' do
43
+ subject { Article.tagged_with('melborne', 'oregon') }
44
+
45
+ it { expect(subject.count).to eq 3 }
46
+ it { is_expected.to include melborne_article, oregon_article, melborne_oregon_article }
47
+ end
48
+
49
+ context 'given an array of tag names' do
50
+ subject { Article.tagged_with(%w(melborne oregon)) }
51
+
52
+ it { expect(subject.count).to eq 3 }
53
+ it { is_expected.to include melborne_article, oregon_article, melborne_oregon_article }
54
+ end
55
+
56
+ context 'given a single tag instance' do
57
+ subject { Article.tagged_with(Gutentag::Tag.find_by_name('melborne')) }
58
+
59
+ it { expect(subject.count).to eq 2 }
60
+ it { is_expected.to include melborne_article, melborne_oregon_article }
61
+ it { is_expected.not_to include oregon_article }
62
+ end
63
+
64
+ context 'given multiple tag objects' do
65
+ subject { Article.tagged_with(Gutentag::Tag.where(name: %w(melborne oregon))) }
66
+
67
+ it { expect(subject.count).to eq 3 }
68
+ it { is_expected.to include melborne_article, oregon_article, melborne_oregon_article }
69
+ end
70
+
71
+ context 'chaining where clause' do
72
+ subject { Article.tagged_with(%w(melborne oregon)).where(title: 'Overview') }
73
+
74
+ it { expect(subject.count).to eq 1 }
75
+ it { is_expected.to include melborne_article }
76
+ it { is_expected.not_to include oregon_article, melborne_oregon_article }
77
+ end
78
+ end
79
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,10 +1,5 @@
1
1
  require 'bundler'
2
2
 
3
- # Get Bundler set up
4
- Bundler.setup :default, :development
5
- # Require Rails first
6
- require 'rails'
7
- # Then require everything else
8
3
  Bundler.require :default, :development
9
4
 
10
5
  Combustion.initialize! :active_record
@@ -12,5 +7,9 @@ Combustion.initialize! :active_record
12
7
  require 'rspec/rails'
13
8
 
14
9
  RSpec.configure do |config|
15
- config.use_transactional_fixtures = true
10
+ if config.respond_to?(:use_transactional_tests)
11
+ config.use_transactional_tests = true
12
+ else
13
+ config.use_transactional_fixtures = true
14
+ end
16
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gutentag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Allan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-27 00:00:00.000000000 Z
11
+ date: 2017-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.0.2
33
+ version: 2.1.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.0.2
40
+ version: 2.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 0.5.1
61
+ version: 0.5.5
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.5.1
68
+ version: 0.5.5
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rails
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +131,7 @@ files:
131
131
  - gemfiles/rails_4_0.gemfile
132
132
  - gemfiles/rails_4_1.gemfile
133
133
  - gemfiles/rails_4_2.gemfile
134
+ - gemfiles/rails_5_0.gemfile
134
135
  - gutentag.gemspec
135
136
  - lib/gutentag.rb
136
137
  - lib/gutentag/active_record.rb
@@ -138,8 +139,11 @@ files:
138
139
  - lib/gutentag/engine.rb
139
140
  - lib/gutentag/persistence.rb
140
141
  - lib/gutentag/tag_name.rb
142
+ - lib/gutentag/tag_names.rb
143
+ - lib/gutentag/tag_validations.rb
141
144
  - spec/acceptance/tag_names_spec.rb
142
145
  - spec/acceptance/tags_spec.rb
146
+ - spec/gutentag/active_record_spec.rb
143
147
  - spec/gutentag/tag_name_spec.rb
144
148
  - spec/internal/app/models/article.rb
145
149
  - spec/internal/config/database.yml
@@ -168,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
172
  version: '0'
169
173
  requirements: []
170
174
  rubyforge_project:
171
- rubygems_version: 2.4.8
175
+ rubygems_version: 2.6.8
172
176
  signing_key:
173
177
  specification_version: 4
174
178
  summary: Good Tags