gutentag 0.9.0 → 1.0.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +21 -0
  4. data/.travis.yml +6 -5
  5. data/Appraisals +20 -26
  6. data/Gemfile +13 -8
  7. data/README.md +5 -1
  8. data/Rakefile +9 -5
  9. data/app/models/gutentag/tag.rb +7 -4
  10. data/app/models/gutentag/tagging.rb +5 -3
  11. data/bin/literals +9 -0
  12. data/db/migrate/1_gutentag_tables.rb +5 -3
  13. data/db/migrate/2_gutentag_cache_counter.rb +2 -0
  14. data/db/migrate/3_no_null_counters.rb +8 -4
  15. data/gutentag.gemspec +18 -18
  16. data/lib/gutentag.rb +13 -13
  17. data/lib/gutentag/active_record.rb +11 -6
  18. data/lib/gutentag/active_record/class_methods.rb +4 -16
  19. data/lib/gutentag/active_record/instance_methods.rb +3 -1
  20. data/lib/gutentag/change_state.rb +32 -0
  21. data/lib/gutentag/dirty.rb +4 -1
  22. data/lib/gutentag/engine.rb +2 -4
  23. data/lib/gutentag/persistence.rb +13 -16
  24. data/lib/gutentag/tag_validations.rb +4 -1
  25. data/lib/gutentag/tagged_with.rb +5 -3
  26. data/lib/gutentag/tagged_with/id_query.rb +2 -0
  27. data/lib/gutentag/tagged_with/name_query.rb +2 -0
  28. data/lib/gutentag/tagged_with/query.rb +2 -0
  29. data/spec/acceptance/tag_names_spec.rb +40 -38
  30. data/spec/acceptance/tags_spec.rb +8 -6
  31. data/spec/gutentag/active_record_spec.rb +69 -112
  32. data/spec/gutentag_spec.rb +5 -3
  33. data/spec/internal/app/models/article.rb +2 -0
  34. data/spec/internal/db/schema.rb +2 -0
  35. data/spec/models/gutentag/tag_spec.rb +24 -22
  36. data/spec/models/gutentag/tagging_spec.rb +5 -3
  37. data/spec/spec_helper.rb +4 -2
  38. metadata +11 -43
  39. data/gemfiles/rails_3_2.gemfile +0 -11
  40. data/gemfiles/rails_4_0.gemfile +0 -11
  41. data/gemfiles/rails_4_1.gemfile +0 -11
  42. data/gemfiles/rails_4_2.gemfile +0 -10
  43. data/gemfiles/rails_5_0.gemfile +0 -8
  44. data/gemfiles/rails_5_1.gemfile +0 -8
  45. data/lib/gutentag/has_many_tags.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6dfcf9cc249f5d24513e805b16a351641f06520
4
- data.tar.gz: 819247c5802512d2de7cccaea882f6faa8caa3cb
3
+ metadata.gz: e38980a4454dabe309f3c203ddd7b918f82c5193
4
+ data.tar.gz: 8b50af89daa6b099ae1cca584478758d11ab6b0c
5
5
  SHA512:
6
- metadata.gz: dd5025ccfab3083978980ea492d725235f550cec508d9a955c36ca8bb8337f44027aff7b56fc7d165b96d3fea0fb944369c54917d44ea050dcf243004748d84c
7
- data.tar.gz: '0191ae96a804109c49e990f2bde2e6192d2f0ae37f8f8bea68a12a1294e3e0ce717a179162793982a889332ef80c125bfb9955c004cc9979fc86ca4787dd578a'
6
+ metadata.gz: 31686ed82181198d188ea9e6f323b3e47e9dbb69e53d9458a2d1adbcbd75d17cc2baf6a563428caabe9dcca0552c22b1efb785e5834312baadefa59f2eeb9a4c
7
+ data.tar.gz: d9c469b2df3bc48d991700f0e062aa626efeca3c2d15fd813f0f108705ad471d4d833814fbf61af29d577a276e1936cc418746c8e37ce19e448bbfd12a51978c
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  *.lock
2
+ gemfiles
2
3
  pkg/*
3
4
  spec/internal/db/*.sqlite
5
+ .rubocop-*-yml
@@ -0,0 +1,21 @@
1
+ inherit_from:
2
+ - https://gist.githubusercontent.com/pat/ba3b8ffb1901bfe5439b460943b6b019/raw/.rubocop.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.2
6
+
7
+ Metrics/MethodLength:
8
+ Exclude:
9
+ - db/migrate/1_gutentag_tables.rb
10
+
11
+ Style/MultilineIfModifier:
12
+ Exclude:
13
+ - Appraisals
14
+ - spec/acceptance/tag_names_spec.rb
15
+
16
+ Style/MultilineTernaryOperator:
17
+ Exclude:
18
+ - db/migrate/*.rb
19
+
20
+ Style/SafeNavigation:
21
+ Enabled: false
@@ -1,14 +1,15 @@
1
1
  language: ruby
2
- script: bundle exec appraisal rspec
2
+ script: bundle exec appraisal rake
3
3
  rvm:
4
- - 2.0.0
5
- - 2.2.2
6
- - 2.3.3
7
- - 2.4.0
4
+ - 2.2.8
5
+ - 2.3.5
6
+ - 2.4.2
7
+ - jruby-9.1.13.0
8
8
  before_install:
9
9
  - gem install bundler
10
10
  before_script:
11
11
  - bundle exec appraisal install
12
+ - ./bin/literals
12
13
  env:
13
14
  - DATABASE=postgres
14
15
  - DATABASE=mysql
data/Appraisals CHANGED
@@ -1,34 +1,28 @@
1
- appraise 'rails_3_2' do
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
- gem 'mysql2', '~> 0.3.10'
6
- end if RUBY_VERSION.to_f < 2.2
1
+ # frozen_string_literal: true
7
2
 
8
- appraise 'rails_4_0' do
9
- gem 'rails', '~> 4.0.13'
10
- gem 'rack', '~> 1.0', :platforms => [:ruby_20, :ruby_21]
11
- gem 'nokogiri', '~> 1.6.0', :platforms => [:ruby_20]
12
- gem 'mysql2', '~> 0.3.10'
3
+ appraise "rails_3_2" do
4
+ gem "rails", "~> 3.2.22.5"
5
+ gem "mysql2", "~> 0.3.10", :platform => :ruby
6
+ end if RUBY_VERSION.to_f <= 2.2
7
+
8
+ appraise "rails_4_0" do
9
+ gem "rails", "~> 4.0.13"
10
+ gem "mysql2", "~> 0.3.10", :platform => :ruby
13
11
  end if RUBY_VERSION.to_f < 2.4
14
12
 
15
- appraise 'rails_4_1' do
16
- gem 'rails', '~> 4.1.16'
17
- gem 'rack', '~> 1.0', :platforms => [:ruby_20, :ruby_21]
18
- gem 'nokogiri', '~> 1.6.0', :platforms => [:ruby_20]
19
- gem 'mysql2', '~> 0.3.13'
13
+ appraise "rails_4_1" do
14
+ gem "rails", "~> 4.1.16"
15
+ gem "mysql2", "~> 0.3.13", :platform => :ruby
20
16
  end if RUBY_VERSION.to_f < 2.4
21
17
 
22
- appraise 'rails_4_2' do
23
- gem 'rails', '~> 4.2.7'
24
- gem 'rack', '~> 1.0', :platforms => [:ruby_20, :ruby_21]
25
- gem 'nokogiri', '~> 1.6.0', :platforms => [:ruby_20]
18
+ appraise "rails_4_2" do
19
+ gem "rails", "~> 4.2.8"
26
20
  end if RUBY_VERSION.to_f < 2.4
27
21
 
28
- appraise 'rails_5_0' do
29
- gem 'rails', '~> 5.0.1'
30
- end if RUBY_VERSION.to_f >= 2.2
22
+ appraise "rails_5_0" do
23
+ gem "rails", "~> 5.0.3"
24
+ end if RUBY_VERSION.to_f >= 2.2 && RUBY_PLATFORM != "java"
31
25
 
32
- appraise 'rails_5_1' do
33
- gem 'rails', '~> 5.1.0'
34
- end if RUBY_VERSION.to_f >= 2.2
26
+ appraise "rails_5_1" do
27
+ gem "rails", "~> 5.1.1"
28
+ end if RUBY_VERSION.to_f >= 2.2 && RUBY_PLATFORM != "java"
data/Gemfile CHANGED
@@ -1,12 +1,17 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
 
3
5
  gemspec
4
6
 
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
7
+ gem "test-unit", :platform => :ruby_22
8
+
9
+ gem "mysql2", "~> 0.3", :platform => :ruby
10
+ gem "pg", "~> 0.18", :platform => :ruby
11
+ gem "sqlite3", "~> 1.3", :platform => :ruby
12
+
13
+ gem "activerecord-jdbcmysql-adapter", "~> 1.3.23", :platform => :jruby
14
+ gem "activerecord-jdbcpostgresql-adapter", "~> 1.3.23", :platform => :jruby
15
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.23", :platform => :jruby
8
16
 
9
- gem 'combustion', '~> 0.6',
10
- :git => 'https://github.com/pat/combustion.git',
11
- :branch => 'master',
12
- :ref => 'ef434634d7'
17
+ gem "activerecord", [">= 3.2.22", "< 5"] if RUBY_PLATFORM == "java"
data/README.md CHANGED
@@ -68,7 +68,7 @@ Article.tagged_with(:ids => [tag_a.id, tag_b.id], :match => :all)
68
68
  Get it into your Gemfile - and don't forget the version constraint!
69
69
 
70
70
  ```Ruby
71
- gem 'gutentag', '~> 0.9.0'
71
+ gem 'gutentag', '~> 1.0.0'
72
72
  ```
73
73
 
74
74
  Next: your tags get persisted to your database, so let's import and run the migrations to get the tables set up:
@@ -105,6 +105,10 @@ add_index :gutentag_tags, :taggings_count
105
105
 
106
106
  <h2 id="upgrading">Upgrading</h2>
107
107
 
108
+ ### 1.0.0
109
+
110
+ Behaviour that was deprecated in 0.9.0 (`has_many_tags`, `tagged_with` arguments) have now been removed.
111
+
108
112
  ### 0.9.0
109
113
 
110
114
  * In your models with tags, change `has_many_tags` to `Gutentag::ActiveRecord.call self`.
data/Rakefile CHANGED
@@ -1,8 +1,12 @@
1
- require 'bundler/setup'
2
- require 'bundler/gem_tasks'
3
- require 'rspec/core/rake_task'
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "bundler/gem_tasks"
5
+ require "rspec/core/rake_task"
6
+ require "rubocop/rake_task"
4
7
 
5
8
  RSpec::Core::RakeTask.new(:spec)
9
+ RuboCop::RakeTask.new(:rubocop)
6
10
 
7
- task :default => [:test]
8
- task :test => [:spec]
11
+ task :default => %i[ test ]
12
+ task :test => %i[ rubocop spec ]
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Gutentag::Tag < ActiveRecord::Base
2
- self.table_name = 'gutentag_tags'
4
+ self.table_name = "gutentag_tags"
3
5
 
4
- has_many :taggings, :class_name => 'Gutentag::Tagging',
5
- :dependent => :destroy
6
+ has_many :taggings,
7
+ :class_name => "Gutentag::Tagging",
8
+ :dependent => :destroy
6
9
 
7
10
  attr_accessible :name if ActiveRecord::VERSION::MAJOR == 3
8
11
 
9
- scope :by_weight, ->{ order('gutentag_tags.taggings_count DESC') }
12
+ scope :by_weight, lambda { order("gutentag_tags.taggings_count DESC") }
10
13
 
11
14
  Gutentag.tag_validations.call self
12
15
 
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Gutentag::Tagging < ActiveRecord::Base
2
- self.table_name = 'gutentag_taggings'
4
+ self.table_name = "gutentag_taggings"
3
5
 
4
6
  belongs_to :taggable, :polymorphic => true
5
- belongs_to :tag, :class_name => 'Gutentag::Tag', :counter_cache => true
7
+ belongs_to :tag, :class_name => "Gutentag::Tag", :counter_cache => true
6
8
 
7
9
  validates :taggable, :presence => true
8
10
  validates :tag, :presence => true
9
11
  validates :tag_id, :uniqueness => {
10
- :scope => [:taggable_id, :taggable_type]
12
+ :scope => %i[ taggable_id taggable_type ]
11
13
  }
12
14
  end
@@ -0,0 +1,9 @@
1
+ if (ruby -e "exit RUBY_VERSION.to_f >= 2.4")
2
+ then
3
+ echo "Automatic frozen string literals are supported"
4
+ gem install pragmater -v 4.0.0
5
+ pragmater --add lib --comments "# frozen_string_literal: true" --whitelist "**/*.rb"
6
+ pragmater --add spec --comments "# frozen_string_literal: true" --whitelist "**/*.rb"
7
+ else
8
+ echo "Automatic frozen string literals are not supported."
9
+ fi
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  superclass = ActiveRecord::VERSION::MAJOR < 5 ?
2
4
  ActiveRecord::Migration : ActiveRecord::Migration[4.2]
