publishing_logic 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -19,4 +19,5 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
- publishing_logic.gemspec
22
+ spec/support/test_publishing_logic.db
23
+ test.log
data/README.rdoc CHANGED
@@ -4,12 +4,14 @@ Publishing logic for ActiveRecord models
4
4
  * Generates a migration with fields required for publishing
5
5
  logic. Fields are:
6
6
  * publishing_enabled:boolean
7
- * publish_from_datetime:datetime
8
- * publish_until_datetime:datetime
7
+ * published_at:datetime
8
+ * published_until:datetime (optional)
9
9
  * Defines logic on models that include PublishingLogic::ModelLogic
10
10
  * published named scope
11
11
  * published? method
12
- * ordering by publish_from_date
12
+ * ordering by published_at
13
+
14
+ The source for this gem can be found on http://github.com/unboxed/publishing_logic
13
15
 
14
16
  == Note on Patches/Pull Requests
15
17
 
@@ -24,4 +26,4 @@ Publishing logic for ActiveRecord models
24
26
 
25
27
  == Copyright
26
28
 
27
- Copyright (c) 2009 Unboxed Consulting. See LICENSE for details.
29
+ Copyright (c) 2009 Unboxed Consulting and Channel 5 Broadcasting Ltd. See LICENSE for details.
data/Rakefile CHANGED
@@ -12,6 +12,12 @@ begin
12
12
  gem.authors = ["Unboxed Consulting"]
13
13
  gem.add_development_dependency "rspec", ">= 1.2.9"
14
14
  gem.add_development_dependency "cucumber", ">= 0"
15
+ gem.add_development_dependency 'rspec-rails', ">= 1.3.0"
16
+ gem.add_development_dependency 'factory_girl', ">= 1.2.0"
17
+ gem.add_development_dependency 'activesupport', ">= 2.3.0"
18
+ gem.add_development_dependency 'activerecord', ">= 2.3.0"
19
+ gem.add_development_dependency 'database_cleaner', ">= 0.5.0"
20
+
15
21
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
22
  end
17
23
  Jeweler::GemcutterTasks.new
@@ -33,17 +39,6 @@ end
33
39
 
34
40
  task :spec => :check_dependencies
35
41
 
36
- begin
37
- require 'cucumber/rake/task'
38
- Cucumber::Rake::Task.new(:features)
39
-
40
- task :features => :check_dependencies
41
- rescue LoadError
42
- task :features do
43
- abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
44
- end
45
- end
46
-
47
42
  task :default => :spec
48
43
 
49
44
  require 'rake/rdoctask'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.2.0
data/lib/model_logic.rb CHANGED
@@ -1,41 +1,82 @@
1
1
  module PublishingLogic
2
2
  module ModelLogic
3
3
 
4
- def published?
5
- return false if published_at && Time.now < published_at
6
- return false if published_until && Time.now > published_until
7
- publishing_enabled?
8
- end
9
-
10
4
  def self.included(base)
