dm-taggings 0.11.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.
@@ -39,9 +39,6 @@ module DataMapper
39
39
 
40
40
  # Add instance-methods
41
41
  include DataMapper::Is::Tagger::InstanceMethods
42
-
43
- cattr_accessor(:taggable_object_classes)
44
- self.taggable_object_classes = []
45
42
  end
46
43
 
47
44
  raise "options[:for] is missing" unless options[:for]
@@ -50,6 +47,14 @@ module DataMapper
50
47
  end
51
48
 
52
49
  module ClassMethods
50
+ def self.extended(base)
51
+ base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
52
+ def self.taggable_object_classes
53
+ @@taggable_object_classes ||= []
54
+ end
55
+ RUBY
56
+ end
57
+
53
58
  # Return if a model is tagger
54
59
  #
55
60
  # @return [TrueClass]
@@ -71,10 +76,12 @@ module DataMapper
71
76
  self.taggable_object_classes << taggable_object_class
72
77
 
73
78
  has n, taggable_object_class.tagging_relationship_name,
79
+ :model => taggable_object_class.tagging_class,
74
80
  :constraint => :destroy
75
81
 
76
82
  has n, taggable_object_class.taggable_relationship_name,
77
- :through => taggable_object_class.tagging_relationship_name,
83
+ :model => taggable_object_class.name,
84
+ :through => taggable_object_class.tagging_relationship_name,
78
85
  :constraint => :destroy
79
86
  end
80
87
  end
@@ -94,7 +101,7 @@ module DataMapper
94
101
  #
95
102
  # @api public
96
103
  def tag!(taggable, options={})
97
- unless self.taggable_object_classes.include?(taggable.class)
104
+ unless self.class.taggable_object_classes.include?(taggable.class)
98
105
  raise "Object of type #{taggable.class} isn't taggable!"
99
106
  end
100
107
 
@@ -112,4 +119,3 @@ module DataMapper
112
119
  end # Tagger
113
120
  end # Is
114
121
  end # DataMapper
115
-
@@ -2,12 +2,12 @@ module Tagging
2
2
  include DataMapper::Resource
3
3
 
4
4
  property :id, Serial
5
- property :tag_id, Integer, :min => 1, :required => true
5
+
6
+ belongs_to :tag
6
7
 
7
8
  is :remixable, :suffix => "tag"
8
9
 
9
10
  def tagger=(tagger)
10
- send("#{DataMapper::Inflector.underscore(tagger.class.name).to_sym}=", tagger)
11
+ send("#{DataMapper::Inflector.underscore(DataMapper::Inflector.demodulize(tagger.class.name)).to_sym}=", tagger)
11
12
  end
12
13
  end
13
-
@@ -1,23 +1,21 @@
1
1
  share_examples_for 'A taggable resource' do
2
2
  def create_taggable(attrs={})
3
- @taggable.create(@taggable_attributes.merge(attrs))
3
+ taggable.create(@taggable_attributes.merge(attrs))
4
4
  end
5
5
 
6
- before :all do
7
- %w[ @taggable ].each do |ivar|
8
- raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
9
- end
10
-
11
- @taggable_attributes ||= {}
6
+ def taggable
7
+ raise "taggable should be defined"
8
+ end
12
9
 
13
- @foo_tag = Tag["foo"]
14
- @bar_tag = Tag["bar"]
10
+ let(:foo_tag) { Tag["foo"] }
11
+ let(:bar_tag) { Tag["bar"] }
15
12
 
16
- @tags = [@foo_tag, @bar_tag]
13
+ before :all do
14
+ @taggable_attributes ||= {}
17
15
  end
18
16
 
19
17
  describe "public class methods" do
20
- subject { @taggable }
18
+ subject { taggable }
21
19
 
22
20
  it { should respond_to(:is_taggable) }
23
21
  it { should respond_to(:taggable?) }
@@ -27,40 +25,52 @@ share_examples_for 'A taggable resource' do
27
25
  it { should respond_to(:tagging_class) }
28
26
  it { should respond_to(:tagging_parent_name) }
29
27
  it { should respond_to(:taggable_relationship_name) }
28
+ it { should respond_to(:taggable_options) }
29
+
30
+ describe ".taggable_options" do
31
+ let(:expected_options) { { :tag_list_separator => ',' } }
32
+
33
+ it "should set the defaults" do
34
+ taggable.taggable_options.should == expected_options
35
+ end
36
+ end
30
37
 
31
38
  describe ".taggable?" do
32
39
  it "should return true" do
33
- @taggable.taggable?.should be(true)
40
+ taggable.taggable?.should be(true)
34
41
  end