3
5
  class GutentagTables < superclass
@@ -10,9 +12,9 @@ class GutentagTables < superclass
10
12
  end
11
13
 
12
14
  add_index :gutentag_taggings, :tag_id
13
- add_index :gutentag_taggings, [:taggable_type, :taggable_id]
14
- add_index :gutentag_taggings, [:taggable_type, :taggable_id, :tag_id],
15
- :unique => true, :name => 'unique_taggings'
15
+ add_index :gutentag_taggings, %i[ taggable_type taggable_id ]
16
+ add_index :gutentag_taggings, %i[ taggable_type taggable_id tag_id ],
17
+ :unique => true, :name => "unique_taggings"
16
18
 
17
19
  create_table :gutentag_tags do |t|
18
20
  t.string :name, :null => false
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  superclass = ActiveRecord::VERSION::MAJOR < 5 ?
2
4
  ActiveRecord::Migration : ActiveRecord::Migration[4.2]
3
5
  class GutentagCacheCounter < superclass
@@ -1,13 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  superclass = ActiveRecord::VERSION::MAJOR < 5 ?
2
4
  ActiveRecord::Migration : ActiveRecord::Migration[4.2]
3
5
  class NoNullCounters < superclass
4
6
  def up
5
- change_column :gutentag_tags, :taggings_count, :integer, :default => 0,
6
- :null => false
7
+ change_column :gutentag_tags, :taggings_count, :integer,
8
+ :default => 0,
9
+ :null => false
7
10
  end