11
- base.extend(ClassMethods)
12
- base.instance_eval do
13
- named_scope :published, lambda {{ :conditions => ["#{base.table_name}.publishing_enabled = true AND \
14
- (#{base.table_name}.published_until is null or #{base.table_name}.published_until > ?) AND \
15
- (#{base.table_name}.published_at is null or #{base.table_name}.published_at < ?)",
16
- Time.now.utc, Time.now.utc] }} do
17
-
18
- # TODO Not using table name with the following methods so in danger of getting ambiguous column names
19
- def newest
20
- find(:first, :order => "published_at DESC")
21
- end
22
-
23
- def oldest
24
- find(:last, :order => "published_at DESC")
25
- end
26
- end
27
-
5
+ module_to_include = if base.column_names.include?('published_until')
6
+ WithPublishedUntilField
7
+ else
8
+ WithoutPublishedUntilField
9
+ end
10
+ base.class_eval do
28
11
  # If objects have identical published_at values, order by created_at. If these are
29
12
  # identical as well, then order by id. This is done to ensure there is a unique
30
13
  # ordering of objects, ordering by newest and oldest should result in arrays that are
31
14
  # the inverse of the other.
32
- named_scope :by_date_oldest_first, :order => "#{base.table_name}.published_at ASC, #{base.table_name}.created_at ASC, #{base.table_name}.id ASC"
33
- named_scope :by_date_newest_first, :order => "#{base.table_name}.published_at DESC, #{base.table_name}.created_at DESC, #{base.table_name}.id DESC"
15
+ named_scope :by_publication_date_oldest_first, :order => "#{base.table_name}.published_at ASC, #{base.table_name}.created_at ASC, #{base.table_name}.id ASC"
16
+ named_scope :by_publication_date_newest_first, :order => "#{base.table_name}.published_at DESC, #{base.table_name}.created_at DESC, #{base.table_name}.id DESC"
17
+
18
+ include module_to_include
19
+
20
+ class << self
21
+ def by_date_oldest_first
22
+ ::ActiveSupport::Deprecation.warn("by_date_oldest_first is deprecated and will be removed in the next version of this gem (use by_publication_date_oldest_first instead, it's more intention revealing).", caller)
23
+ by_publication_date_oldest_first
24
+ end
25
+
26
+ def by_date_newest_first
27
+ ::ActiveSupport::Deprecation.warn("by_date_newest_first is deprecated and will be removed in the next version of this gem (use by_publication_date_newest_first instead, it's more intention revealing).", caller)
28
+ by_publication_date_newest_first
29
+ end
30
+ end
34
31
  end
35
32
  end
36
33
 
37
- module ClassMethods
34
+ module WithoutPublishedUntilField
35
+ def self.included(base)
36
+ base.class_eval do
37
+ named_scope :published, lambda {{ :conditions => ["#{base.table_name}.publishing_enabled = ? AND \
38
+ (#{base.table_name}.published_at is null or #{base.table_name}.published_at < ?)",
39
+ true, Time.now.utc] }} do
40
+ def newest
41
+ find(:first, :order => "#{proxy_scope.table_name}.published_at DESC")
42
+ end
43
+
44
+ def oldest
45
+ find(:last, :order => "#{proxy_scope.table_name}.published_at DESC")
46
+ end
47
+ end
48
+
49
+ def published?
50
+ return false if published_at && Time.now < published_at
51
+ publishing_enabled?
52
+ end
53
+ end
54
+ end
38
55
  end
39
56
 
57
+ module WithPublishedUntilField
58
+ def self.included(base)
59
+ base.class_eval do
60
+ named_scope :published, lambda {{ :conditions => ["#{base.table_name}.publishing_enabled = ? AND \
61
+ (#{base.table_name}.published_until is null or #{base.table_name}.published_until > ?) AND \
62
+ (#{base.table_name}.published_at is null or #{base.table_name}.published_at < ?)",
63
+ true, Time.now.utc, Time.now.utc] }} do
64
+ def newest
65
+ find(:first, :order => "#{proxy_scope.table_name}.published_at DESC")
66
+ end
67
+
68
+ def oldest
69
+ find(:last, :order => "#{proxy_scope.table_name}.published_at DESC")
70
+ end
71
+ end
72
+
73
+ def published?
74
+ return false if published_at && Time.now < published_at
75
+ return false if published_until && Time.now > published_until
76
+ publishing_enabled?
77
+ end
78
+ end
79
+ end
80
+ end
40
81
  end
41
82
  end
@@ -1,4 +1,6 @@
1
1
  class PublishingLogicFieldsGenerator < Rails::Generator::NamedBase
2
+ default_options :use_published_until_field => true, :skip_admin_form => false
3
+
2
4
  def initialize(args, options)
3
5
  super(args, options)
4
6
  end
@@ -7,9 +9,26 @@ class PublishingLogicFieldsGenerator < Rails::Generator::NamedBase
7
9
  record do |m|
8
10
  class_name.camelize.constantize # Raise an error if model does not yet exist
9
11
  m.migration_template 'db/migrate/add_publishing_logic_fields.rb.erb', 'db/migrate', :assigns => {
10
- :migration_name => "AddPublishingLogicFieldsTo#{class_name.pluralize.gsub(/::/, '')}"
12
+ :migration_name => "AddPublishingLogicFieldsTo#{class_name.pluralize.gsub(/::/, '')}",
13
+ :use_published_until_field => options[:use_published_until_field]
11
14
  }, :migration_file_name => "add_publishing_logic_fields_to_#{file_path.gsub(/\//, '_').pluralize}"
12
- m.template 'app/views/publishing_logic_fields.html.erb', File.join('app', 'views', 'admin', plural_name, "_publishing_logic_fields.html.erb")
15
+ unless options[:skip_admin_form]
16
+ m.template 'app/views/publishing_logic_fields.html.erb',
17
+ File.join('app', 'views', 'admin', plural_name, "_publishing_logic_fields.html.erb"),
18
+ :assigns => {
19
+ :use_published_until_field => options[:use_published_until_field]
20
+ }
21
+ end
13
22
  end
14
23
  end
24
+
25
+ protected
26
+ def add_options!(opt)
27
+ opt.separator ''
28
+ opt.separator 'Options:'
29
+ opt.on("--no-published-until",
30
+ "Don't add the published_until field to this model") { |v| options[:use_published_until_field] = false }
31
+ opt.on("--skip-admin-form",
32
+ "Don't generate the admin form partial for this model") { |v| options[:skip_admin_form] = true }
33
+ end
15
34
  end
@@ -2,10 +2,10 @@
2
2
  <%%= form.label :published_at %><br />
3
3
  <%%= form.datetime_select :published_at %>
4
4
  </p>
5
- <p>
5
+ <% if use_published_until_field %><p>
6
6
  <%%= form.label :published_until %><br />
7
7
  <%%= form.datetime_select :published_until %>
8
- </p>
8
+ </p><% end %>
9
9
  <p>
10
10
  <%%= form.label :publishing_enabled %>
11
11
  <%%= form.check_box :publishing_enabled %>
@@ -2,18 +2,17 @@
2
2
 
3
3
  class <%= migration_name %> < ActiveRecord::Migration
4
4
  def self.up
5
- add_column :<%= table_name %>, :publishing_enabled, :boolean
6
- add_column :<%= table_name %>, :published_at, :datetime
7
- add_column :<%= table_name %>, :published_until, :datetime
8
-
9
- add_index :<%= table_name %>, [:published_at, :publishing_enabled, :published_until], :name => :index_<%= table_name %>_on_publishing_logic_fields
5
+ change_table :<%= table_name %> do |t|
6
+ t.boolean :publishing_enabled
7
+ t.datetime :published_at<% if use_published_until_field %>, :published_until<% end %>
8
+ t.index [:published_at, :publishing_enabled<% if use_published_until_field %>, :published_until<% end %>], :name => 'index_<%= table_name %>_on_publishing_logic_fields'
9
+ end
10
10
  end
11
11
 
12
12
  def self.down
13
- remove_column :<%= table_name %>, :publishing_enabled
14
- remove_column :<%= table_name %>, :published_at
15
- remove_column :<%= table_name %>, :published_until
16
-
17
- remove_index :<%= table_name %>, :name => :index_<%= table_name %>_on_publishing_logic_fields
13
+ change_table :<%= table_name %> do |t|
14
+ t.remove :publishing_enabled, :published_at<% if use_published_until_field %>, :published_until<% end %>
15
+ t.remove_index :name => 'index_<%= table_name %>_on_publishing_logic_fields'
16
+ end
18
17
  end
19
18
  end
@@ -0,0 +1,93 @@
1
+ shared_examples_for 'a model with publish logic' do
2
+ def create_objects_with_different_published_at_dates(for_class)
3
+ factory_name = for_class.name.underscore.to_sym
4
+ @object2 = Factory.create(factory_name, :publishing_enabled => true, :published_at => 2.days.ago)
5
+ @object1 = Factory.create(factory_name, :publishing_enabled => true, :published_at => 1.days.ago)
6
+ @object3 = Factory.create(factory_name, :publishing_enabled => true, :published_at => 3.days.ago)
7
+ end
8
+
9
+ describe "ordering by published_at" do
10
+ describe "from the published scope" do
11
+ before do
12
+ create_objects_with_different_published_at_dates(@class)
13
+ end
14
+
15
+ describe "newest first" do
16
+ it "should be the most recently published object" do
17
+ @class.published.newest.should == @object1
18
+ end
19
+ end
20
+
21
+ describe "oldest first" do
22
+ it "should be the object published the longest ago" do
23
+ @class.published.oldest.should == @object3
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "by publication date oldest first" do
29
+ before do
30
+ create_objects_with_different_published_at_dates(@class)
31
+ end
32
+
33
+ it "should return the items, oldest first" do
34
+ @class.by_publication_date_oldest_first.map(&:id).should == [@object3,
35
+ @object2,
36
+ @object1].map(&:id)
37
+ end
38
+
39
+ it "should order by created_at date if published_ats are equal" do
40
+ @object2b = Factory.create(@class.name.underscore.to_sym,
41
+ :publishing_enabled => true,
42
+ :published_at => @object2.published_at,
43
+ :created_at => 3.days.ago)
44
+ @class.by_publication_date_oldest_first.map(&:id).should == [@object3,
45
+ @object2b,
46
+ @object2,
47
+ @object1].map(&:id)
48
+ end
49
+
50
+ it 'should have deprecated by_date_oldest_first' do
51
+ assert_deprecated do
52
+ @class.by_date_oldest_first
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "by publication date newest first" do
58
+ before do
59
+ create_objects_with_different_published_at_dates(@class)
60
+ end
61
+
62
+ it "should return the items, newest first" do
63
+ @class.by_publication_date_newest_first.map(&:id).should == [@object1,
64
+ @object2,
65
+ @object3].map(&:id)
66
+ end
67
+
68
+ it "should order by created_at date if published_ats are equal" do
69
+ @object2b = Factory.create(@class.name.underscore.to_sym,
70
+ :publishing_enabled => true,
71
+ :published_at => @object2.published_at,
72
+ :created_at => 3.days.from_now)
73
+ @class.by_publication_date_newest_first.map(&:id).should == [@object1,
74
+ @object2b,
75
+ @object2,
76
+ @object3].map(&:id)
77
+ end
78
+
79
+ it 'should have deprecated by_date_newest_first' do
80
+ assert_deprecated do
81
+ @class.by_date_newest_first
82
+ end
83
+ end
84
+ end
85
+
86
+ it "should have a newest first ordering that is the reverse of the oldest first ordering for identical objects" do
87
+ creation_time = 2.days.ago
88
+ publish_time = 1.days.ago
89
+ 5.times { Factory.create(@class.name.underscore.to_sym, :created_at => creation_time, :published_at => publish_time) }
90
+ @class.by_publication_date_newest_first.map(&:id).should == @class.by_publication_date_oldest_first.map(&:id).reverse
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,85 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require 'general_model_logic'
3
+
4
+ describe 'Using publishing logic on models with all fields' do
5
+ describe "published?" do
6
+ describe "with publishing enabled" do
7
+ it "should be published by default" do
8
+ Factory.create(:programme,
9
+ :publishing_enabled => true,
10
+ :published_at => nil,
11
+ :published_until => nil).should be_published
12
+ end
13
+
14
+ it "should not be published if the published_at datetime is in the future" do
15
+ Factory.create(:programme,
16
+ :publishing_enabled => true,
17
+ :published_at => 5.seconds.from_now,
18
+ :published_until => nil).should_not be_published
19
+ end
20
+
21
+ it "should not be published if the published_until datetime is in the past" do
22
+ Factory.create(:programme,
23
+ :publishing_enabled => true,
24
+ :published_at => nil,
25
+ :published_until => 5.seconds.ago).should_not be_published
26
+ end
27
+ end
28
+ describe "with publishing disabled" do
29
+ it "should not be published" do
30
+ Factory.create(:programme,
31
+ :publishing_enabled => false,
32
+ :published_at => 1.days.ago,
33
+ :published_until => 10.days.from_now).should_not be_published
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "published named scope" do
39
+ it "should include published objects" do
40
+ programme = Factory.create(:programme, :publishing_enabled => true)
41
+ Programme.published.should == [programme]
42
+ end
43
+
44
+ it "should not include any unpublished objects" do
45
+ Factory.create(:programme, :publishing_enabled => false)
46
+ Programme.published.should be_empty
47
+ end
48
+
49
+ it "should not include objects with a published_until in the past" do
50
+ Factory.create(:programme,
51
+ :publishing_enabled => true,
52
+ :published_until => 5.seconds.ago)
53
+ Programme.published.should be_empty
54
+ end
55
+
56
+ it "should not include objects with a published_at in the future" do
57
+ Factory.create(:programme,
58
+ :publishing_enabled => true,
59
+ :published_at => 5.seconds.from_now)
60
+ Programme.published.should be_empty
61
+ end
62
+
63
+ it "should get a new Time.now for each invocation of the named scope" do
64
+ mock_now = mock('now', :utc => 20.days.from_now, :to_f => 0)
65
+ Time.stub(:now).and_return mock_now
66
+ Programme.published
67
+ end
68
+
69
+ it "should use the utc of the current time" do
70
+ # Make sure utc is used, which is hard to test as a behaviour
71
+ mock_now = mock('now')
72
+ Time.stub(:now).and_return mock_now
73
+ mock_now.should_receive(:utc).twice
74
+ Programme.published
75
+ end
76
+ end
77
+
78
+ describe 'generally' do
79
+ before do
80
+ @class = Programme
81
+ end
82
+
83
+ it_should_behave_like 'a model with publish logic'
84
+ end
85
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require 'general_model_logic'
3
+
4
+ describe 'Using publishing logic on models with no published until field' do
5
+ describe "published?" do
6
+ describe "with publishing enabled" do
7
+ it "should be published by default" do
8
+ Factory.create(:article,
9
+ :publishing_enabled => true,
10
+ :published_at => nil).should be_published
11
+ end
12
+
13
+ it "should not be published if the published_at datetime is in the future" do
14
+ Factory.create(:article,
15
+ :publishing_enabled => true,
16
+ :published_at => 5.seconds.from_now).should_not be_published
17
+ end
18
+ end
19
+ describe "with publishing disabled" do
20
+ it "should not be published" do
21
+ Factory.create(:article,
22
+ :publishing_enabled => false,
23
+ :published_at => 1.days.ago).should_not be_published
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "published named scope" do
29
+ it "should include published objects" do
30
+ article = Factory.create(:article, :publishing_enabled => true)
31
+ Article.published.should == [article]
32
+ end
33
+
34
+ it "should not include any unpublished objects" do
35
+ Factory.create(:article, :publishing_enabled => false)
36
+ Article.published.should be_empty
37
+ end
38
+
39
+ it "should not include objects with a published_at in the future" do
40
+ Factory.create(:article,
41
+ :publishing_enabled => true,
42
+ :published_at => 5.seconds.from_now)
43
+ Article.published.should be_empty
44
+ end
45
+
46
+ it "should get a new Time.now for each invocation of the named scope" do
47
+ mock_now = mock('now', :utc => 20.days.from_now, :to_f => 0)
48
+ Time.stub(:now).and_return mock_now
49
+ Article.published
50
+ end
51
+
52
+ it "should use the utc of the current time" do
53
+ # Make sure utc is used, which is hard to test as a behaviour
54
+ mock_now = mock('now')
55
+ Time.stub(:now).and_return mock_now
56
+ mock_now.should_receive(:utc).once
57
+ Article.published
58
+ end
59
+ end
60
+
61
+ describe 'generally' do
62
+ before do
63
+ @class = Article
64
+ end
65
+
66
+ it_should_behave_like 'a model with publish logic'
67
+ end
68
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,18 +1,55 @@
1
- # $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- # $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
- ENV["RAILS_ENV"] ||= "test"
4
- require File.expand_path(File.join(File.dirname(__FILE__), "../../../../config/environment"))
5
- require 'spec/rails'
1
+ require 'rubygems'
2
+ gem 'rspec'
3
+ gem 'rspec-rails'
4
+ gem 'factory_girl'
5
+ gem 'activesupport'
6
+ gem 'activerecord'
7
+ gem 'database_cleaner'
6
8
 
7
9
  require 'factory_girl'
10
+ require 'active_support'
11
+ require 'active_record'
12
+
13
+ # We don't need all of spec/rails - just the bits that're to do with ActiveRecord
14
+
15
+ require 'active_support/test_case'
16
+ require 'active_record/fixtures' if defined?(ActiveRecord::Base)
17
+
18
+ require 'spec/test/unit'
19
+
20
+ require "spec/rails/example/model_example_group"
21
+ require 'spec/rails/extensions/spec/matchers/have'
22
+
23
+ require 'spec/rails/matchers/ar_be_valid'
24
+ require 'spec/rails/matchers/change'
25
+
26
+ require 'spec/rails/mocks'
27
+
28
+ require 'spec/rails/extensions/active_support/test_case'
29
+ require 'spec/rails/extensions/active_record/base'
30
+
31
+ require 'spec/rails/interop/testcase'
32
+
33
+ Spec::Example::ExampleGroupFactory.default(ActiveSupport::TestCase)
34
+
35
+ require 'publishing_logic'
36
+
37
+ require 'logger'
38
+ ActiveRecord::Base.logger = Logger.new("test.log")
39
+
40
+ # Time zone setup Publishing Logic assumes that you've properly set up your timezones.
41
+ Time.zone_default = Time.send(:get_zone, 'UTC')
42
+ ActiveRecord::Base.time_zone_aware_attributes = true
43
+ ActiveRecord::Base.default_timezone = :utc
44
+
45
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
8
46
 
9
47
  # require 'publishing_logic'
10
48
  # require 'spec'
11
49
  # require 'spec/autorun'
12
50
 
13
- class Programme < ActiveRecord::Base
14
- end
51
+ require 'database_cleaner'
52
+ DatabaseCleaner.strategy = :truncation
15
53
 
16
54
  Spec::Runner.configure do |config|
17
-
18
55
  end
@@ -0,0 +1,14 @@
1
+ Spec::Runner.configure do |config|
2
+ config.before(:suite) do
3
+ DatabaseCleaner.strategy = :transaction
4
+ DatabaseCleaner.clean_with(:truncation)
5
+ end
6
+
7
+ config.before(:each) do
8
+ DatabaseCleaner.start
9
+ end
10
+
11
+ config.after(:each) do
12
+ DatabaseCleaner.clean
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ ActiveRecord::Base.establish_connection(
2
+ :adapter => "sqlite3",
3
+ :database => "#{File.join(File.dirname(__FILE__),'test_publishing_logic.db')}"
4
+ )
@@ -0,0 +1,56 @@
1
+ module PublishingLogic
2
+ module Migrations
3
+ class AddProgrammes < ActiveRecord::Migration
4
+ def self.up
5
+ create_table :programmes do |t|
6
+ t.boolean :publishing_enabled
7
+ t.datetime :published_at
8
+ t.datetime :published_until
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :programmes, [:published_at, :publishing_enabled, :published_until], :name => 'index_programmes_on_publishing_logic_fields'
13
+ end
14
+
15
+ def self.down
16
+ remove_index :programmes, :name => 'index_programmes_on_publishing_logic_fields'
17
+ end
18
+ end
19
+
20
+ class AddArticles < ActiveRecord::Migration
21
+ def self.up
22
+ create_table :articles do |t|
23
+ t.boolean :publishing_enabled
24
+ t.datetime :published_at
25
+ t.timestamps
26
+ end
27
+
28
+ add_index :programmes, [:published_at, :publishing_enabled], :name => 'index_articles_on_publishing_logic_fields'
29
+ end
30
+
31
+ def self.down
32
+ remove_index :articles, :name => 'index_articles_on_publishing_logic_fields'
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ if ActiveRecord::Migrator.current_version != 2
39
+ migrator = ActiveRecord::Migrator.new(:up, '', 2)
40
+ migrator.instance_eval {
41
+ migration_1 = ActiveRecord::MigrationProxy.new
42
+ migration_1.instance_eval {
43
+ @name = 'add_programmes'
44
+ @version = 1
45
+ @migration = PublishingLogic::Migrations::AddProgrammes
46
+ }
47
+ migration_2 = ActiveRecord::MigrationProxy.new
48
+ migration_2.instance_eval {
49
+ @name = 'add_articles'
50
+ @version = 2
51
+ @migration = PublishingLogic::Migrations::AddArticles
52
+ }
53
+ @migrations = [ migration_1, migration_2 ]
54
+ }
55
+ migrator.migrate
56
+ end
@@ -0,0 +1,10 @@
1
+ Factory.define :programme do |p|
2
+ p.publishing_enabled { true }
3
+ p.published_at { Date.yesterday }
4
+ p.published_until { Date.tomorrow }
5
+ end
6
+
7
+ Factory.define :article do |p|
8
+ p.publishing_enabled { true }
9
+ p.published_at { Date.yesterday }
10
+ end
@@ -0,0 +1,2 @@
1
+ require 'logger'
2
+ ActiveRecord::Base.logger = Logger.new("test.log")
@@ -0,0 +1,3 @@
1
+ class Article < ActiveRecord::Base
2
+ include PublishingLogic::ModelLogic
3
+ end
@@ -0,0 +1,3 @@
1
+ class Programme < ActiveRecord::Base
2
+ include PublishingLogic::ModelLogic
3
+ end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: publishing_logic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Unboxed Consulting
@@ -9,29 +15,119 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-01-17 00:00:00 +00:00
18
+ date: 2010-08-20 00:00:00 +01:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: rspec
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 1
32
+ - 2
33
+ - 9
23
34
  version: 1.2.9
24
- version:
35
+ type: :development
36
+ version_requirements: *id001
25
37
  - !ruby/object:Gem::Dependency
26
38
  name: cucumber
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
30
42
  requirements:
31
43
  - - ">="
32
44
  - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
33
48
  version: "0"
34
- version:
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: rspec-rails
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 27
60
+ segments:
61
+ - 1
62
+ - 3
63
+ - 0
64
+ version: 1.3.0
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: factory_girl
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 31
76
+ segments:
77
+ - 1
78
+ - 2
79
+ - 0
80
+ version: 1.2.0
81
+ type: :development
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 2
94
+ - 3
95
+ - 0
96
+ version: 2.3.0
97
+ type: :development
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ name: activerecord
101
+ prerelease: false
102
+ requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 2
110
+ - 3
111
+ - 0
112
+ version: 2.3.0
113
+ type: :development
114
+ version_requirements: *id006
115
+ - !ruby/object:Gem::Dependency
116
+ name: database_cleaner
117
+ prerelease: false
118
+ requirement: &id007 !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ hash: 11
124
+ segments:
125
+ - 0
126
+ - 5
127
+ - 0
128
+ version: 0.5.0
129
+ type: :development
130
+ version_requirements: *id007
35
131
  description: Publishing logic for ActiveRecord models
36
132
  email: enquiries@unboxedconsulting.com
37
133
  executables: []
@@ -49,19 +145,24 @@ files:
49
145
  - README.rdoc
50
146
  - Rakefile
51
147
  - VERSION
52
- - features/publishing_logic.feature
53
- - features/step_definitions/publishing_logic_steps.rb
54
- - features/support/env.rb
55
148
  - lib/model_logic.rb
56
149
  - lib/publishing_logic.rb
57
150
  - rails_generators/publishing_logic_fields/USAGE
58
151
  - rails_generators/publishing_logic_fields/publishing_logic_fields_generator.rb
59
152
  - rails_generators/publishing_logic_fields/templates/app/views/publishing_logic_fields.html.erb
60
153
  - rails_generators/publishing_logic_fields/templates/db/migrate/add_publishing_logic_fields.rb.erb
61
- - spec/lib/model_logic_spec.rb
62
- - spec/publishing_logic_spec.rb
154
+ - spec/general_model_logic.rb
155
+ - spec/models_with_all_fields_spec.rb
156
+ - spec/models_with_no_published_until_field_spec.rb
63
157
  - spec/spec.opts
64
158
  - spec/spec_helper.rb
159
+ - spec/support/database_cleanliness.rb
160
+ - spec/support/database_connection.rb
161
+ - spec/support/database_migrations.rb
162
+ - spec/support/factories.rb
163
+ - spec/support/logging.rb
164
+ - spec/support/models/article.rb
165
+ - spec/support/models/programme.rb
65
166
  has_rdoc: true
66
167
  homepage: http://github.com/unboxed/publishing_logic
67
168
  licenses: []
@@ -72,25 +173,39 @@ rdoc_options:
72
173
  require_paths:
73
174
  - lib
74
175
  required_ruby_version: !ruby/object:Gem::Requirement
176
+ none: false
75
177
  requirements:
76
178
  - - ">="
77
179
  - !ruby/object:Gem::Version
180
+ hash: 3
181
+ segments:
182
+ - 0
78
183
  version: "0"
79
- version:
80
184
  required_rubygems_version: !ruby/object:Gem::Requirement
185
+ none: false
81
186
  requirements:
82
187
  - - ">="
83
188
  - !ruby/object:Gem::Version
189
+ hash: 3
190
+ segments:
191
+ - 0
84
192
  version: "0"
85
- version:
86
193
  requirements: []
87
194
 
88
195
  rubyforge_project:
89
- rubygems_version: 1.3.5
196
+ rubygems_version: 1.3.7
90
197
  signing_key:
91
198
  specification_version: 3
92
199
  summary: Publishing logic for ActiveRecord models
93
200
  test_files:
94
- - spec/lib/model_logic_spec.rb
95
- - spec/publishing_logic_spec.rb
201
+ - spec/general_model_logic.rb
202
+ - spec/models_with_all_fields_spec.rb
203
+ - spec/models_with_no_published_until_field_spec.rb
96
204
  - spec/spec_helper.rb
205
+ - spec/support/database_cleanliness.rb
206
+ - spec/support/database_connection.rb
207
+ - spec/support/database_migrations.rb
208
+ - spec/support/factories.rb
209
+ - spec/support/logging.rb
210
+ - spec/support/models/article.rb
211
+ - spec/support/models/programme.rb
@@ -1,9 +0,0 @@
1
- Feature: something something
2
- In order to something something
3
- A user something something
4
- something something something
5
-
6
- Scenario: something something
7
- Given inspiration
8
- When I create a sweet new gem
9
- Then everyone should see how awesome I am
File without changes
@@ -1,4 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
- require 'publishing_logic'
3
-
4
- require 'spec/expectations'
@@ -1,158 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
- require File.expand_path(File.join(File.dirname(__FILE__), "../../../../../spec/factories"))
3
- require 'model_logic'
4
-
5
- describe PublishingLogic::ModelLogic do
6
- def create_objects_with_different_published_at_dates
7
- @object2 = Factory.create(:programme, :publishing_enabled => true, :published_at => 2.days.ago)
8
- @object1 = Factory.create(:programme, :publishing_enabled => true, :published_at => 1.days.ago)
9
- @object3 = Factory.create(:programme, :publishing_enabled => true, :published_at => 3.days.ago)
10
- end
11
-
12
- describe "published?" do
13
- describe "with publishing enabled" do
14
- it "should be published by default" do
15
- Factory.create(:programme,
16
- :publishing_enabled => true,
17
- :published_at => nil,
18
- :published_until => nil).should be_published
19
- end
20
-
21
- it "should not be published if the published_at datetime is in the future" do
22
- Factory.create(:programme,
23
- :publishing_enabled => true,
24
- :published_at => 5.seconds.from_now,
25
- :published_until => nil).should_not be_published
26
- end
27
-
28
- it "should not be published if the published_until datetime is in the past" do
29
- Factory.create(:programme,
30
- :publishing_enabled => true,
31
- :published_at => nil,
32
- :published_until => 5.seconds.ago).should_not be_published
33
- end
34
- end
35
- describe "with publishing disabled" do
36
- it "should not be published" do
37
- Factory.create(:programme,
38
- :publishing_enabled => false,
39
- :published_at => 1.days.ago,
40
- :published_until => 10.days.from_now).should_not be_published
41
- end
42
- end
43
- end
44
-
45
- describe "published named scope" do
46
- it "should include published objects" do
47
- programme = Factory.create(:programme, :publishing_enabled => true)
48
- Programme.published.should == [programme]
49
- end
50
-
51
- it "should not include any unpublished objects" do
52
- Factory.create(:programme, :publishing_enabled => false)
53
- Programme.published.should be_empty
54
- end
55
-
56
- # it "should not expose a published episode published an hour ago" do
57
- # article = Factory.create(:episode, :is_hidden => false, :published_at => 1.hour.from_now, :published_until => nil)
58
- # Episode.published.should == []
59
- # end
60
-
61
- it "should not include objects with a published_until in the past" do
62
- Factory.create(:programme,
63
- :publishing_enabled => true,
64
- :published_until => 5.seconds.ago)
65
- Programme.published.should be_empty
66
- end
67
-
68
- it "should not include objects with a published_at in the future" do
69
- Factory.create(:programme,
70
- :publishing_enabled => true,
71
- :published_at => 5.seconds.from_now)
72
- Programme.published.should be_empty
73
- end
74
-
75
- it "should get a new Time.now for each invocation of the named scope" do
76
- item = Factory.create(:programme,
77
- :publishing_enabled => true,
78
- :published_until => 10.days.from_now)
79
- mock_now = mock('now', :utc => 20.days.from_now, :to_f => 0)
80
- Time.stub(:now).and_return mock_now
81
- Programme.published.should be_empty
82
- end
83
-
84
- it "should use the utc of the current time" do
85
- # Make sure utc is used, which is hard to test as a behaviour
86
- mock_now = mock('now')
87
- Time.stub(:now).and_return mock_now
88
- mock_now.should_receive(:utc).twice
89
- Programme.published
90
- end
91
-
92
- describe "newest" do
93
- before do
94
- create_objects_with_different_published_at_dates
95
- end
96
-
97
- it "should be the most recently published object" do
98
- Programme.published.newest.should == @object1
99
- end
100
- end
101
- describe "oldest" do
102
- it "should be the object published the longest ago" do
103
- Programme.published.oldest.should == @object3
104
- end
105
- end
106
- end
107
-
108
- describe "ordering by published_at" do
109
- describe "by date oldest first" do
110
- it "should return the items, oldest first" do
111
- create_objects_with_different_published_at_dates
112
- Programme.by_date_oldest_first.map(&:id).should == [@object3,
113
- @object2,
114
- @object1].map(&:id)
115
- end
116
-
117
- it "should order by created_at date if published_ats are equal" do
118
- create_objects_with_different_published_at_dates
119
- @object2b = Factory.create(:programme,
120
- :publishing_enabled => true,
121
- :published_at => @object2.published_at,
122
- :created_at => 3.days.ago)
123
- Programme.by_date_oldest_first.map(&:id).should == [@object3,
124
- @object2b,
125
- @object2,
126
- @object1].map(&:id)
127
- end
128
- end
129
-
130
- describe "by date newest first" do
131
- it "should return the items, oldest first" do
132
- create_objects_with_different_published_at_dates
133
- Programme.by_date_newest_first.map(&:id).should == [@object1,
134
- @object2,
135
- @object3].map(&:id)
136
- end
137
-
138
- it "should order by created_at date if published_ats are equal" do
139
- create_objects_with_different_published_at_dates
140
- @object2b = Factory.create(:programme,
141
- :publishing_enabled => true,
142
- :published_at => @object2.published_at,
143
- :created_at => 3.days.from_now)
144
- Programme.by_date_newest_first.map(&:id).should == [@object1,
145
- @object2b,
146
- @object2,
147
- @object3].map(&:id)
148
- end
149
- end
150
-
151
- it "should have a newest first ordering that is the reverse of the oldest first ordering for identical objects" do
152
- creation_time = 2.days.ago
153
- publish_time = 1.days.ago
154
- 5.times { Factory.create(:programme, :created_at => creation_time, :published_at => publish_time) }
155
- Programme.by_date_newest_first.map(&:id).should == Programme.by_date_oldest_first.map(&:id).reverse
156
- end
157
- end
158
- end
@@ -1,4 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "PublishingLogic" do
4
- end