35
42
  end
36
43
 
37
44
  describe "relationships" do
38
- subject { @taggable.relationships }
45
+ subject { taggable.relationships.named?(taggable.tagging_relationship_name) }
39
46
 
40
- it { should have_key(@taggable.tagging_relationship_name) }
47
+ it { should be(true) }
41
48
 
42
49
  describe "tagging constraint" do
43
- subject { @taggable.tagging_relationship.constraint }
50
+ subject { taggable.tagging_relationship.constraint }
44
51
  it { subject.should eql(:destroy!) }
45
52
  end
46
53
  end
47
54
 
48
55
  describe ".tagged_with" do
49
- before :all do
50
- @resource_one = create_taggable(:tag_list => "red, green, blue")
51
- @resource_two = create_taggable(:tag_list => "orange, yellow")
56
+ let(:resource_one) { create_taggable(:tag_list => "red, green, blue") }
57
+ let(:resource_two) { create_taggable(:tag_list => "orange, yellow") }
58
+
59
+ before do
60
+ resource_one
61
+ resource_two
52
62
  end
53
63
 
64
+ subject { taggable.tagged_with(["red", "yellow", "purple"]) }
65
+
54
66
  it "should return correct resources" do
55
- result = @taggable.tagged_with(["red", "yellow", "purple"])
56
- result.size.should eql(2)
57
- result.should include(@resource_one, @resource_two)
67
+ should == [ resource_one, resource_two ]
58
68
  end
59
69
  end
60
70
  end
61
71
 
62
72
  describe "public instance methods" do
63
- subject { @taggable.new }
73
+ subject { taggable.new }
64
74
 
65
75
  it { should respond_to(:tag) }
66
76
  it { should respond_to(:tag!) }
@@ -70,189 +80,173 @@ share_examples_for 'A taggable resource' do
70
80
  it { should respond_to(:taggings) }
71
81
 
72
82
  describe ".tag" do
73
- before :all do
74
- @resource = create_taggable
75
- @taggings = @resource.tag([@foo_tag, @bar_tag])
76
- end
83
+ let(:resource) { create_taggable }
84
+ let(:tags) { resource.tag([ foo_tag, bar_tag ]) }
77
85
 
78
- it "should set new taggings" do
79
- @taggings.should eql(@resource.taggings)
86
+ it "should set new tags" do
87
+ tags.should == resource.tags
80
88
  end
81
89
 
82
- it "should not create new taggings" do
83
- @resource.tags.should be_empty
90
+ it "should not save new taggings" do
91
+ resource.taggings.all? { |tagging| tagging.new? }.should be(true)
84
92
  end
85
93
  end
86
94
 
87
95
  describe ".tag!" do
88
- before :all do
89
- @resource = create_taggable
90
- @taggings = @resource.tag!([@foo_tag, @bar_tag])
96
+ let(:resource) { create_taggable }
97
+ let(:new_tags) { [ foo_tag, bar_tag ] }
98
+ let(:tags) { resource.tag!(new_tags) }
99
+
100
+
101
+ it "returns added tags" do
102
+ tags.should == new_tags
91
103
  end
92
104
 
93
- it "should create new taggings" do
94
- @resource.reload.tags.should include(@foo_tag, @bar_tag)
105
+ it "creates new taggings" do
106
+ resource.tags.should == tags
95
107
  end
96
108
  end
97
109
 
98
110
  describe ".untag" do
99
- describe "all" do
100
- before :all do
101
- @resource = create_taggable
102
- @taggings = @resource.tag!([@foo_tag, @bar_tag])
111
+ let(:tags) { [ foo_tag, bar_tag ] }
112
+ let(:resource) { create_taggable(:tags => tags) }
103
113
 
104
- @resource.untag
114
+ describe "all" do
115
+ before do
116
+ resource.untag
105
117
  end
106
118
 
107
- it "should remove the taggings from the collection" do
108
- @resource.taggings.should be_empty
119
+ it "removes taggings from loaded collection" do
120
+ resource.tags.should be_empty
109
121
  end
110
122
 
111
- it "should not destroy the taggings" do
112
- @resource.reload.tags.should_not be_empty
123
+ it "doesn't destroy the taggings" do
124
+ resource.reload.tags.should == tags
113
125
  end
114
126
  end
115
127
 
116
- describe "specific names" do
117
- before :all do
118
- @resource = create_taggable
119
- @taggings = @resource.tag!([@foo_tag, @bar_tag])
120
-
121
- @resource.untag([@foo_tag])
128
+ describe "specific tags" do
129
+ before do
130
+ resource.untag([ foo_tag ])
122
131
  end
