publishable 0.3.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.
- data/.document +2 -1
- data/.rspec +2 -0
- data/Gemfile +43 -0
- data/Gemfile.lock +60 -0
- data/{LICENSE → LICENSE.txt} +1 -0
- data/README.rdoc +87 -0
- data/Rakefile +30 -28
- data/lib/publishable.rb +252 -20
- data/lib/publishable/railtie.rb +2 -0
- data/lib/publishable/version.rb +40 -0
- data/publishable.gemspec +41 -33
- data/spec/publishable_spec.rb +281 -83
- data/spec/spec_helper.rb +27 -7
- data/spec/support/matcher_each.rb +12 -0
- metadata +98 -30
- data/.gitignore +0 -22
- data/README.textile +0 -29
- data/VERSION +0 -1
- data/db/schema.rb +0 -8
- data/spec/spec.opts +0 -2
data/lib/publishable/railtie.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Publishable
|
4
|
+
|
5
|
+
# Defines the current version for this gem. Versions are specified as a dot-delimited string:
|
6
|
+
#
|
7
|
+
# major.minor.patch.prerelease+build
|
8
|
+
#
|
9
|
+
# When incrementing any field, all lower-rank fields should be reset to zero or nil.
|
10
|
+
#
|
11
|
+
# @author David Daniell / тιηуηυмвєяѕ <info@tinynumbers.com>
|
12
|
+
module VERSION
|
13
|
+
|
14
|
+
# The major version number, only incremented for a major overhaul.
|
15
|
+
MAJOR = 1
|
16
|
+
|
17
|
+
# The minor version number, incremented for significant releases of new features.
|
18
|
+
MINOR = 0
|
19
|
+
|
20
|
+
# The patch-level, incremented for minor bug fixes / patches.
|
21
|
+
PATCH = 0
|
22
|
+
|
23
|
+
# Prerelease specification for e.g. "alpha", "beta.1", etc
|
24
|
+
PRERELEASE = nil
|
25
|
+
|
26
|
+
# The build number; can be used for e.g. git version of current build, etc.
|
27
|
+
BUILD = nil
|
28
|
+
|
29
|
+
# Return the version as a dot-delimited string.
|
30
|
+
# @return [String] the current gem version
|
31
|
+
def self.to_s
|
32
|
+
@version_string ||= begin
|
33
|
+
v = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
34
|
+
v = PRERELEASE ? "#{v}.#{PRERELEASE}" : v
|
35
|
+
BUILD ? "#{v}+#{BUILD}" : v
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
data/publishable.gemspec
CHANGED
@@ -1,57 +1,65 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.
|
7
|
+
s.name = "publishable"
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Martin Linkhorst"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
s.email =
|
11
|
+
s.authors = ["Martin Linkhorst", "\321\202\316\271\316\267\321\203\316\267\317\205\320\274\320\262\321\224\321\217\321\225"]
|
12
|
+
s.date = "2013-03-07"
|
13
|
+
s.description = "Provides methods to publish and unpublish your active record models based on a boolean flag, a date, or a datetime. Also adds named scopes to nicely filter your records. Does not touch any controller or views."
|
14
|
+
s.email = ["m.linkhorst@googlemail.com", "info@tinynumbers.com"]
|
15
15
|
s.extra_rdoc_files = [
|
16
|
-
"LICENSE",
|
17
|
-
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
"spec/spec.opts",
|
32
|
-
"spec/spec_helper.rb"
|
33
|
-
]
|
34
|
-
s.homepage = %q{http://github.com/linki/publishable}
|
35
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
-
s.require_paths = ["lib"]
|
37
|
-
s.rubygems_version = %q{1.3.7}
|
38
|
-
s.summary = %q{Adds publishing functionality to your active record model}
|
39
|
-
s.test_files = [
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"lib/publishable.rb",
|
28
|
+
"lib/publishable/railtie.rb",
|
29
|
+
"lib/publishable/version.rb",
|
30
|
+
"publishable.gemspec",
|
40
31
|
"spec/publishable_spec.rb",
|
41
|
-
|
32
|
+
"spec/spec_helper.rb",
|
33
|
+
"spec/support/matcher_each.rb"
|
42
34
|
]
|
35
|
+
s.homepage = "http://github.com/linki/publishable"
|
36
|
+
s.licenses = ["MIT"]
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
s.rubygems_version = "1.8.24"
|
39
|
+
s.summary = "Adds publishing functionality to your active record model"
|
43
40
|
|
44
41
|
if s.respond_to? :specification_version then
|
45
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
46
42
|
s.specification_version = 3
|
47
43
|
|
48
44
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
-
s.add_development_dependency(%q<
|
45
|
+
s.add_development_dependency(%q<yard>, ["~> 0.7"])
|
46
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
47
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
48
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
49
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
50
50
|
else
|
51
|
-
s.add_dependency(%q<
|
51
|
+
s.add_dependency(%q<yard>, ["~> 0.7"])
|
52
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
53
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
54
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
55
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
52
56
|
end
|
53
57
|
else
|
54
|
-
s.add_dependency(%q<
|
58
|
+
s.add_dependency(%q<yard>, ["~> 0.7"])
|
59
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
60
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
61
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
62
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
data/spec/publishable_spec.rb
CHANGED
@@ -1,98 +1,296 @@
|
|
1
|
-
require File.expand_path('
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
|
4
|
-
extend Publishable
|
5
|
-
publishable
|
6
|
-
end
|
3
|
+
describe Publishable do
|
7
4
|
|
8
|
-
|
9
|
-
extend Publishable
|
10
|
-
publishable :on => :public_since
|
11
|
-
end
|
5
|
+
context 'with a Boolean publish attribute' do
|
12
6
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
7
|
+
before :all do
|
8
|
+
build_model :post do
|
9
|
+
string :title
|
10
|
+
text :body
|
11
|
+
boolean :published
|
12
|
+
attr_accessible :title, :body, :published
|
13
|
+
validates :body, :title, :presence => true
|
14
|
+
extend Publishable
|
15
|
+
publishable
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
before :each do
|
20
|
+
@post = Post.new :title => Faker::Lorem.sentence(4), :body => Faker::Lorem.paragraphs(3).join("\n")
|
21
|
+
@post.should be_valid
|
22
|
+
@post.should_not be_published
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should become published when publish flag is set' do
|
26
|
+
@post.publish!
|
27
|
+
@post.should be_published
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should become unpublished when publish flag is cleared' do
|
31
|
+
@post.published = true
|
32
|
+
@post.should be_published
|
33
|
+
@post.unpublish!
|
34
|
+
@post.should_not be_published
|
35
|
+
end
|
32
36
|
|
33
|
-
it "should be published" do
|
34
|
-
# now
|
35
|
-
@album.published_at = Time.now
|
36
|
-
@album.should be_published
|
37
|
-
|
38
|
-
# in the past
|
39
|
-
@album.published_at = Time.now - 60
|
40
|
-
@album.should be_published
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should be publishable" do
|
44
|
-
@album.should_not be_published
|
45
|
-
@album.publish
|
46
|
-
@album.should be_published
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should persist" do
|
50
|
-
@album.expects(:publish).returns(true)
|
51
|
-
@album.expects(:save)
|
52
|
-
@album.publish!
|
53
37
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
38
|
+
|
39
|
+
context 'with a Date publish attribute' do
|
40
|
+
|
41
|
+
before :all do
|
42
|
+
build_model :post do
|
43
|
+
string :title
|
44
|
+
text :body
|
45
|
+
date :published
|
46
|
+
attr_accessible :title, :body, :published
|
47
|
+
validates :body, :title, :presence => true
|
48
|
+
extend Publishable
|
49
|
+
publishable
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
before :each do
|
54
|
+
@post = Post.new :title => Faker::Lorem.sentence(4),
|
55
|
+
:body => Faker::Lorem.paragraphs(3).join("\n")
|
56
|
+
@post.should be_valid
|
57
|
+
@post.should_not be_published
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should be published if today is after the publish date' do
|
61
|
+
@post.published = Date.current - 1.days
|
62
|
+
@post.should be_published
|
69
63
|
end
|
64
|
+
|
65
|
+
it 'should be published if today is the publish date' do
|
66
|
+
@post.published = Date.current
|
67
|
+
@post.should be_published
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should not be published if today is before the publish date' do
|
71
|
+
@post.published = Date.current + 1.days
|
72
|
+
@post.should_not be_published
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should have a publish date of today or earlier after publish is directly called' do
|
76
|
+
@post.publish
|
77
|
+
@post.should be_published
|
78
|
+
@post.published.should <= Date.current
|
79
|
+
end
|
80
|
+
|
70
81
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
82
|
+
|
83
|
+
context 'with a DateTime publish attribute' do
|
84
|
+
|
85
|
+
before :all do
|
86
|
+
build_model :post do
|
87
|
+
string :title
|
88
|
+
text :body
|
89
|
+
datetime :published
|
90
|
+
attr_accessible :title, :body, :published
|
91
|
+
validates :body, :title, :presence => true
|
92
|
+
extend Publishable
|
93
|
+
publishable
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'publishing and unpublishing' do
|
98
|
+
|
99
|
+
before :each do
|
100
|
+
@post = Post.new :title => Faker::Lorem.sentence(4),
|
101
|
+
:body => Faker::Lorem.paragraphs(3).join("\n")
|
102
|
+
@post.should be_valid
|
103
|
+
@post.should_not be_published
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should be published if now is after the publish time' do
|
107
|
+
@post.published = DateTime.now - 1.minute
|
108
|
+
@post.should be_published
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should not be published if now is before the publish time' do
|
112
|
+
@post.published = DateTime.now + 1.minute
|
113
|
+
@post.should_not be_published
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should have a publish time of now or earlier after publish is directly called' do
|
117
|
+
@post.publish
|
118
|
+
@post.should be_published
|
119
|
+
@post.published.should <= DateTime.now
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'querying for all upcoming items' do
|
125
|
+
|
126
|
+
before :all do
|
127
|
+
# create a bunch of published Posts
|
128
|
+
(rand(9) + 1).times do
|
129
|
+
days_ago = (rand(100) + 1).days
|
130
|
+
Post.create :published => Date.current - days_ago,
|
131
|
+
:title => Faker::Lorem.sentence(4),
|
132
|
+
:body => Faker::Lorem.paragraphs(3).join("\n")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
after :each do
|
137
|
+
Post.upcoming.destroy_all
|
138
|
+
end
|
139
|
+
|
140
|
+
after :all do
|
141
|
+
# have to destroy posts between tests - these are fake, not in the DB, so database-cleaner won't help us
|
142
|
+
Post.destroy_all
|
143
|
+
end
|
144
|
+
|
145
|
+
[1, 2, 5, 10].each do |how_many|
|
146
|
+
it "should return all #{how_many} upcoming queries if no limit is specified" do
|
147
|
+
# create a known number of unpublished Posts
|
148
|
+
how_many.times do
|
149
|
+
days_from_now = (rand(100) + 1).days
|
150
|
+
Post.create :published => Date.current + days_from_now,
|
151
|
+
:title => Faker::Lorem.sentence(4),
|
152
|
+
:body => Faker::Lorem.paragraphs(3).join("\n")
|
153
|
+
end
|
154
|
+
size = Post.upcoming.size
|
155
|
+
size.should == how_many
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
78
159
|
end
|
79
|
-
|
80
|
-
describe
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
160
|
+
|
161
|
+
describe 'querying for all recent items' do
|
162
|
+
|
163
|
+
before :all do
|
164
|
+
# create a bunch of unpublished posts
|
165
|
+
(rand(7) + 3).times do
|
166
|
+
days_from_now = (rand(100) + 1).days
|
167
|
+
Post.create :published => Date.current + days_from_now,
|
168
|
+
:title => Faker::Lorem.sentence(4),
|
169
|
+
:body => Faker::Lorem.paragraphs(3).join("\n")
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
after :each do
|
174
|
+
Post.recent.destroy_all
|
175
|
+
end
|
176
|
+
|
177
|
+
after :all do
|
178
|
+
Post.destroy_all
|
179
|
+
end
|
180
|
+
|
181
|
+
[1, 2, 5, 10].each do |how_many|
|
182
|
+
it "should return all #{how_many} recent queries if no limit is specified" do
|
183
|
+
# create a known number of published posts
|
184
|
+
how_many.times do
|
185
|
+
Post.create :published => Date.current - rand(100).days,
|
186
|
+
:title => Faker::Lorem.sentence(4),
|
187
|
+
:body => Faker::Lorem.paragraphs(3).join("\n")
|
188
|
+
end
|
189
|
+
Post.recent.size.should == how_many
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
describe 'queries for recent or upcoming items' do
|
196
|
+
|
197
|
+
before :all do
|
198
|
+
# this is more a test for Publishable than it is for Story, but let's set the time to near the end of the day
|
199
|
+
# this was causing a failing condition due to UTC/local TZ differences
|
200
|
+
new_time = Time.local(2013, 01, 23, 22, 0, 0)
|
201
|
+
Timecop.travel(new_time)
|
202
|
+
|
203
|
+
(-5..5).each do |n|
|
204
|
+
Post.create :published => Date.current + n.days,
|
205
|
+
:title => Faker::Lorem.sentence(4),
|
206
|
+
:body => Faker::Lorem.paragraphs(3).join("\n")
|
207
|
+
end
|
87
208
|
end
|
88
209
|
|
89
|
-
|
90
|
-
|
210
|
+
after :all do
|
211
|
+
# go back to the normal time and date
|
212
|
+
Timecop.return
|
213
|
+
Post.destroy_all
|
91
214
|
end
|
92
215
|
|
93
|
-
|
94
|
-
|
216
|
+
context 'recent' do
|
217
|
+
|
218
|
+
it 'returns only published items' do
|
219
|
+
Post.recent.should each be_published
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'returns the requested number of items' do
|
223
|
+
Post.recent(2).size.should == 2
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'returns as many items as available if we request too many' do
|
227
|
+
Post.recent(10).size.should == 6
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'upcoming' do
|
233
|
+
|
234
|
+
it 'returns only unpublished items' do
|
235
|
+
Post.upcoming.should each be_unpublished
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'returns the requested number of items' do
|
239
|
+
Post.upcoming(2).size.should == 2
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'returns as many items as available if we request too many' do
|
243
|
+
Post.upcoming(50).size.should == 5
|
244
|
+
end
|
245
|
+
|
95
246
|
end
|
96
|
-
|
247
|
+
|
248
|
+
end
|
249
|
+
|
97
250
|
end
|
251
|
+
|
252
|
+
describe 'with an invalid configuration' do
|
253
|
+
|
254
|
+
it 'should raise a configuration error when defined on an invalid column type' do
|
255
|
+
expect {
|
256
|
+
build_model :post do
|
257
|
+
string :title
|
258
|
+
text :body
|
259
|
+
attr_accessible :title, :body
|
260
|
+
validates :body, :title, :presence => true
|
261
|
+
extend Publishable
|
262
|
+
publishable :on => :title
|
263
|
+
end
|
264
|
+
}.to raise_error ActiveRecord::ConfigurationError
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'should raise a configuration error when the publish column not defined' do
|
268
|
+
expect {
|
269
|
+
build_model :post do
|
270
|
+
string :title
|
271
|
+
text :body
|
272
|
+
attr_accessible :title, :body
|
273
|
+
validates :body, :title, :presence => true
|
274
|
+
extend Publishable
|
275
|
+
publishable
|
276
|
+
end
|
277
|
+
}.to raise_error ActiveRecord::ConfigurationError
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should raise a configuration error when defined on a missing column' do
|
281
|
+
expect {
|
282
|
+
build_model :post do
|
283
|
+
string :title
|
284
|
+
text :body
|
285
|
+
datetime :published
|
286
|
+
attr_accessible :title, :body, :published
|
287
|
+
validates :body, :title, :presence => true
|
288
|
+
extend Publishable
|
289
|
+
publishable :on => :foobar
|
290
|
+
end
|
291
|
+
}.to raise_error ActiveRecord::ConfigurationError
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
|
98
296
|
end
|