oktoberliner-ar_publish_control_with_scopes 0.0.1

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/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-11-17
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
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
@@ -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
+
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,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ar_publish_control_with_scopes}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ismael Celis, Vadim Rastyagaev"]
9
+ s.date = %q{2008-11-18}
10
+ s.description = %q{Publish control for ActiveRecord}
11
+ s.email = ["abc@oktoberliner.ru"]
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_with_scopes.gemspec", "lib/ar_publish_control_with_scopes.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.post_install_message = %q{PostInstall.txt}
16
+ s.rdoc_options = ["--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubygems_version = %q{1.3.1}
19
+ s.summary = %q{Publish control for ActiveRecord, with start and optional end dates}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 2
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ s.add_development_dependency(%q<newgem>, [">= 1.1.0"])
27
+ s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
28
+ else
29
+ s.add_dependency(%q<newgem>, [">= 1.1.0"])
30
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<newgem>, [">= 1.1.0"])
34
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
35
+ end
36
+ end
@@ -0,0 +1,318 @@
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
+ # #@@publish_scopes = []
98
+ #
99
+ def publish_scopes
100
+ read_inheritable_attribute :publish_scopes
101
+ end
102
+
103
+ def publish_control(options = {})
104
+ # don't allow multiple calls
105
+ return if self.included_modules.include?(ArPublishControl::Publishable::InstanceMethods)
106
+
107
+ write_inheritable_attribute(:publish_scopes, options[:scopes] || [])
108
+
109
+ publish_scopes.each do |scope|
110
+ send :class_eval, %Q{
111
+ def #{scope}_published?
112
+ is_#{scope}_published?
113
+ end
114
+
115
+ def #{scope}_publish
116
+ return if #{scope}_published?
117
+ self.is_#{scope}_published = true
118
+ self.publish_at = Time.now
119
+ self.unpublish_at = nil
120
+ end
121
+
122
+ def #{scope}_publish!
123
+ #{scope}_publish
124
+ save!
125
+ end
126
+
127
+ def #{scope}_unpublish
128
+ self.is_#{scope}_published = false
129
+ end
130
+
131
+ def #{scope}_unpublish!
132
+ #{scope}_unpublish
133
+ save!
134
+ end
135
+ }
136
+ end
137
+
138
+ publish_by_default = options[:publish_by_default] || true
139
+
140
+
141
+ send :include, ArPublishControl::Publishable::InstanceMethods
142
+
143
+ named_scope :published, lambda{{:conditions => published_conditions}}
144
+ named_scope :unpublished, lambda{{:conditions => unpublished_conditions}}
145
+ named_scope :upcoming, lambda{{:conditions => upcoming_conditions}}
146
+ named_scope :expired, lambda {{:conditions => expired_conditions}}
147
+ named_scope :draft, :conditions => {:is_published => false}
148
+
149
+ named_scope :published_only, lambda {|*args|
150
+ bool = (args.first.nil? ? true : (args.first)) # nil = true by default
151
+ bool ? {:conditions => published_conditions} : {}
152
+ }
153
+
154
+ validate :validate_publish_date_consistency
155
+ before_create :publish_by_default if options[:publish_by_default]
156
+ end
157
+
158
+ # Takes a block whose containing SQL queries are limited to
159
+ # published objects. You can pass a boolean flag indicating
160
+ # whether this scope should be applied or not--for example,
161
+ # you might want to disable it when the user is an administrator.
162
+ # By default the scope is applied.
163
+ #
164
+ # Example usage:
165
+ #
166
+ # Post.published_only(!logged_in?)
167
+ # @post.comments.published_only(!logged_in?)
168
+ #
169
+
170
+ protected
171
+
172
+ # returns a string for use in SQL to filter the query to unpublished results only
173
+ # Meant for internal use only
174
+ def unpublished_conditions
175
+ t = Time.now
176
+ unpld_conds = if publish_scopes.empty?
177
+ "#{table_name}.is_published = ?"
178
+ else
179
+ '(' + publish_scopes.collect{|s| "#{table_name}.is_#{s}_published = ?" }.join(' OR ') + ')'
180
+ end
181
+ ["(#{unpld_conds} OR #{table_name}.publish_at > ?) OR (#{table_name}.unpublish_at IS NOT NULL AND #{table_name}.unpublish_at < ?)",false,t,t]
182
+ end
183
+
184
+ def is_published_conditions
185
+ pld_conds = if publish_scopes.empty?
186
+ "#{table_name}.is_published = ?"
187
+ else
188
+ '(' + publish_scopes.collect{|s| "#{table_name}.is_#{s}_published = ?" }.join(' AND ') + ')'
189
+ end
190
+ end
191
+
192
+ # return a string for use in SQL to filter the query to published results only
193
+ # Meant for internal use only
194
+ def published_conditions(scope = nil)
195
+ t = Time.now
196
+ ["(#{is_published_conditions} AND #{table_name}.publish_at <= ?) AND (#{table_name}.unpublish_at IS NULL OR #{table_name}.unpublish_at > ?)",true,t,t]
197
+ end
198
+
199
+ def upcoming_conditions(scope = nil)
200
+ t = Time.now
201
+ ["(#{is_published_conditions} AND #{table_name}.publish_at > ?)",true,t]
202
+ end
203
+
204
+ def expired_conditions(scope = nil)
205
+ ["(#{table_name}.unpublish_at IS NOT NULL AND #{table_name}.unpublish_at < ?)",t]
206
+ end
207
+ end
208
+
209
+ module InstanceMethods
210
+
211
+ def after_initialize
212
+ write_attribute(:publish_at, Time.now) if publish_at.nil?
213
+ end
214
+
215
+ # ActiveRecrod callback fired on +before_create+ to make
216
+ # sure a new object always gets a publication date; if
217
+ # none is supplied it defaults to the creation date.
218
+ def publish_by_default
219
+ if self.class.publish_scopes.empty?
220
+ write_attribute(:is_published, true) if is_published.nil?
221
+ else
222
+ self.class.publish_scopes.each do |scope|
223
+ write_attribute("is_#{scope}_published", true) if self.read_attribute("is_#{scope}_published").nil?
224
+ end
225
+ end
226
+ end
227
+
228
+ # Validate that unpublish_at is greater than publish_at
229
+ # publish_at must not be nil
230
+ def validate_publish_date_consistency
231
+ if unpublish_at && publish_at && unpublish_at <= publish_at
232
+ errors.add(:unpublish_at,"should be greater than publication date or empty")
233
+ end
234
+ end
235
+
236
+ def check_for_all_scopes(method_name)
237
+ res = true
238
+ self.class.publish_scopes.each do |scope|
239
+ res &= send "#{scope}_#{method_name}"
240
+ end
241
+ res
242
+ end
243
+
244
+ def do_for_all_scopes(method_name)
245
+ self.class.publish_scopes.each do |scope|
246
+ send "#{scope}_#{method_name}"
247
+ end
248
+ end
249
+ public
250
+
251
+ # Return whether the current object is published or not
252
+ def published?
253
+ p = if self.class.publish_scopes.empty?
254
+ is_published?
255
+ else
256
+ check_for_all_scopes('published')
257
+ end
258
+ (p && (publish_at <=> Time.now) <= 0) && (unpublish_at.nil? || (unpublish_at <=> Time.now) >= 0)
259
+ end
260
+
261
+ def upcoming?
262
+ p = if self.class.publish_scopes.empty?
263
+ is_published?
264
+ else
265
+ check_for_all_scopes('published?')
266
+ end
267
+ (p && publish_at > Time.now)
268
+ end
269
+
270
+ def expired?
271
+ (!unpublish_at.nil? && unpublish_at < Time.now)
272
+ end
273
+
274
+ # Indefinitely publish the current object right now
275
+ def publish
276
+ if self.class.publish_scopes.empty?
277
+ return if published?
278
+ self.is_published = true
279
+ self.publish_at = Time.now
280
+ self.unpublish_at = nil
281
+ else
282
+ do_for_all_scopes :publish
283
+ end
284
+ end
285
+
286
+ # Same as publish, but immediatly saves the object.
287
+ # Raises an error when saving fails.
288
+ def publish!
289
+ publish
290
+ save!
291
+ end
292
+
293
+ # Immediatly unpublish the current object
294
+ def unpublish
295
+ if self.class.publish_scopes.empty?
296
+ self.is_published = false
297
+ else
298
+ do_for_all_scopes :unpublish
299
+ end
300
+ end
301
+
302
+ # Same as unpublish, but immediatly saves the object.
303
+ # Raises an error when saving files.
304
+ def unpublish!
305
+ unpublish
306
+ save!
307
+ end
308
+
309
+ end
310
+ end
311
+
312
+
313
+ end
314
+
315
+ require 'rubygems'
316
+ require 'active_record'
317
+
318
+ 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
@@ -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,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oktoberliner-ar_publish_control_with_scopes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ismael Celis, Vadim Rastyagaev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-11-18 00:00:00 -08: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.1.0
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: Publish control for ActiveRecord
36
+ email:
37
+ - abc@oktoberliner.ru
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_with_scopes.gemspec
54
+ - lib/ar_publish_control_with_scopes.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: false
64
+ homepage:
65
+ licenses:
66
+ post_install_message: PostInstall.txt
67
+ rdoc_options:
68
+ - --main
69
+ - README.rdoc
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: "0"
83
+ version:
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.3.5
88
+ signing_key:
89
+ specification_version: 2
90
+ summary: Publish control for ActiveRecord, with start and optional end dates
91
+ test_files: []
92
+