123
132
 
124
- it "should remove the related tagging from the collection" do
125
- @resource.taggings.size.should eql(1)
126
- end
127
-
128
- it "should remove the related tag" do
129
- @resource.tags.should_not include(@foo_tag)
133
+ it "should remove the tag from loaded collection" do
134
+ resource.tags.should == [ bar_tag ]
130
135
  end
131
136
  end
132
137
 
133
138
  describe "when save is called" do
134
- before :all do
135
- @resource = create_taggable
136
- @taggings = @resource.tag!([@foo_tag, @bar_tag])
137
-
138
- @resource.untag
139
- end
140
-
141
- it "should return true" do
142
- pending "Currently DataMapper doesn't support saving an empty collection" do
143
- @resource.save.should be(true)
144
- end
139
+ before do
140
+ resource.untag
141
+ resource.save
142
+ resource.reload
145
143
  end
146
144
 
147
145
  it "should destroy taggings" do
148
- pending "Currently DataMapper doesn't support saving an empty collection" do
149
- @resource.reload.taggings.should be_empty
150
- end
146
+ resource.taggings.should be_empty
151
147
  end
152
148
 
153
149
  it "should destroy tags" do
154
- pending "Currently DataMapper doesn't support saving an empty collection" do
155
- @resource.reload.tags.should be_empty
156
- end
150
+ resource.tags.should be_empty
157
151
  end
158
152
  end
159
153
  end
160
154
 
161
155
  describe ".untag!" do
156
+ let(:tags) { [ foo_tag, bar_tag ] }
157
+ let(:resource) { create_taggable(:tags => tags) }
158
+
162
159
  describe "all" do
163
- before :all do
164
- @resource = create_taggable
165
- @taggings = @resource.tag!([@foo_tag, @bar_tag])
160
+ before do
161
+ @result = resource.untag!
162
+ resource.reload
163
+ end
166
164
 
167
- @resource.untag!
165
+ it "returns removed tags" do
166
+ @result == tags
168
167
  end
169
168
 
170
- it "should destroy the taggings" do
171
- @resource.reload.taggings.should be_empty
169
+ it "destroys the taggings" do
170
+ resource.tags.should be_empty
172
171
  end
173
172
  end
174
173
 
175
- describe "specific names" do
176
- before :all do
177
- @resource = create_taggable
178
- @taggings = @resource.tag!([@foo_tag, @bar_tag])
179
-
180
- @resource.untag!([@foo_tag])
181
- @resource.reload
174
+ describe "specific tags" do
175
+ before do
176
+ resource.untag!([ foo_tag ])
177
+ resource.reload
182
178
  end
183
179
 
184
- subject { @resource.tags }
180
+ subject { resource.tags }
185
181
 
186
- it { should_not include(@foo_tag) }
187
- it { should include(@bar_tag) }
182
+ it { should_not include(foo_tag) }
183
+ it { should include(bar_tag) }
188
184
  end
189
185
  end
190
186
 
191
187
  describe ".tag_list=" do
192
188
  describe "with a list of tag names" do
193
189
  describe "with blank values" do
194
- before :all do
195
- @resource = create_taggable(:tag_list => "foo, , ,bar, , ")
196
- end
190
+ let(:resource) { create_taggable(:tag_list => "foo, , ,bar, , ") }
197
191
 
198
192
  it "should add new tags and reject blank names" do
199
- @resource.reload.tags.should include(Tag["foo"], Tag["bar"])
193
+ resource.tags.should == [ Tag["foo"], Tag["bar"] ]
200
194
  end
201
195
  end
202
196
 
203
197
  describe "when tags are removed and added" do
204
- before :all do
205
- @resource = create_taggable(:tag_list => "foo, bar")
206
- @resource.update(:tag_list => "foo, bar, pub")
198
+ let(:resource) { create_taggable(:tag_list => "foo, bar") }
199
+
200
+ before do
201
+ resource.update(:tag_list => "foo, bar, pub")
207
202
  end
208
203
 
209
204
  it "should add new tags" do
210
- @resource.reload.tags.should include(Tag["bar"], Tag["bar"], Tag["pub"])
205
+ resource.tags.should == [ Tag["foo"], Tag["bar"], Tag["pub"] ]
211
206
  end
212
207
  end
213
208
 
214
209
  describe "when tags are added" do
215
- before :all do
216
- @resource = create_taggable(:tag_list => "foo, bar")
217
- @resource.update(:tag_list => "bar, pub")
210
+ let(:resource) { create_taggable(:tag_list => "foo, bar") }
211
+
212
+ before do
213
+ resource.update(:tag_list => "bar, pub")
218
214
  end
