ar_publish_control 0.0.9

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.
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-11-17
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -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
@@ -0,0 +1,7 @@
1
+
2
+ For more information on ar_publish_control, see http://ar_publish_control.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
@@ -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.
@@ -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
@@ -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"
@@ -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)
@@ -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
@@ -0,0 +1 @@
1
+ --colour
@@ -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
@@ -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
@@ -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
+