Browse files

inital version

git-svn-id: https://actsaspublishable.googlecode.com/svn/trunk@2 8478b3f8-0828-0410-aa1f-879340598c00
  • Loading branch information...
1 parent 62b89b7 commit 8de6b37eb37cc113353f74847aac5919d48768f2 arjan.vandergaag committed Jan 29, 2007
Showing with 362 additions and 0 deletions.
  1. +20 −0 MIT-LICENSE
  2. +19 −0 README
  3. +22 −0 Rakefile
  4. +1 −0 init.rb
  5. +2 −0 install.rb
  6. +155 −0 lib/acts_as_publishable.rb
  7. +32 −0 test/abstract_unit.rb
  8. +59 −0 test/acts_as_publishable_test.rb
  9. +12 −0 test/database.yml
  10. +7 −0 test/fixtures/article.rb
  11. +26 −0 test/fixtures/articles.yml
  12. +7 −0 test/schema.rb
View
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2005 Arjan van der Gaag
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
19 README
@@ -0,0 +1,19 @@
+= acts_as_publishable
+
+This plugin lets you add basic time-based publishing-behaviour to your models by specifying a publication
+range with to date attributes.
+
+To use simply call the plugin in your model:
+
+ class Post < ActiveRecord::Base
+ acts_as_publishable
+ end
+
+This includes two special finder methods for finding published and unpublished models, and adds some
+basic instance methods for working with individual objects--most notably the 'published?'-flag.
+
+You can check if the plugin installed correctly by testing it yourself (in the plugin dir.):
+
+ rake test
+
+Find more information at this plugins homepage at http://code.google.com/p/actsaspublishable.
View
22 Rakefile
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the acts_as_publishable plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the acts_as_publishable plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'ActsAsPublishable'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
View
1 init.rb
@@ -0,0 +1 @@
+require 'acts_as_publishable'
View
2 install.rb
@@ -0,0 +1,2 @@
+# print the readme file
+puts IO.read(File.join(File.dirname(__FILE__), 'README'))
View
155 lib/acts_as_publishable.rb
@@ -0,0 +1,155 @@
+# Copyright (c) 2005 Arjan van der Gaag
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Agw #:nodoc:
+ module Acts #:nodoc:
+ # Specify this act if you want to show or hide your object based on date/time settings. This act lets you
+ # specify two dates two form a range in which the model is publicly available; it is unavailable outside it.
+ #
+ # Usage
+ #
+ # You can add this behaviour to your model like so:
+ #
+ # class Post < ActiveRecord::Base
+ # acts_as_publishable
+ # end
+ #
+ # Then you can use it as follows:
+ #
+ # post = Post.create(:title => 'Hello world')
+ # post.published? # => true
+ #
+ # post.publish!
+ # post.published? # => true
+ #
+ # post.unpublish!
+ # post.published? # => false
+ #
+ # You can use two special finder methods to find the published or unpublished objects.
+ # Use them like you use your standard <tt>#find</tt>:
+ #
+ # Post.find(:all).size # => 15
+ # Post.find_published(:all).size # => 10
+ # Post.find_unpublished(:all).size # => 5
+ #
+ module Publishable
+
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ # == Configuration options
+ #
+ # Right now this plugin has no configuration options. Do note that models with no publication dates
+ # are by default published, not unpublished. So, if you want to hide your model you have to explicitly
+ # set these dates.
+ #
+ # == Database Schema
+ #
+ # The model that you're publishing needs to have two special date attributes:
+ #
+ # * publish_at
+ # * unpublish_at
+ #
+ # These attributes have no further requirements or required validations; they
+ # just need to be <tt>datetime</tt>-columns.
+ #
+ # You can use a migration like this to add these columns to your model:
+ #
+ # class AddPublicationDatesToPosts < ActiveRecord::Migration
+ # def self.up
+ # add_column :posts, :publish_at, :datetime
+ # add_column :posts, :unpublish_at, :datetime
+ # end
+ #
+ # def self.down
+ # remove_column :posts, :publish_at
+ # remove_column :posts, :unpublish_at
+ # end
+ # end
+ #
+ def acts_as_publishable()
+ # don't allow multiple calls
+ return if self.included_modules.include?(Agw::Acts::Publishable::InstanceMethods)
+ send :include, Agw::Acts::Publishable::InstanceMethods
+ end
+
+ # Special finder method for finding all objects that are published.
+ # Use the same way as #find
+ def find_published(*args)
+ t = Time.now.to_s(:db)
+ c = "(publish_at IS NULL OR publish_at <= '#{t}') AND (unpublish_at IS NULL OR unpublish_at > '#{t}')"
+ with_scope :find => { :conditions => c} do
+ find(*args)
+ end
+ end
+
+ # Special finder method for finding all objects that are not published.
+ # Use the same way as #find
+ def find_unpublished(*args)
+ t = Time.now.to_s(:db)
+ c = "(publish_at IS NOT NULL AND publish_at > '#{t}') OR (unpublish_at IS NOT NULL AND unpublish_at < '#{t}')"
+ with_scope :find => { :conditions => c } do
+ find(*args)
+ end
+ end
+ end
+
+ module InstanceMethods
+
+ # Return whether the current object is published or not
+ def published?
+ (publish_at.nil? || (publish_at <=> Time.now) <= 0) && (unpublish_at.nil? || (unpublish_at <=> Time.now) >= 0)
+ end
+
+ # Indefinitely publish the current object right now
+ def publish
+ return if published?
+ self.publish_at = Time.now
+ self.unpublish_at = nil
+ end
+
+ # Same as publish, but immediatly saves the object.
+ # Raises an error when saving fails.
+ def publish!
+ publish
+ save!
+ end
+
+ # Immediatly unpublish the current object
+ def unpublish
+ return unless published?
+ self.unpublish_at = 1.minute.ago
+ end
+
+ # Same as unpublish, but immediatly saves the object.
+ # Raises an error when saving files.
+ def unpublish!
+ unpublish
+ save!
+ end
+ end
+ end
+ end
+end
+
+ActiveRecord::Base.send :include, Agw::Acts::Publishable
View
32 test/abstract_unit.rb
@@ -0,0 +1,32 @@
+$:.unshift(File.dirname(__FILE__) + '/../lib')
+
+require 'test/unit'
+require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
+require 'active_record/fixtures'
+
+config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
+ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
+ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3'])
+
+load(File.dirname(__FILE__) + "/schema.rb")
+
+Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
+$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
+
+class Test::Unit::TestCase #:nodoc:
+ def create_fixtures(*table_names)
+ if block_given?
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
+ else
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
+ end
+ end
+
+ # Turn off transactional fixtures if you're working with MyISAM tables in MySQL
+ self.use_transactional_fixtures = true
+
+ # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
+ self.use_instantiated_fixtures = true
+
+ # Add more helper methods to be used by all tests here...
+end
View
59 test/acts_as_publishable_test.rb
@@ -0,0 +1,59 @@
+require 'test/unit'
+require File.join(File.dirname(__FILE__), 'abstract_unit')
+require File.join(File.dirname(__FILE__), 'fixtures/article')
+
+class ActsAsPublishableTest < Test::Unit::TestCase
+
+ fixtures :articles
+
+ def setup
+ @published_articles = [@undated_article, @published_article, @regular_article]
+ @unpublished_articles = [@scheduled_article, @unpublished_article]
+ end
+
+ def test_published
+ @published_articles.each { |p| assert p.published?, "Article #{p.id} should not be flagged unpublished, but is: #{p.inspect}" }
+ @unpublished_articles.each { |p| assert !p.published?, "Article #{p.id} should not be flagged published, but is: #{p.inspect}" }
+ end
+
+ def test_no_dates_should_be_published
+ assert Article.find_published(:all).include?(@undated_article)
+ assert !Article.find_unpublished(:all).include?(@undated_articlet)
+ end
+
+ def test_published_posts_should_be_found
+ p = Article.find_published(:all)
+ @published_articles.each do |post|
+ assert p.include?(post), "Article #{post.id} is not found when using #find_published"
+ end
+ assert_equal @published_articles.size, p.size
+ end
+
+ def test_unpublished_posts_should_not_be_found
+ p = Article.find_unpublished(:all)
+ @unpublished_articles.each do |post|
+ assert p.include?(post), "Article #{post.id} is not found when using #find_unpublished"
+ end
+ assert_equal @unpublished_articles.size, p.size
+ end
+
+ def test_publish
+ @unpublished_articles.each do |p|
+ p.publish
+ assert p.published?, "Article #{p.id} should now be published but is not: #{p.inspect}"
+ assert !p.reload.published?
+ p.publish!
+ assert p.reload.published?
+ end
+ end
+
+ def test_unpublish
+ @published_articles.each do |p|
+ p.unpublish
+ assert !p.published?, "Article #{p.id} should now be unpublished but is not: #{p.inspect}"
+ assert p.reload.published?
+ p.unpublish!
+ assert !p.reload.published?
+ end
+ end
+end
View
12 test/database.yml
@@ -0,0 +1,12 @@
+sqlite:
+ adapter: sqlite
+ dbfile: acts_as_publishable_plugin.sqlite.db
+sqlite3:
+ adapter: sqlite3
+ dbfile: acts_as_publishable_plugin.sqlite3.db
+mysql:
+ adapter: mysql
+ host: localhost
+ username: root
+ password:
+ database: acts_as_publishable_plugin_test
View
7 test/fixtures/article.rb
@@ -0,0 +1,7 @@
+class Article < ActiveRecord::Base
+ acts_as_publishable
+
+ def slug
+ 'hello world'
+ end
+end
View
26 test/fixtures/articles.yml
@@ -0,0 +1,26 @@
+undated_article:
+ id: 1
+ title: A post without publication dates
+ publish_at:
+ unpublish_at:
+published_article:
+ id: 2
+ title: A post with a publication date before now
+ publish_at: <%= 10.minutes.ago.to_s(:db) %>
+ unpublish_at:
+scheduled_article:
+ id: 3
+ title: A post that is to be published in the future
+ publish_at: <%= 2.days.since.to_s(:db) %>
+ unpublish_at: <%= 10.days.since.to_s(:db) %>
+unpublished_article:
+ id: 4
+ title: A post that has already been unpublished
+ publish_at: <%= 10.days.ago.to_s(:db) %>
+ unpublish_at: <%= 2.days.ago.to_s(:db) %>
+regular_article:
+ id: 5
+ title: A published post with both dates set
+ publish_at: <%= 2.days.ago.to_s(:db) %>
+ unpublish_at: <%= 2.days.since.to_s(:db) %>
+
View
7 test/schema.rb
@@ -0,0 +1,7 @@
+ActiveRecord::Schema.define(:version => 0) do
+ create_table :articles, :force => true do |t|
+ t.column :title, :string
+ t.column :publish_at, :datetime
+ t.column :unpublish_at, :datetime
+ end
+end

0 comments on commit 8de6b37

Please sign in to comment.