8
11
 
9
12
  def down
10
- change_column :gutentag_tags, :taggings_count, :integer, :default => 0,
11
- :null => true
13
+ change_column :gutentag_tags, :taggings_count, :integer,
14
+ :default => 0,
15
+ :null => true
12
16
  end
13
17
  end
@@ -1,26 +1,26 @@
1
+ # frozen_string_literal: true
1
2
  # -*- encoding: utf-8 -*-
3
+
2
4
  Gem::Specification.new do |s|
3
- s.name = 'gutentag'
4
- s.version = '0.9.0'
5
- s.authors = ['Pat Allan']
6
- s.email = ['pat@freelancing-gods.com']
7
- s.homepage = 'https://github.com/pat/gutentag'
8
- s.summary = 'Good Tags'
9
- s.description = 'A good, simple, solid tagging extension for ActiveRecord'
10
- s.license = 'MIT'
5
+ s.name = "gutentag"
6
+ s.version = "1.0.0"
7
+ s.authors = ["Pat Allan"]
8
+ s.email = ["pat@freelancing-gods.com"]
9
+ s.homepage = "https://github.com/pat/gutentag"
10
+ s.summary = "Good Tags"
11
+ s.description = "A good, simple, solid tagging extension for ActiveRecord"
12
+ s.license = "MIT"
11
13
 
12
14
  s.files = `git ls-files`.split("\n")
13
15
  s.test_files = `git ls-files -- {spec}/*`.split("\n")
14
- s.require_paths = ['lib']
16
+ s.require_paths = ["lib"]
15
17
 
16
- s.add_runtime_dependency 'activerecord', '>= 3.2.0'
18
+ s.add_runtime_dependency "activerecord", ">= 3.2.0"
17
19
 
18
- s.add_development_dependency 'appraisal', '~> 2.1.0'
19
- s.add_development_dependency 'bundler', '>= 1.7.12'
20
- s.add_development_dependency 'combustion', '0.5.5'
21
- s.add_development_dependency 'mysql2'
22
- s.add_development_dependency 'pg'
23
- s.add_development_dependency 'rails'
24
- s.add_development_dependency 'rspec-rails', '~> 3.1'
25
- s.add_development_dependency 'sqlite3', '~> 1.3.7'
20
+ s.add_development_dependency "appraisal", "~> 2.1.0"
21
+ s.add_development_dependency "bundler", ">= 1.7.12"
22
+ s.add_development_dependency "combustion", "0.7.0"
23
+ s.add_development_dependency "rails"
24
+ s.add_development_dependency "rspec-rails", "~> 3.1"
25
+ s.add_development_dependency "rubocop", "~> 0.51.0"
26
26
  end
@@ -1,5 +1,6 @@
1
- require 'active_record/version'
2
- require 'active_support/deprecation'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/version"
3
4
 
4
5
  module Gutentag
5
6
  def self.dirtier
@@ -27,12 +28,12 @@ module Gutentag
27
28
  end
28
29
  end
29
30
 
30
- require 'gutentag/active_record'
31
- require 'gutentag/dirty'
32
- require 'gutentag/has_many_tags'
33
- require 'gutentag/persistence'
34
- require 'gutentag/tag_validations'
35
- require 'gutentag/tagged_with'
31
+ require "gutentag/active_record"
32
+ require "gutentag/change_state"
33
+ require "gutentag/dirty"
34
+ require "gutentag/persistence"
35
+ require "gutentag/tag_validations"
36
+ require "gutentag/tagged_with"
36
37
 
