publishing_logic 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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