219
215
 
220
216
  it "should add new tags" do
221
- @resource.reload.tags.should include(Tag["bar"], Tag["pub"])
217
+ resource.tags.should include(Tag["bar"], Tag["pub"])
222
218
  end
223
219
 
224
220
  it "should remove tags" do
225
- @resource.reload.tags.should_not include(Tag["foo"])
221
+ resource.tags.should_not include(Tag["foo"])
226
222
  end
227
223
  end
228
224
  end
229
225
 
230
226
  describe "when no list of tag names is given" do
227
+ let(:resource) { create_taggable(:tag_list => "foo, bar") }
228
+
231
229
  before :all do
232
- @resource = create_taggable(:tag_list => "foo, bar")
233
- @resource.update(:tag_list => "")
230
+ resource.update(:tag_list => "")
234
231
  end
235
232
 
236
233
  it "should destroy taggings" do
237
- @resource.reload.taggings.should be_blank
234
+ resource.reload.taggings.should be_blank
238
235
  end
239
236
 
240
237
  it "should remove the tags" do
241
- @resource.reload.tags.should be_blank
238
+ resource.reload.tags.should be_blank
242
239
  end
243
240
  end
244
241
  end
245
242
 
246
243
  describe ".tag_list" do
247
- before :all do
248
- @tag_names = %w(red green blue)
249
- @expected = @tag_names.join(', ')
250
- @resource = create_taggable(:tag_list => @expected)
251
- end
244
+ let(:expected_tag_names) { %w(nice cool awesome).join(',') }
245
+ let(:resource) { create_taggable(:tag_list => expected_tag_names) }
252
246
 
253
- it "should return the list of tag names" do
254
- @resource.tag_list.should eql(@expected)
255
- end
247
+ subject { resource.tag_list }
248
+
249
+ it { should == expected_tag_names }
256
250
  end
257
251
  end
258
252
  end
@@ -1,32 +1,33 @@
1
1
  share_examples_for 'A tagger resource' do
2
- before :all do
3
- %w[ @tagger @taggable ].each do |ivar|
4
- raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
5
- end
6
-
7
- @foo_tag = Tag["foo"]
8
- @bar_tag = Tag["bar"]
2
+ def taggable
3
+ raise "taggable should be defined"
4
+ end
9
5
 
10
- @tags = [@foo_tag, @bar_tag]
6
+ def tagger
7
+ raise "tagger should be defined"
11
8
  end
12
9
 
13
- subject { @tagger }
10
+ let(:foo_tag) { Tag["foo"] }
11
+ let(:bar_tag) { Tag["bar"] }
12
+ let(:tags) { [ foo_tag, bar_tag ] }
13
+
14
+ subject { tagger }
14
15
 
15
16
  [ :is_tagger, :tagger?, :add_taggable_object_classes, :taggable_object_classes ].each do |method|
16
17
  it { should respond_to(method) }
17
18
  end
18
19
 
19
20
  describe ".tagger?" do
20
- subject { @tagger.tagger? }
21
+ subject { tagger.tagger? }
21
22
  it { should be(true) }
22
23
  end
23
24
 
24
25
  describe "#tag!" do
25
26
  before :all do
26
- @tagger_resource = @tagger.create
27
- @taggable_resource = @taggable.create
27
+ @tagger_resource = tagger.create
28
+ @taggable_resource = taggable.create
28
29
 
29
- @tags = @tagger_resource.tag!(@taggable_resource, :with => @tags)
30
+ @tags = @tagger_resource.tag!(@taggable_resource, :with => tags)
30
31
  end
31
32
 
32
33
  it "should tag the taggable resource" do
@@ -34,12 +35,12 @@ share_examples_for 'A tagger resource' do
34
35
  end
35
36
 
36
37
  it "should associate tagger with taggable" do
37
- @tagger_resource.reload.send(DataMapper::Inflector.underscore(@taggable.name).pluralize).should include(@taggable_resource)
38
+ @tagger_resource.reload.send(DataMapper::Inflector.pluralize(DataMapper::Inflector.underscore(DataMapper::Inflector.demodulize(taggable.name)))).should include(@taggable_resource)
38
39
  end
39
40
 
40
41
  it "should associate taggings with tagger" do
41
42
  @taggable_resource.taggings.each do |tagging|
42
- tagging.send(DataMapper::Inflector.underscore(@tagger.name)).should eql(@tagger_resource)
43
+ tagging.send(DataMapper::Inflector.underscore(DataMapper::Inflector.demodulize(tagger.name))).should eql(@tagger_resource)
43
44
  end
44
45
  end
45
46
  end