37
38
  if ActiveRecord::VERSION::MAJOR == 3
38
39
  Gutentag.dirtier = Gutentag::Dirty
@@ -41,10 +42,9 @@ elsif ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR < 2
41
42
  end
42
43
 
43
44
  if defined?(Rails::Engine)
44
- require 'gutentag/engine'
45
+ require "gutentag/engine"
45
46
  else
46
- require 'active_record'
47
- ActiveRecord::Base.extend Gutentag::HasManyTags
48
- require_relative '../app/models/gutentag/tag'
49
- require_relative '../app/models/gutentag/tagging'
47
+ require "active_record"
48
+ require_relative "../app/models/gutentag/tag"
49
+ require_relative "../app/models/gutentag/tagging"
50
50
  end
@@ -1,9 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Gutentag::ActiveRecord
2
4
  def self.call(model)
3
- model.has_many :taggings, :class_name => 'Gutentag::Tagging',
4
- :as => :taggable, :dependent => :destroy
5
- model.has_many :tags, :class_name => 'Gutentag::Tag',
6
- :through => :taggings
5
+ model.has_many :taggings,
6
+ :class_name => "Gutentag::Tagging",
7
+ :as => :taggable,
8
+ :dependent => :destroy
9
+ model.has_many :tags,
10
+ :class_name => "Gutentag::Tag",
11
+ :through => :taggings
7
12
 
8
13
  model.after_save :persist_tags
9
14
 
@@ -12,5 +17,5 @@ class Gutentag::ActiveRecord
12
17
  end
13
18
  end
14
19
 
15
- require 'gutentag/active_record/class_methods'
16
- require 'gutentag/active_record/instance_methods'
20
+ require "gutentag/active_record/class_methods"
21
+ require "gutentag/active_record/instance_methods"
@@ -1,19 +1,7 @@
1
- module Gutentag::ActiveRecord::ClassMethods
2
- def tagged_with(*arguments)
3
- arguments.flatten!
1
+ # frozen_string_literal: true
4
2
 
5
- case arguments.first
6
- when Hash
7
- Gutentag::TaggedWith.call(self, arguments.first)
8
- when Integer
9
- ActiveSupport::Deprecation.warn "Calling tagged_with with an array of integers will not be supported in Gutentag 1.0. Please use tagged_with :ids => [1, 2] instead."
10
- Gutentag::TaggedWith.call(self, :ids => arguments)
11
- when Gutentag::Tag
12
- ActiveSupport::Deprecation.warn "Calling tagged_with with an array of tags will not be supported in Gutentag 1.0. Please use tagged_with :tags => [tag_a, tag_b] instead."
13
- Gutentag::TaggedWith.call(self, :tags => arguments)
14
- else
15
- ActiveSupport::Deprecation.warn "Calling tagged_with with an array of strings will not be supported in Gutentag 1.0. Please use tagged_with :names => [\"melbourne\", \"ruby\"] instead."
16
- Gutentag::TaggedWith.call(self, :names => arguments)
17
- end
3
+ module Gutentag::ActiveRecord::ClassMethods
4
+ def tagged_with(options)
5
+ Gutentag::TaggedWith.call self, options
18
6
  end
19
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gutentag::ActiveRecord::InstanceMethods
2
4
  def reset_tag_names
3
5
  @tag_names = nil
@@ -16,6 +18,6 @@ module Gutentag::ActiveRecord::InstanceMethods
16
18
  private
17
19
 
18
20
  def persist_tags
19
- Gutentag::Persistence.new(self).persist
21
+ Gutentag::Persistence.new(Gutentag::ChangeState.new(self)).persist
20
22
  end
21
23
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gutentag::ChangeState
4
+ attr_reader :taggable
5
+ attr_writer :normaliser
6
+
7
+ def initialize(taggable)
8
+ @taggable = taggable
9
+ @existing = normalised taggable.tags.collect(&:name)
10
+ @changes = normalised taggable.tag_names
11
+ end
12
+
13
+ def added
14
+ @added ||= changes - existing
15
+ end
16
+
17
+ def removed
18
+ @removed ||= existing - changes
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :existing, :changes
24
+
25
+ def normalised(names)
26
+ names.collect { |name| normaliser.call(name) }.uniq
27
+ end
28
+
29
+ def normaliser
30
+ @normaliser ||= proc { |name| Gutentag.normaliser.call(name) }
31
+ end
32
+ end