gutentag 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22821eb031cd1b00ea0f167035e557971b5c3c073ce56964394b96f05b364d5b
4
- data.tar.gz: d523b07744aa3159028c765284b91e4d83bfebff3ad5fdaab27383bfee76e1d7
3
+ metadata.gz: e6935bb3c51e7b225573d2330a1f95b858bed7cd130f0825177aef98c9f0d175
4
+ data.tar.gz: 52201a047a523da00bd33cee60fe72ac1901c1273eb8296b4cfa637349991cf2
5
5
  SHA512:
6
- metadata.gz: 04f2eb02cfd53bac7b394f07e0c2d035b79978b96388f7ea8c083adfb2bc5cbe59a2ae4a4535863455d3cdc62260c8927879ef987cd1596567c3402006b954e8
7
- data.tar.gz: fc75caec7d7a1b03f42136087c78f8cd5c0319595afca6e76b2977b8c7f11b2b75a456434342040f2c8b78a4e9f9091181a327785eae551a52adcbc2ebb3f496
6
+ metadata.gz: 75251e4214a914b48256c60a97241f0db275fd06441e4eb3def15a8ada9fdebf6150208237b81d6715d63c87eae15d2bbcca208c61cc767961f451be60c8737f
7
+ data.tar.gz: 2b8f4b94045a63adfae0bb8e762922f788e49d3b0f37e44d5f54f8a2cd5fb0390f453a532106cc6b4da38b4f9c5cd8bf51211f2ba64713b0fb649a35b5b71e5d
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project (at least, from v0.5.0 onwards) will be documented in this file.
4
4
 
