ar_publish_control 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +15 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +166 -0
- data/Rakefile +28 -0
- data/ar_publish_control.gemspec +38 -0
- data/lib/ar_publish_control.rb +229 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/ar_publish_control_spec.rb +194 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +47 -0
- data/tasks/db.rake +57 -0
- data/tasks/rspec.rake +21 -0
- metadata +93 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
PostInstall.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
ar_publish_control.gemspec
|
7
|
+
lib/ar_publish_control.rb
|
8
|
+
script/console
|
9
|
+
script/destroy
|
10
|
+
script/generate
|
11
|
+
spec/ar_publish_control_spec.rb
|
12
|
+
spec/spec.opts
|
13
|
+
spec/spec_helper.rb
|
14
|
+
tasks/db.rake
|
15
|
+
tasks/rspec.rake
|
data/PostInstall.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
This is a gem version of http://github.com/avdgaag/acts_as_publishable ( a Rails plugin)
|
2
|
+
Thanks to Arjan van der Gaag for his original work in that plugin, which this gem is heavily based off.
|
3
|
+
|
4
|
+
His plugin is Copyright (c) 2007 Arjan van der Gaag, released under the MIT license
|
5
|
+
|
6
|
+
= ar_publish_control
|
7
|
+
|
8
|
+
http://github.com/ismasan/ar_publish_control
|
9
|
+
|
10
|
+
== DESCRIPTION:
|
11
|
+
|
12
|
+
Add start/end publishing dates to your ActiveRecord models.
|
13
|
+
|
14
|
+
== FEATURES/PROBLEMS:
|
15
|
+
|
16
|
+
Adds published, unpublished and published_only(boolean) named_scopes to your models.
|
17
|
+
|
18
|
+
== SYNOPSIS:
|
19
|
+
|
20
|
+
class Post < ActiveRecord::Base
|
21
|
+
publish_control
|
22
|
+
end
|
23
|
+
|
24
|
+
# creating
|
25
|
+
@post = Post.create(params[:post])
|
26
|
+
|
27
|
+
@post.publish!
|
28
|
+
|
29
|
+
# With start and end dates
|
30
|
+
@post.update_attributes :publish_at => Time.now, :unpublish_at => 2.weeks.from_now
|
31
|
+
|
32
|
+
# Or, in your views...
|
33
|
+
<% form_for @post do |f| %>
|
34
|
+
...
|
35
|
+
<p>
|
36
|
+
<%= f.label :is_published, "Publish" %>
|
37
|
+
<%= f.check_box :is_published %>
|
38
|
+
</p>
|
39
|
+
<p>
|
40
|
+
<%= f.label :publish_at, "From" %>
|
41
|
+
<%= f.date_select :publish_at %>
|
42
|
+
</p>
|
43
|
+
<p>
|
44
|
+
<%= f.label :unpublish_at, "To" %>
|
45
|
+
<%= f.date_select :unpublish_at %>
|
46
|
+
</p>
|
47
|
+
...
|
48
|
+
<% end %>
|
49
|
+
|
50
|
+
# in your controllers
|
51
|
+
def index
|
52
|
+
@posts = Post.published
|
53
|
+
end
|
54
|
+
|
55
|
+
def show
|
56
|
+
@post = Post.published.find(params[:id])
|
57
|
+
@post.published? # => true
|
58
|
+
end
|
59
|
+
|
60
|
+
# You can nest scopes:
|
61
|
+
@post = current_user.posts.published(params[:id])
|
62
|
+
|
63
|
+
@posts = current_user.posts.published.paginate(:page => params[:page])
|
64
|
+
|
65
|
+
# unpublished ones
|
66
|
+
@posts = Post.unpublished
|
67
|
+
|
68
|
+
# All posts if logged_in?, only published otherwise
|
69
|
+
@posts = Post.published_only?( !logged_in? ).paginate(:page => params[:page])
|
70
|
+
|
71
|
+
# Unpublish
|
72
|
+
@post.unpublish!
|
73
|
+
@post.unpublished? # => true
|
74
|
+
|
75
|
+
# You can access the ones marked as "published" but with a publish date in the future
|
76
|
+
@upcoming_post = Post.upcoming
|
77
|
+
@upcoming_post.first.upcoming? # => true
|
78
|
+
|
79
|
+
# You can fetch objects that have expired (ie. they have an unpublish_at date set in the past)
|
80
|
+
@expired_posts = Post.expired
|
81
|
+
@expired_posts.first.expired? # => true
|
82
|
+
|
83
|
+
# Finally, if you want those objects where is_published == false, regardless of dates
|
84
|
+
@drafts = Post.draft
|
85
|
+
|
86
|
+
All of these named_scopes can be chained with other finder conditions and paginated with will_paginate
|
87
|
+
|
88
|
+
== REQUIREMENTS:
|
89
|
+
|
90
|
+
ActiveRecord
|
91
|
+
|
92
|
+
== INSTALL:
|
93
|
+
|
94
|
+
If you haven't yet, add github.com to your gem sources (you only need to do that once):
|
95
|
+
|
96
|
+
gem sources -a http://gems.github.com
|
97
|
+
|
98
|
+
Now you can install the normal way:
|
99
|
+
|
100
|
+
sudo gem install ismasan-ar_publish_control
|
101
|
+
|
102
|
+
Add the necessary fields to you schema, in a migration:
|
103
|
+
|
104
|
+
class AddPublishableToPosts < ActiveRecord::Migration
|
105
|
+
def self.up
|
106
|
+
add_column :posts, :is_published, :boolean, :default => true
|
107
|
+
add_column :posts, :publish_at, :datetime
|
108
|
+
add_column :posts, :unpublish_at, :datetime
|
109
|
+
# update existing records if you have them
|
110
|
+
Post.update_all "publish_at = created_at"
|
111
|
+
end
|
112
|
+
def self.down
|
113
|
+
remove_column :posts, :is_published
|
114
|
+
remove_column :posts, :publish_at
|
115
|
+
remove_column :posts, :unpublish_at
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
rake db:migrate
|
120
|
+
|
121
|
+
Then, in your Rails app's environment:
|
122
|
+
|
123
|
+
config.gem 'ismasan-ar_publish_control',:lib => 'ar_publish_control',:source => "http://gems.github.com"
|
124
|
+
|
125
|
+
...Or in Merb or elsewhere
|
126
|
+
|
127
|
+
require "ar_publish_control"
|
128
|
+
|
129
|
+
If you wan to unpack the gem to you app's "vendor" directory:
|
130
|
+
|
131
|
+
rake gems:unpack
|
132
|
+
|
133
|
+
== TEST
|
134
|
+
|
135
|
+
Test are in the spec directory (rspec). To run them, first initialize the test sqlite database
|
136
|
+
|
137
|
+
rake db:create
|
138
|
+
|
139
|
+
Now you can run the specs
|
140
|
+
|
141
|
+
rake spec
|
142
|
+
|
143
|
+
== LICENSE:
|
144
|
+
|
145
|
+
(The MIT License)
|
146
|
+
|
147
|
+
Copyright (c) 2008 Ismael Celis
|
148
|
+
|
149
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
150
|
+
a copy of this software and associated documentation files (the
|
151
|
+
'Software'), to deal in the Software without restriction, including
|
152
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
153
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
154
|
+
permit persons to whom the Software is furnished to do so, subject to
|
155
|
+
the following conditions:
|
156
|
+
|
157
|
+
The above copyright notice and this permission notice shall be
|
158
|
+
included in all copies or substantial portions of the Software.
|
159
|
+
|
160
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
161
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
162
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
163
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
164
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
165
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
166
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/ar_publish_control'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('ar_publish_control', ArPublishControl::VERSION) do |p|
|
7
|
+
p.developer('Ismael Celis', 'ismaelct@gmail.com')
|
8
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
9
|
+
p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
10
|
+
p.rubyforge_name = p.name # TODO this is default value
|
11
|
+
# p.extra_deps = [
|
12
|
+
# ['activesupport','>= 2.0.2'],
|
13
|
+
# ]
|
14
|
+
p.extra_dev_deps = [
|
15
|
+
['newgem', ">= #{::Newgem::VERSION}"]
|
16
|
+
]
|
17
|
+
|
18
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
19
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
20
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
21
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
25
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
26
|
+
|
27
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
28
|
+
# task :default => [:spec, :features]
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{ar_publish_control}
|
5
|
+
s.version = "0.0.9"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Ismael Celis"]
|
9
|
+
s.date = %q{2008-11-18}
|
10
|
+
s.description = %q{Publish control for ActiveRecord}
|
11
|
+
s.email = ["ismaelct@gmail.com"]
|
12
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc"]
|
13
|
+
s.files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "ar_publish_control.gemspec", "lib/ar_publish_control.rb", "script/console", "script/destroy", "script/generate", "spec/ar_publish_control_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/db.rake", "tasks/rspec.rake"]
|
14
|
+
s.has_rdoc = false
|
15
|
+
s.homepage = %q{http://www.estadobeta.com}
|
16
|
+
s.post_install_message = %q{PostInstall.txt}
|
17
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.rubyforge_project = %q{ar_publish_control}
|
20
|
+
s.rubygems_version = %q{1.3.1}
|
21
|
+
s.summary = %q{Publish control for ActiveRecord, with start and optional end dates}
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 2
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
s.add_development_dependency(%q<newgem>, [">= 1.1.0"])
|
29
|
+
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
30
|
+
else
|
31
|
+
s.add_dependency(%q<newgem>, [">= 1.1.0"])
|
32
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
33
|
+
end
|
34
|
+
else
|
35
|
+
s.add_dependency(%q<newgem>, [">= 1.1.0"])
|
36
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
module ArPublishControl
|
5
|
+
VERSION = '0.0.9'
|
6
|
+
# This is a gem version of http://github.com/avdgaag/acts_as_publishable ( a Rails plugin)
|
7
|
+
# Thanks to Avdaag for his awesome, super readable code which I ripped off for this gem.
|
8
|
+
#
|
9
|
+
# Specify this act if you want to show or hide your object based on date/time settings. This act lets you
|
10
|
+
# specify two dates two form a range in which the model is publicly available; it is unavailable outside it.
|
11
|
+
#
|
12
|
+
# == Usage
|
13
|
+
#
|
14
|
+
# You can add this behaviour to your model like so:
|
15
|
+
#
|
16
|
+
# class Post < ActiveRecord::Base
|
17
|
+
# publish_control
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Then you can use it as follows:
|
21
|
+
#
|
22
|
+
# post = Post.create(:title => 'Hello world')
|
23
|
+
# post.published? # => true
|
24
|
+
#
|
25
|
+
# post.publish!
|
26
|
+
# post.published? # => true
|
27
|
+
#
|
28
|
+
# post.unpublish!
|
29
|
+
# post.published? # => false
|
30
|
+
#
|
31
|
+
# You can use two named_scopes to find the published or unpublished objects.
|
32
|
+
# You can chain them with other scopes and use them on association collections:
|
33
|
+
#
|
34
|
+
# Post.all.count # => 15
|
35
|
+
# Post.published.count # => 10
|
36
|
+
# Post.unpublished.count # => 5 includes upcoming and expired
|
37
|
+
# Post.draft.count # => where is_published == false regardless of date
|
38
|
+
# @post.comments.published
|
39
|
+
#
|
40
|
+
# Post.recent.published
|
41
|
+
#
|
42
|
+
# Klass.unpublished includes all objects which is_published flag is set to false and/or are expired or upcoming.
|
43
|
+
# If you specifically want those where is_published == false regardless of dates, use Klass.draft
|
44
|
+
#
|
45
|
+
# There's a third named_scope that you can pass a boolean in order to find only published items or all of them
|
46
|
+
# This is useful in controller for permission-based publish control
|
47
|
+
#
|
48
|
+
# @post = Post.published.find(params[:id])
|
49
|
+
# @comments = @post.comments.only_published( logged_in? )
|
50
|
+
#
|
51
|
+
# Available statuses. This constant is useful for autogenerated routes, controller actions and view helpers
|
52
|
+
#
|
53
|
+
STATUSES = [:published, :draft, :upcoming, :expired]
|
54
|
+
|
55
|
+
module Publishable
|
56
|
+
|
57
|
+
def self.included(base) #:nodoc:
|
58
|
+
base.extend ClassMethods
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
62
|
+
# == Configuration options
|
63
|
+
#
|
64
|
+
# Right now this plugin has only one configuration option. Models with no publication dates
|
65
|
+
# are by default published, not unpublished. If you want to hide your model when it has no
|
66
|
+
# explicit publication date set, you can turn off this behaviour with the
|
67
|
+
# +publish_by_default+ (defaults to <tt>true</tt>) option like so:
|
68
|
+
#
|
69
|
+
# class Post < ActiveRecord::Base
|
70
|
+
# publish_control :publish_by_default => false
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# == Database Schema
|
74
|
+
#
|
75
|
+
# The model that you're publishing needs to have two special date attributes:
|
76
|
+
#
|
77
|
+
# * publish_at
|
78
|
+
# * unpublish_at
|
79
|
+
#
|
80
|
+
# These attributes have no further requirements or required validations; they
|
81
|
+
# just need to be <tt>datetime</tt>-columns.
|
82
|
+
#
|
83
|
+
# You can use a migration like this to add these columns to your model:
|
84
|
+
#
|
85
|
+
# class AddPublicationDatesToPosts < ActiveRecord::Migration
|
86
|
+
# def self.up
|
87
|
+
# add_column :posts, :publish_at, :datetime
|
88
|
+
# add_column :posts, :unpublish_at, :datetime
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# def self.down
|
92
|
+
# remove_column :posts, :publish_at
|
93
|
+
# remove_column :posts, :unpublish_at
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
def publish_control(options = { :publish_by_default => true })
|
98
|
+
# don't allow multiple calls
|
99
|
+
return if self.included_modules.include?(ArPublishControl::Publishable::InstanceMethods)
|
100
|
+
send :include, ArPublishControl::Publishable::InstanceMethods
|
101
|
+
|
102
|
+
named_scope :published, lambda{{:conditions => published_conditions}}
|
103
|
+
named_scope :unpublished, lambda{{:conditions => unpublished_conditions}}
|
104
|
+
named_scope :upcoming, lambda{{:conditions => upcoming_conditions}}
|
105
|
+
named_scope :expired, lambda {{:conditions => expired_conditions}}
|
106
|
+
named_scope :draft, :conditions => {:is_published => false}
|
107
|
+
|
108
|
+
named_scope :published_only, lambda {|*args|
|
109
|
+
bool = (args.first.nil? ? true : (args.first)) # nil = true by default
|
110
|
+
bool ? {:conditions => published_conditions} : {}
|
111
|
+
}
|
112
|
+
|
113
|
+
validate :validate_publish_date_consistency
|
114
|
+
before_create :publish_by_default if options[:publish_by_default]
|
115
|
+
end
|
116
|
+
|
117
|
+
# Takes a block whose containing SQL queries are limited to
|
118
|
+
# published objects. You can pass a boolean flag indicating
|
119
|
+
# whether this scope should be applied or not--for example,
|
120
|
+
# you might want to disable it when the user is an administrator.
|
121
|
+
# By default the scope is applied.
|
122
|
+
#
|
123
|
+
# Example usage:
|
124
|
+
#
|
125
|
+
# Post.published_only(!logged_in?)
|
126
|
+
# @post.comments.published_only(!logged_in?)
|
127
|
+
#
|
128
|
+
|
129
|
+
protected
|
130
|
+
|
131
|
+
# returns a string for use in SQL to filter the query to unpublished results only
|
132
|
+
# Meant for internal use only
|
133
|
+
def unpublished_conditions
|
134
|
+
t = Time.now
|
135
|
+
["(#{table_name}.is_published = ? OR #{table_name}.publish_at > ?) OR (#{table_name}.unpublish_at IS NOT NULL AND #{table_name}.unpublish_at < ?)",false,t,t]
|
136
|
+
end
|
137
|
+
|
138
|
+
# return a string for use in SQL to filter the query to published results only
|
139
|
+
# Meant for internal use only
|
140
|
+
def published_conditions
|
141
|
+
t = Time.now
|
142
|
+
["(#{table_name}.is_published = ? AND #{table_name}.publish_at <= ?) AND (#{table_name}.unpublish_at IS NULL OR #{table_name}.unpublish_at > ?)",true,t,t]
|
143
|
+
end
|
144
|
+
|
145
|
+
def upcoming_conditions
|
146
|
+
t = Time.now
|
147
|
+
["(#{table_name}.is_published = ? AND #{table_name}.publish_at > ?)",true,t]
|
148
|
+
end
|
149
|
+
|
150
|
+
def expired_conditions
|
151
|
+
t = Time.now
|
152
|
+
["(#{table_name}.unpublish_at IS NOT NULL AND #{table_name}.unpublish_at < ?)",t]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
module InstanceMethods
|
157
|
+
|
158
|
+
def after_initialize
|
159
|
+
write_attribute(:publish_at, Time.now) if publish_at.nil?
|
160
|
+
end
|
161
|
+
|
162
|
+
# ActiveRecrod callback fired on +before_create+ to make
|
163
|
+
# sure a new object always gets a publication date; if
|
164
|
+
# none is supplied it defaults to the creation date.
|
165
|
+
def publish_by_default
|
166
|
+
write_attribute(:is_published, true) if is_published.nil?
|
167
|
+
end
|
168
|
+
|
169
|
+
# Validate that unpublish_at is greater than publish_at
|
170
|
+
# publish_at must not be nil
|
171
|
+
def validate_publish_date_consistency
|
172
|
+
if unpublish_at && publish_at && unpublish_at <= publish_at
|
173
|
+
errors.add(:unpublish_at,"should be greater than publication date or empty")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
public
|
178
|
+
|
179
|
+
# Return whether the current object is published or not
|
180
|
+
def published?
|
181
|
+
(is_published? && (publish_at <=> Time.now) <= 0) && (unpublish_at.nil? || (unpublish_at <=> Time.now) >= 0)
|
182
|
+
end
|
183
|
+
|
184
|
+
def upcoming?
|
185
|
+
(is_published? && publish_at > Time.now)
|
186
|
+
end
|
187
|
+
|
188
|
+
def expired?
|
189
|
+
(!unpublish_at.nil? && unpublish_at < Time.now)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Indefinitely publish the current object right now
|
193
|
+
def publish
|
194
|
+
return if published?
|
195
|
+
self.is_published = true
|
196
|
+
self.publish_at = Time.now
|
197
|
+
self.unpublish_at = nil
|
198
|
+
end
|
199
|
+
|
200
|
+
# Same as publish, but immediatly saves the object.
|
201
|
+
# Raises an error when saving fails.
|
202
|
+
def publish!
|
203
|
+
publish
|
204
|
+
save!
|
205
|
+
end
|
206
|
+
|
207
|
+
# Immediatly unpublish the current object
|
208
|
+
def unpublish
|
209
|
+
return unless published?
|
210
|
+
self.is_published = false
|
211
|
+
end
|
212
|
+
|
213
|
+
# Same as unpublish, but immediatly saves the object.
|
214
|
+
# Raises an error when saving files.
|
215
|
+
def unpublish!
|
216
|
+
unpublish
|
217
|
+
save!
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
require 'rubygems'
|
227
|
+
require 'active_record'
|
228
|
+
|
229
|
+
ActiveRecord::Base.send :include, ArPublishControl::Publishable
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/ar_publish_control.rb'}"
|
9
|
+
puts "Loading ar_publish_control gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe ArPublishControl do
|
4
|
+
it "should have array of available statuses" do
|
5
|
+
(ArPublishControl::STATUSES == [:published, :draft, :upcoming, :expired]).should be_true
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Comment do
|
10
|
+
before(:each) do
|
11
|
+
Post.destroy_all
|
12
|
+
@published_post = Post.create do |p|
|
13
|
+
p.title = 'some post'
|
14
|
+
p.publish_at = 1.day.ago
|
15
|
+
p.unpublish_at = 2.days.from_now
|
16
|
+
end
|
17
|
+
|
18
|
+
@unpublished_post = Post.create do |p|
|
19
|
+
p.title = 'some other post'
|
20
|
+
p.publish_at = 1.day.from_now
|
21
|
+
p.unpublish_at = 2.days.from_now
|
22
|
+
end
|
23
|
+
|
24
|
+
@published_comment_in_published_post = @published_post.comments.create do |c|
|
25
|
+
c.body = 'some comment'
|
26
|
+
c.publish_at = 2.day.ago
|
27
|
+
c.unpublish_at = 2.days.from_now
|
28
|
+
end
|
29
|
+
|
30
|
+
@published_comment_in_unpublished_post = @unpublished_post.comments.create do |c|
|
31
|
+
c.body = 'some other comment'
|
32
|
+
c.publish_at = 1.day.ago
|
33
|
+
c.unpublish_at = 2.days.from_now
|
34
|
+
end
|
35
|
+
|
36
|
+
@unpublished_comment_in_published_post = @published_post.comments.create do |c|
|
37
|
+
c.body = 'some other comment 2'
|
38
|
+
c.publish_at = 1.day.from_now
|
39
|
+
c.unpublish_at = 2.days.from_now
|
40
|
+
end
|
41
|
+
|
42
|
+
@unupublished_comment_in_unpublished_post = @unpublished_post.comments.create do |c|
|
43
|
+
c.body = 'some other comment 3'
|
44
|
+
c.publish_at = 1.day.from_now
|
45
|
+
c.unpublish_at = 2.days.from_now
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should find published comment at class level" do
|
51
|
+
Comment.published.size.should == 2
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should find published comments in collection" do
|
55
|
+
@published_post.comments.published.size.should == 1
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should find published comments in a collection with conditions" do
|
59
|
+
@published_post.published_comments.size.should == 1
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should work with named scope at class level" do
|
63
|
+
Comment.published.size.should == 2
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should work with named scope at collection level" do
|
67
|
+
@published_post.comments.published.size.should == 1
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should find unpublished with named scope" do
|
71
|
+
Comment.unpublished.size.should == 2
|
72
|
+
@published_post.comments.unpublished.size.should == 1
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should chain correctly with other scopes" do
|
76
|
+
Comment.published.desc.should == [@published_comment_in_unpublished_post,@published_comment_in_published_post]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should chain correctly with other scopes on collections" do
|
80
|
+
@unpublished_comment_in_published_post.publish_at = @published_comment_in_published_post.publish_at + 1.hour
|
81
|
+
@unpublished_comment_in_published_post.save
|
82
|
+
@published_post.comments.reload
|
83
|
+
@published_post.comments.published.desc.should == [@unpublished_comment_in_published_post,@published_comment_in_published_post]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should find all with conditional flag" do
|
87
|
+
Comment.published_only.size.should == 2
|
88
|
+
Comment.published_only(true).size.should == 2
|
89
|
+
@published_post.comments.published_only(true).first.should == @published_comment_in_published_post
|
90
|
+
@published_post.comments.published_only(true).include?(@unpublished_comment_in_published_post).should be_false
|
91
|
+
@published_post.comments.published_only(false).include?(@unpublished_comment_in_published_post).should be_true
|
92
|
+
@published_post.comments.published_only(false).include?(@published_comment_in_published_post).should be_true
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should validate that unpublish_at is greater than publish_at" do
|
96
|
+
@published_comment_in_published_post.unpublish_at = @published_comment_in_published_post.publish_at - 1.minute
|
97
|
+
@published_comment_in_published_post.save
|
98
|
+
@published_comment_in_published_post.should_not be_valid
|
99
|
+
@published_comment_in_published_post.errors.on(:unpublish_at).should == "should be greater than publication date or empty"
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
# describe Post, 'with no dates' do
|
105
|
+
# it "should be published" do
|
106
|
+
# puts "DESTROYING #{Post.count}============="
|
107
|
+
# Post.destroy_all
|
108
|
+
# puts "====================================="
|
109
|
+
# post = Post.create(:title => 'some post aaaaaaaaaaaaaaaaaaaaaaaaaaaa')
|
110
|
+
# post.published?.should be_true
|
111
|
+
# Post.published.include?(post).should be_true
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
|
115
|
+
describe Post, "unpublished by default" do
|
116
|
+
before(:each) do
|
117
|
+
Article.destroy_all
|
118
|
+
@a1 = Article.create(:title=>'a1')
|
119
|
+
@invalid = Article.create(:title=>'a2', :publish_at => '')
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should be valid" do
|
123
|
+
@a1.should be_valid
|
124
|
+
@a1.publish_at.should_not be_nil
|
125
|
+
@invalid.publish_at.should_not be_blank
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should be unpublished by default" do
|
129
|
+
@a1.published?.should_not be_true
|
130
|
+
Article.published.size.should == 0
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should publish" do
|
134
|
+
@a1.publish!
|
135
|
+
@a1.published?.should be_true
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe Post, 'upcoming' do
|
140
|
+
before(:each) do
|
141
|
+
Post.destroy_all
|
142
|
+
@p1 = Post.create(:title => 'p1',:is_published => true,:publish_at => 1.day.from_now) #upcoming
|
143
|
+
@p2 = Post.create(:title => 'p2',:is_published => true,:publish_at => 1.week.from_now)#upcoming
|
144
|
+
@p3 = Post.create(:title => 'p3',:is_published => false,:publish_at => 1.day.from_now)#unpublished
|
145
|
+
@p4 = Post.create(:title => 'p4',:is_published => true)#published
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should have upcoming" do
|
149
|
+
@p1.upcoming?.should be_true
|
150
|
+
@p2.upcoming?.should be_true
|
151
|
+
@p3.upcoming?.should be_false
|
152
|
+
@p4.upcoming?.should be_false
|
153
|
+
Post.upcoming.size.should == 2
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe Post, 'expired' do
|
158
|
+
before(:each) do
|
159
|
+
Post.destroy_all
|
160
|
+
@p1 = Post.create(:title => 'p1',:is_published => true,:publish_at => 2.weeks.ago) #published
|
161
|
+
@p2 = Post.create(:title => 'p2',:is_published => true,:publish_at => 2.weeks.ago,:unpublish_at => 1.day.ago)#expired
|
162
|
+
@p3 = Post.create(:title => 'p3',:is_published => false,:publish_at => 3.days.ago,:unpublish_at => 2.hours.ago)#unpublished and expired
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should have expired" do
|
166
|
+
@p1.expired?.should be_false
|
167
|
+
@p2.expired?.should be_true
|
168
|
+
@p3.expired?.should be_true
|
169
|
+
Post.expired.size.should == 2
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe Post, 'draft' do
|
174
|
+
before(:each) do
|
175
|
+
Post.destroy_all
|
176
|
+
@p1 = Post.create(:title => 'p1',:is_published => true,:publish_at => 2.weeks.ago) #published
|
177
|
+
@p2 = Post.create(:title => 'p2',:is_published => true,:publish_at => 2.weeks.ago,:unpublish_at => 1.day.ago)#expired
|
178
|
+
@p3 = Post.create(:title => 'p3',:is_published => false,:publish_at => 3.days.ago,:unpublish_at => 2.hours.ago)#unpublished and expired
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should have draft" do
|
182
|
+
Post.draft.count.should == 1
|
183
|
+
Post.draft.first.should == @p3
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe "new record" do
|
188
|
+
it "should default to Time.now" do
|
189
|
+
# d = Time.now
|
190
|
+
# Time.stub!(:now).and_return d
|
191
|
+
a = Article.new
|
192
|
+
a.publish_at.should_not be_nil
|
193
|
+
end
|
194
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
end
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
10
|
+
require 'ar_publish_control'
|
11
|
+
|
12
|
+
ActiveRecord::Base.establish_connection(
|
13
|
+
:adapter=>'sqlite3',
|
14
|
+
:dbfile=> File.join(File.dirname(__FILE__),'db','test.db')
|
15
|
+
)
|
16
|
+
|
17
|
+
#ActiveRecord::Base.connection.query_cache_enabled = false
|
18
|
+
|
19
|
+
LOGGER = Logger.new(File.dirname(__FILE__)+'/log/test.log')
|
20
|
+
ActiveRecord::Base.logger = LOGGER
|
21
|
+
|
22
|
+
class Comment < ActiveRecord::Base
|
23
|
+
belongs_to :post
|
24
|
+
|
25
|
+
named_scope :recent, lambda{|limit|
|
26
|
+
{:order => 'created_at desc',:limit => limit}
|
27
|
+
}
|
28
|
+
|
29
|
+
named_scope :desc, :order => 'publish_at desc'
|
30
|
+
|
31
|
+
publish_control
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class Post < ActiveRecord::Base
|
36
|
+
|
37
|
+
has_many :comments, :dependent => :destroy
|
38
|
+
|
39
|
+
has_many :published_comments, :class_name => 'Comment', :conditions => Comment.published_conditions
|
40
|
+
|
41
|
+
publish_control
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
class Article < ActiveRecord::Base
|
46
|
+
publish_control :publish_by_default => false
|
47
|
+
end
|
data/tasks/db.rake
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
database_config = {
|
2
|
+
:adapter=>'sqlite3',
|
3
|
+
:dbfile=> File.join(File.dirname(__FILE__),'..','spec','db','test.db')
|
4
|
+
}
|
5
|
+
|
6
|
+
ActiveRecord::Base.establish_connection(database_config)
|
7
|
+
# define a migration
|
8
|
+
class TestSchema < ActiveRecord::Migration
|
9
|
+
def self.up
|
10
|
+
create_table :posts do |t|
|
11
|
+
t.string :title
|
12
|
+
t.boolean :is_published
|
13
|
+
t.datetime :publish_at
|
14
|
+
t.datetime :unpublish_at
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :articles do |t|
|
19
|
+
t.string :title
|
20
|
+
t.boolean :is_published
|
21
|
+
t.datetime :publish_at
|
22
|
+
t.datetime :unpublish_at
|
23
|
+
t.timestamps
|
24
|
+
end
|
25
|
+
|
26
|
+
create_table :comments do |t|
|
27
|
+
t.text :body
|
28
|
+
t.boolean :is_published
|
29
|
+
t.integer :post_id
|
30
|
+
t.datetime :publish_at
|
31
|
+
t.datetime :unpublish_at
|
32
|
+
t.timestamps
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.down
|
37
|
+
drop_table :posts
|
38
|
+
drop_table :comments
|
39
|
+
drop_table :articles
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
namespace :db do
|
45
|
+
desc "migrate test schema"
|
46
|
+
task :create do
|
47
|
+
File.unlink(database_config[:dbfile])
|
48
|
+
ActiveRecord::Base.connection # this creates the DB
|
49
|
+
# run the migration
|
50
|
+
TestSchema.migrate(:up)
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Destroy test schema"
|
54
|
+
task :destroy do
|
55
|
+
TestSchema.migrate(:down)
|
56
|
+
end
|
57
|
+
end
|
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
require 'spec'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'spec/rake/spectask'
|
9
|
+
rescue LoadError
|
10
|
+
puts <<-EOS
|
11
|
+
To use rspec for testing you must install rspec gem:
|
12
|
+
gem install rspec
|
13
|
+
EOS
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run the specs under spec/models"
|
18
|
+
Spec::Rake::SpecTask.new do |t|
|
19
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
20
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ar_publish_control
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.9
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ismael Celis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-05 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: newgem
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
version:
|
35
|
+
description: Add start/end publishing dates to your ActiveRecord models.
|
36
|
+
email:
|
37
|
+
- ismaelct@gmail.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
- PostInstall.txt
|
46
|
+
- README.rdoc
|
47
|
+
files:
|
48
|
+
- History.txt
|
49
|
+
- Manifest.txt
|
50
|
+
- PostInstall.txt
|
51
|
+
- README.rdoc
|
52
|
+
- Rakefile
|
53
|
+
- ar_publish_control.gemspec
|
54
|
+
- lib/ar_publish_control.rb
|
55
|
+
- script/console
|
56
|
+
- script/destroy
|
57
|
+
- script/generate
|
58
|
+
- spec/ar_publish_control_spec.rb
|
59
|
+
- spec/spec.opts
|
60
|
+
- spec/spec_helper.rb
|
61
|
+
- tasks/db.rake
|
62
|
+
- tasks/rspec.rake
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://github.com/ismasan/ar_publish_control
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message: PostInstall.txt
|
68
|
+
rdoc_options:
|
69
|
+
- --main
|
70
|
+
- README.rdoc
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project: ar_publish_control
|
88
|
+
rubygems_version: 1.3.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Add start/end publishing dates to your ActiveRecord models.
|
92
|
+
test_files: []
|
93
|
+
|