gutentag 0.2.2 → 0.3.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 +4 -4
- data/README.md +7 -1
- data/gutentag.gemspec +1 -1
- data/lib/gutentag.rb +1 -1
- data/lib/gutentag/active_record.rb +8 -8
- data/lib/gutentag/persistence.rb +38 -0
- data/spec/acceptance/tag_names_spec.rb +18 -26
- metadata +3 -3
- data/lib/gutentag/tag_names.rb +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dda4e9077e5d19af15ad0ae9bab60a64147f4c11
|
4
|
+
data.tar.gz: dcd0271e7e842c8edf3fc25ba1f4254c4853369a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc49c2eaa8236fd2991c5213fb53bce4077890135185f0cf5730331603a384813fe0ecf3427d370719e11931044095ba65297c38052a43a4343e396311e77d68
|
7
|
+
data.tar.gz: b734e64f5731e2458af240c09a26e650a2d103d5d9bdb8649c52a0cf9d868cb1d06f1fd0fd61271c93b4764c3a7ea0dfa79b3f61ae5e6e932e042bd6321977ff
|
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Gutentag
|
2
2
|
|
3
|
+
[](http://badge.fury.io/rb/gutentag)
|
3
4
|
[](https://travis-ci.org/pat/gutentag)
|
4
5
|
[](https://codeclimate.com/github/pat/gutentag)
|
5
6
|
|
@@ -11,7 +12,7 @@ This was built partly as a proof-of-concept, and partly to see how a tagging gem
|
|
11
12
|
|
12
13
|
Get it into your Gemfile - and don't forget the version constraint!
|
13
14
|
|
14
|
-
gem 'gutentag', '~> 0.
|
15
|
+
gem 'gutentag', '~> 0.3.0'
|
15
16
|
|
16
17
|
Next: your tags get persisted to your database, so let's import and run the migrations to get the tables set up:
|
17
18
|
|
@@ -36,6 +37,11 @@ That's all it takes to get a tags association on each article. Of course, popula
|
|
36
37
|
article.tag_names -= ['ruby']
|
37
38
|
article.tag_names #=> ['pancakes', 'melbourne', 'portland']
|
38
39
|
|
40
|
+
Changes to tag_names are not persisted immediately - you must save your taggable object to have the tag changes reflected in your database:
|
41
|
+
|
42
|
+
article.tag_names << 'ruby'
|
43
|
+
article.save
|
44
|
+
|
39
45
|
## Licence
|
40
46
|
|
41
47
|
Copyright (c) 2013, Gutentag is developed and maintained by Pat Allan, and is released under the open MIT Licence.
|
data/gutentag.gemspec
CHANGED
data/lib/gutentag.rb
CHANGED
@@ -9,18 +9,18 @@ module Gutentag::ActiveRecord
|
|
9
9
|
:dependent => :destroy
|
10
10
|
has_many :tags, :class_name => 'Gutentag::Tag',
|
11
11
|
:through => :taggings
|
12
|
+
|
13
|
+
after_save Gutentag::Persistence
|
14
|
+
|
15
|
+
attr_writer :tag_names
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
15
|
-
def
|
16
|
-
@tag_names
|
19
|
+
def reset_tag_names
|
20
|
+
@tag_names = nil
|
17
21
|
end
|
18
22
|
|
19
|
-
def tag_names
|
20
|
-
|
21
|
-
@tag_names = names
|
22
|
-
else
|
23
|
-
@tag_names = Gutentag::TagNames.new_with_names self, names
|
24
|
-
end
|
23
|
+
def tag_names
|
24
|
+
@tag_names ||= tags.collect(&:name)
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Gutentag::Persistence
|
2
|
+
def self.after_save(taggable)
|
3
|
+
new(taggable).persist
|
4
|
+
end
|
5
|
+
|
6
|
+
def initialize(taggable)
|
7
|
+
@taggable = taggable
|
8
|
+
@existing = normalised taggable.tags.collect(&:name)
|
9
|
+
@changes = normalised taggable.tag_names
|
10
|
+
end
|
11
|
+
|
12
|
+
def persist
|
13
|
+
remove_old
|
14
|
+
add_new
|
15
|
+
|
16
|
+
taggable.reset_tag_names
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :taggable, :existing, :changes
|
22
|
+
|
23
|
+
def add_new
|
24
|
+
(changes - existing).each do |name|
|
25
|
+
taggable.tags << Gutentag::Tag.find_or_create(name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def normalised(names)
|
30
|
+
names.collect { |name| Gutentag::TagName.normalise(name) }.uniq
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_old
|
34
|
+
(existing - changes).each do |name|
|
35
|
+
taggable.tags.delete Gutentag::Tag.find_by_name(name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -8,11 +8,12 @@ describe "Managing tags via names" do
|
|
8
8
|
|
9
9
|
article.tags << melbourne
|
10
10
|
|
11
|
-
article.tag_names.
|
11
|
+
article.tag_names.should == ['melbourne']
|
12
12
|
end
|
13
13
|
|
14
14
|
it "adds tags via their names" do
|
15
15
|
article.tag_names << 'melbourne'
|
16
|
+
article.save!
|
16
17
|
|
17
18
|
article.tags.collect(&:name).should == ['melbourne']
|
18
19
|
end
|
@@ -20,32 +21,24 @@ describe "Managing tags via names" do
|
|
20
21
|
it "doesn't complain when adding an existing tag" do
|
21
22
|
article.tag_names << 'melbourne'
|
22
23
|
article.tag_names << 'melbourne'
|
24
|
+
article.save!
|
23
25
|
|
24
26
|
article.tags.collect(&:name).should == ['melbourne']
|
25
27
|
end
|
26
28
|
|
27
29
|
it "accepts a completely new set of tags" do
|
28
30
|
article.tag_names = ['portland', 'oregon']
|
31
|
+
article.save!
|
29
32
|
|
30
33
|
article.tags.collect(&:name).should == ['portland', 'oregon']
|
31
34
|
end
|
32
35
|
|
33
|
-
it "enumerates through tag names" do
|
34
|
-
article.tag_names = ['melbourne', 'victoria']
|
35
|
-
names = []
|
36
|
-
|
37
|
-
article.tag_names.each do |name|
|
38
|
-
names << name
|
39
|
-
end
|
40
|
-
|
41
|
-
names.should == ['melbourne', 'victoria']
|
42
|
-
end
|
43
|
-
|
44
36
|
it "does not allow duplication of tags" do
|
45
37
|
existing = Article.create
|
46
38
|
existing.tags << Gutentag::Tag.create(:name => 'portland')
|
47
39
|
|
48
40
|
article.tag_names = ['portland']
|
41
|
+
article.save!
|
49
42
|
|
50
43
|
existing.tag_ids.should == article.tag_ids
|
51
44
|
end
|
@@ -53,6 +46,7 @@ describe "Managing tags via names" do
|
|
53
46
|
it "appends tag names" do
|
54
47
|
article.tag_names = ['portland']
|
55
48
|
article.tag_names += ['oregon', 'ruby']
|
49
|
+
article.save!
|
56
50
|
|
57
51
|
article.tags.collect(&:name).should == ['portland', 'oregon', 'ruby']
|
58
52
|
end
|
@@ -60,6 +54,7 @@ describe "Managing tags via names" do
|
|
60
54
|
it "does not repeat appended names that already exist" do
|
61
55
|
article.tag_names = ['portland', 'oregon']
|
62
56
|
article.tag_names += ['oregon', 'ruby']
|
57
|
+
article.save!
|
63
58
|
|
64
59
|
article.tags.collect(&:name).should == ['portland', 'oregon', 'ruby']
|
65
60
|
end
|
@@ -67,6 +62,7 @@ describe "Managing tags via names" do
|
|
67
62
|
it "removes a single tag name" do
|
68
63
|
article.tag_names = ['portland', 'oregon']
|
69
64
|
article.tag_names.delete 'oregon'
|
65
|
+
article.save!
|
70
66
|
|
71
67
|
article.tags.collect(&:name).should == ['portland']
|
72
68
|
end
|
@@ -74,32 +70,28 @@ describe "Managing tags via names" do
|
|
74
70
|
it "removes tag names" do
|
75
71
|
article.tag_names = ['portland', 'oregon', 'ruby']
|
76
72
|
article.tag_names -= ['oregon', 'ruby']
|
73
|
+
article.save!
|
77
74
|
|
78
75
|
article.tags.collect(&:name).should == ['portland']
|
79
76
|
end
|
80
77
|
|
81
|
-
it "provides union operators" do
|
82
|
-
article.tag_names = ['portland', 'ruby']
|
83
|
-
article.tag_names |= ['ruby', 'melbourne']
|
84
|
-
|
85
|
-
article.tags.collect(&:name).should == ['portland', 'ruby', 'melbourne']
|
86
|
-
end
|
87
|
-
|
88
|
-
it "provides intersection operators" do
|
89
|
-
article.tag_names = ['portland', 'ruby']
|
90
|
-
article.tag_names &= ['ruby', 'melbourne']
|
91
|
-
|
92
|
-
article.tags.collect(&:name).should == ['ruby']
|
93
|
-
end
|
94
|
-
|
95
78
|
it "matches tag names ignoring case" do
|
96
79
|
article.tag_names = ['portland']
|
97
80
|
article.tag_names += ['Portland']
|
81
|
+
article.save!
|
98
82
|
|
99
83
|
article.tags.collect(&:name).should == ['portland']
|
100
84
|
|
101
85
|
article.tag_names << 'Portland'
|
86
|
+
article.save!
|
102
87
|
|
103
88
|
article.tags.collect(&:name).should == ['portland']
|
104
89
|
end
|
90
|
+
|
91
|
+
it "allows setting of tag names on unpersisted objects" do
|
92
|
+
article = Article.new :tag_names => ['melbourne', 'pancakes']
|
93
|
+
article.save!
|
94
|
+
|
95
|
+
article.tag_names.should == ['melbourne', 'pancakes']
|
96
|
+
end
|
105
97
|
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.
|
4
|
+
version: 0.3.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: 2013-07
|
11
|
+
date: 2013-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -86,8 +86,8 @@ files:
|
|
86
86
|
- lib/gutentag.rb
|
87
87
|
- lib/gutentag/active_record.rb
|
88
88
|
- lib/gutentag/engine.rb
|
89
|
+
- lib/gutentag/persistence.rb
|
89
90
|
- lib/gutentag/tag_name.rb
|
90
|
-
- lib/gutentag/tag_names.rb
|
91
91
|
- spec/acceptance/tag_names_spec.rb
|
92
92
|
- spec/acceptance/tags_spec.rb
|
93
93
|
- spec/gutentag/tag_name_spec.rb
|
data/lib/gutentag/tag_names.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
class Gutentag::TagNames
|
2
|
-
include Enumerable
|
3
|
-
|
4
|
-
def self.new_with_names(taggable, names)
|
5
|
-
new(taggable).replace names
|
6
|
-
end
|
7
|
-
|
8
|
-
def initialize(taggable)
|
9
|
-
@taggable = taggable
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_a
|
13
|
-
taggable.tags.collect &:name
|
14
|
-
end
|
15
|
-
|
16
|
-
def +(array)
|
17
|
-
normalised(array).each { |name| self.<< name }
|
18
|
-
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
def -(array)
|
23
|
-
normalised(array).each { |name| self.delete name }
|
24
|
-
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
def <<(name)
|
29
|
-
tag = Gutentag::Tag.find_or_create name
|
30
|
-
|
31
|
-
taggable.tags << tag unless taggable.tags.include?(tag)
|
32
|
-
end
|
33
|
-
|
34
|
-
def |(array)
|
35
|
-
to_a | normalised(array)
|
36
|
-
end
|
37
|
-
|
38
|
-
def &(array)
|
39
|
-
to_a & normalised(array)
|
40
|
-
end
|
41
|
-
|
42
|
-
def clear
|
43
|
-
taggable.tags.clear
|
44
|
-
end
|
45
|
-
|
46
|
-
def delete(name)
|
47
|
-
taggable.tags.delete Gutentag::Tag.find_by_name(name)
|
48
|
-
end
|
49
|
-
|
50
|
-
def each(&block)
|
51
|
-
to_a.each &block
|
52
|
-
end
|
53
|
-
|
54
|
-
def replace(names)
|
55
|
-
clear
|
56
|
-
self.+ names
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
attr_reader :taggable
|
62
|
-
|
63
|
-
def normalised(array)
|
64
|
-
array.collect { |name| Gutentag::TagName.normalise(name) }
|
65
|
-
end
|
66
|
-
end
|