5
+ ## 2.2.0 - 2018-03-04
6
+
7
+ ### Added
8
+
9
+ * Dirty state support for `tag_names` is now available for Rails 4.2 onwards, and is more reliable for Rails 3.2-4.1 (supporting all known methods, such as `tag_names_changed?`, `previous_changes`, etc.)
10
+
11
+ ### Changed
12
+
13
+ * Switch normalising of tag names from a callback within `Gutentag::Tag` to `#name=` ([Tomasz Ras](https://github.com/RasMachineMan) in [#47](https://github.com/pat/gutentag/pull/47)).
14
+
5
15
  ## 2.1.0 - 2018-02-01
6
16
 
7
17
  ### Added
data/README.md CHANGED
@@ -80,7 +80,7 @@ These are the versions the test suite runs against. It's possible it may work on
80
80
  Get it into your Gemfile - and don't forget the version constraint!
81
81
 
82
82
  ```Ruby
83
- gem 'gutentag', '~> 2.1.0'
83
+ gem 'gutentag', '~> 2.2.0'
84
84
  ```
85
85
 
86
86
  Next: your tags get persisted to your database, so let's import and run the migrations to get the tables set up:
@@ -11,8 +11,6 @@ class Gutentag::Tag < ActiveRecord::Base
11
11
 
12
12
  scope :by_weight, lambda { order("gutentag_tags.taggings_count DESC") }
13
13
 
14
- before_validation :normalise_name
15
-
16
14
  def self.find_by_name(name)
17
15
  where(:name => Gutentag.normaliser.call(name)).first
18
16
  end
@@ -21,9 +19,7 @@ class Gutentag::Tag < ActiveRecord::Base
21
19
  find_by_name(name) || create(:name => name)
22
20
  end
23
21
 
24
- private
25
-
26
- def normalise_name
27
- self.name = Gutentag.normaliser.call name
22
+ def name=(value)
23
+ super(Gutentag.normaliser.call(value))
28
24
  end
29
25
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "gutentag"
6
- s.version = "2.1.0"
6
+ s.version = "2.2.0"
7
7
  s.authors = ["Pat Allan"]
8
8
  s.email = ["pat@freelancing-gods.com"]
9
9
  s.homepage = "https://github.com/pat/gutentag"
@@ -17,10 +17,11 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_runtime_dependency "activerecord", ">= 3.2.0"
19
19
 
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.8.0"
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.8.0"
23
+ s.add_development_dependency "database_cleaner", "~> 1.6"
23
24
  s.add_development_dependency "rails"
24
- s.add_development_dependency "rspec-rails", "~> 3.1"
25
- s.add_development_dependency "rubocop", "~> 0.52.1"
25
+ s.add_development_dependency "rspec-rails", "~> 3.1"
26
+ s.add_development_dependency "rubocop", "~> 0.52.1"
26
27
  end
@@ -36,11 +36,7 @@ require "gutentag/remove_unused"
36
36
  require "gutentag/tag_validations"
37
37
  require "gutentag/tagged_with"
38
38
 
39
- if ActiveRecord::VERSION::MAJOR == 3
40
- Gutentag.dirtier = Gutentag::Dirty
41
- elsif ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR < 2
42
- Gutentag.dirtier = Gutentag::Dirty
43
- end
39
+ Gutentag.dirtier = Gutentag::Dirty if ActiveRecord::VERSION::STRING.to_f < 4.2
44
40
 
45
41
  require "active_support/lazy_load_hooks"
46
42
  ActiveSupport.on_load(:gutentag) do
@@ -2,6 +2,25 @@
2
2
 
3
3
  class Gutentag::ActiveRecord
4
4
  def self.call(model)
5
+ new(model).call
6
+ end
7
+
8
+ def initialize(model)
9
+ @model = model
10
+ end
11
+
12
+ def call
13
+ add_associations
14
+ add_callbacks
15
+ add_methods
16
+ add_attribute
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :model
22
+
23
+ def add_associations
5
24
  model.has_many :taggings,
6
25
  :class_name => "Gutentag::Tagging",
7
26
  :as => :taggable,
@@ -9,13 +28,41 @@ class Gutentag::ActiveRecord
9
28
  model.has_many :tags,
10
29
  :class_name => "Gutentag::Tag",
11
30
  :through => :taggings
31
+ end
32
+
33
+ def add_attribute
34
+ if legacy?
35
+ model.define_attribute_method "tag_names"
36
+ else
37
+ model.attribute "tag_names", ActiveRecord::Type::Value.new, :default => []
38
+ end
39
+ end
12
40
 
41
+ def add_callbacks
13
42
  model.after_save :persist_tags
14
43
 
15
- model.send :extend, Gutentag::ActiveRecord::ClassMethods
16
- model.send :include, Gutentag::ActiveRecord::InstanceMethods
44
+ if legacy?
45
+ model.after_save :reset_tag_names
46
+ else
47
+ model.after_commit :reset_tag_names, :on => %i[ create update ]
48
+ end
49
+ end
50
+
51
+ def add_methods
52
+ model.send :extend, Gutentag::ActiveRecord::ClassMethods
53
+
54
+ if legacy?
55
+ model.send :include, Gutentag::ActiveRecord::LegacyInstanceMethods
56
+ else
57
+ model.send :include, Gutentag::ActiveRecord::ModernInstanceMethods
58
+ end
59
+ end
60
+
61
+ def legacy?
62
+ ActiveRecord::VERSION::STRING.to_f < 4.2
17
63
  end
18
64
  end
19
65
 
20
66
  require "gutentag/active_record/class_methods"
21
- require "gutentag/active_record/instance_methods"
67
+ require "gutentag/active_record/legacy_instance_methods"
68
+ require "gutentag/active_record/modern_instance_methods"
@@ -4,4 +4,20 @@ module Gutentag::ActiveRecord::ClassMethods
4
4
  def tagged_with(options)
5
5
  Gutentag::TaggedWith.call self, options
6
6
  end
7
+
8
+ if ActiveRecord::VERSION::STRING.to_f < 4.2
9
+ def skip_time_zone_conversion_for_attributes
10
+ super + [:tag_names]
11
+ end
12
+ end
13
+
14
+ if ActiveRecord::VERSION::STRING.to_f < 4.0
15
+ def create_time_zone_conversion_attribute?(attr_name, column)
16
+ attr_name != "tag_names" && super
17
+ end
18
+
19
+ def attribute_cast_code(attr_name)
20
+ attr_name == "tag_names" ? "v" : super
21
+ end
22
+ end
7
23
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Gutentag::ActiveRecord::InstanceMethods
3
+ # For Rails <= 4.1
4
+ module Gutentag::ActiveRecord::LegacyInstanceMethods
4
5
  def reset_tag_names
5
6
  @tag_names = nil
6
7
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # For Rails 4.2+
4
+ module Gutentag::ActiveRecord::ModernInstanceMethods
5
+ def reset_tag_names
6
+ self.tag_names = nil
7
+ end
8
+
9
+ def tag_names
10
+ self.tag_names = tags.pluck(:name) if super.nil?
11
+
12
+ super
13
+ end
14
+
15
+ def tag_names=(names)
16
+ Gutentag.dirtier.call self, names if Gutentag.dirtier
17
+
18
+ super
19
+ end
20
+
21
+ private
22
+
23
+ def persist_tags
24
+ Gutentag::Persistence.new(Gutentag::ChangeState.new(self)).persist
25
+ end
26
+ end
@@ -11,7 +11,10 @@ class Gutentag::Dirty
11
11
  end
12
12
 
13
13
  def call
14
- instance.changed_attributes[:tag_names] = existing if changes.present?
14
+ return unless changes.present?
15
+
16
+ instance.tag_names_will_change!
17
+ instance.changed_attributes[:tag_names] = existing
15
18
  end
16
19
 
17
20
  private
@@ -14,8 +14,6 @@ class Gutentag::Persistence
14
14
  def persist
15
15
  remove_old
16
16
  add_new
17
-
18
- taggable.reset_tag_names
19
17
  end
20
18
 
21
19
  private
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Dirty state of tag names" do
6
+ let(:article) { Article.create! }
7
+
8
+ it "knows what tag names will change" do
9
+ article.tag_names = ["pancakes"]
10
+
11
+ expect(article).to be_changed
12
+ expect(article.tag_names_changed?).to eq(true)
13
+ expect(article.tag_names_was).to eq([])
14
+ expect(article.tag_names_change).to eq([[], ["pancakes"]])
15
+
16
+ if ActiveRecord::VERSION::STRING.to_f > 4.0
17
+ expect(article.tag_names_changed?(:from => [], :to => ["pancakes"])).
18
+ to eq(true)
19
+ end
20
+
21
+ if ActiveRecord::VERSION::STRING.to_f > 5.0
22
+ expect(article.will_save_change_to_tag_names?).to eq(true)
23
+ expect(article.tag_names_change_to_be_saved).to eq([[], ["pancakes"]])
24
+ expect(article.tag_names_in_database).to eq([])
25
+ end
26
+ end
27
+
28
+ it "knows what tag names have changed" do
29
+ article.tag_names = ["pancakes"]
30
+ article.save
31
+
32
+ expect(article.tag_names).to eq(["pancakes"])
33
+
34
+ expect(article).to_not be_changed
35
+ expect(article.tag_names_changed?).to eq(false)
36
+ expect(article.previous_changes["tag_names"]).to eq([[], ["pancakes"]])
37
+
38
+ if ActiveRecord::VERSION::STRING.to_f >= 5.0
39
+ expect(article.tag_names_previously_changed?).to eq(true)
40
+ expect(article.tag_names_previous_change).to eq([[], ["pancakes"]])
41
+ end
42
+
43
+ if ActiveRecord::VERSION::STRING.to_f > 5.0
44
+ expect(article.saved_change_to_tag_names?).to eq(true)
45
+ expect(article.saved_change_to_tag_names).to eq([[], ["pancakes"]])
46
+ expect(article.saved_changes["tag_names"]).to eq([[], ["pancakes"]])
47
+ expect(article.tag_names_before_last_save).to eq([])
48
+ expect(article.tag_names_change_to_be_saved).to eq(nil)
49
+ expect(article.tag_names_in_database).to eq(["pancakes"])
50
+ end
51
+ end
52
+ end
@@ -3,7 +3,7 @@
3
3
  require "spec_helper"
4
4
 
5
5
  describe "Managing tags via names" do
6
- let(:article) { Article.create }
6
+ let(:article) { Article.create }
7
7
 
8
8
  it "returns tag names" do
9
9
  melbourne = Gutentag::Tag.create :name => "melbourne"
@@ -20,25 +20,6 @@ describe "Managing tags via names" do
20
20
  expect(article.tags.collect(&:name)).to eq(["melbourne"])
21
21
  end
22
22
 
23
- it "makes model dirty when changing through tag_names" do
24
- article.tag_names << "melbourne"
25
- article.save!
26
-
27
- article.tag_names = ["sydney"]
28
-
29
- expect(article.changed_attributes.stringify_keys).
30
- to eq("tag_names" => ["melbourne"])
31
- end if Gutentag.dirtier
32
-
33
- it "does not make model dirty when changing through tag_names" do
34
- article.tag_names << "melbourne"
35
- article.save!
36
-
37
- article.tag_names = ["melbourne"]
38
-
39
- expect(article.changed_attributes).to eq({})
40
- end
41
-
42
23
  it "allows for different tag normalisation" do
43
24
  Gutentag.normaliser = lambda { |name| name.upcase }
44
25
 
@@ -11,8 +11,19 @@ require "rspec/rails"
11
11
 
12
12
  RSpec.configure do |config|
13
13
  if config.respond_to?(:use_transactional_tests)
14
- config.use_transactional_tests = true
14
+ config.use_transactional_tests = false
15
15
  else
16
- config.use_transactional_fixtures = true
16
+ config.use_transactional_fixtures = false
17
+ end
18
+
19
+ config.before(:suite) do
20
+ DatabaseCleaner.strategy = :truncation
21
+ DatabaseCleaner.clean_with(:truncation)
22
+ end
23
+
24
+ config.around(:each) do |example|
25
+ DatabaseCleaner.cleaning do
26
+ example.run
27
+ end
17
28
  end
18
29
  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: 2.1.0
4
+ version: 2.2.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: 2018-01-31 00:00:00.000000000 Z
11
+ date: 2018-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.8.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: database_cleaner
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.6'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rails
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -133,7 +147,8 @@ files:
133
147
  - lib/gutentag.rb
134
148
  - lib/gutentag/active_record.rb
135
149
  - lib/gutentag/active_record/class_methods.rb
136
- - lib/gutentag/active_record/instance_methods.rb
150
+ - lib/gutentag/active_record/legacy_instance_methods.rb
151
+ - lib/gutentag/active_record/modern_instance_methods.rb
137
152
  - lib/gutentag/change_state.rb
138
153
  - lib/gutentag/dirty.rb
139
154
  - lib/gutentag/engine.rb
@@ -144,6 +159,7 @@ files:
144
159
  - lib/gutentag/tagged_with/id_query.rb
145
160
  - lib/gutentag/tagged_with/name_query.rb
146
161
  - lib/gutentag/tagged_with/query.rb
162
+ - spec/acceptance/dirty_state_spec.rb
147
163
  - spec/acceptance/removing_unused_spec.rb
148
164
  - spec/acceptance/tag_names_spec.rb
149
165
  - spec/acceptance/tags_spec.rb
@@ -176,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
192
  version: '0'
177
193
  requirements: []
178
194
  rubyforge_project:
179
- rubygems_version: 2.7.3
195
+ rubygems_version: 2.7.6
180
196
  signing_key:
181
197
  specification_version: 4
182
198
  summary: Good Tags