dm-taggings 0.11.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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