has_publishing 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/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/has_publishing_test.db
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in has_publishing.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 3months
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # HasPublishing
2
+
3
+ Mark models as `has_publishing` to publish, draft and embargo models. Easy peasy!
4
+
5
+ ## Features
6
+
7
+ * `published`, `draft`, `embargoed` scopes for easy filtering/finding
8
+ * Rails environment-based default scoping: if your site is using `production`, draft/embargoed records will still be found - if you use `RAILS_ENV=production_published`, though, only published records will be found.
9
+ * In use in production on multiple sites
10
+ * Covered by automated tests
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'has_publishing'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install has_publishing
25
+
26
+ ## Usage
27
+
28
+ Simply add `has_publishing` to the model of your choice, and then generate the publishing attributes for your model:
29
+
30
+ ``` bash
31
+ bundle exec rails generate migration [YOUR MODEL NAME] embargoed_until:datetime published_at:datetime published_id:integer kind:string
32
+ ```
33
+
34
+ …and then of course run `rake db:migrate`
35
+
36
+ (If anyone would like to add a generator to automate this process, it would be very much appreciated)
37
+
38
+ ## A note on publishing
39
+
40
+ Publishing is typically used in an environment where there may be two installations of the Rails application sharing a common database. This at least is the set up that `has_publishing` is designed to operate in - something like the following:
41
+
42
+
43
+ ```
44
+ |-- Admin RAILS_ENV=production --| >>>>> SharedDatabase <<<<<< |-- Published Site RAILS_ENV=production_published --|
45
+ ```
46
+
47
+ Because of this, the gem applies a default_scope to all instances of this model to either:
48
+
49
+ * Only return published records if `Rails.env` matches `HasPublishing.config.published_rails_environment`
50
+ * Only return draft records otherwise
51
+
52
+ This prevents 'duplicate' records from appearing for the user (since each 'record' has two representations - 'draft' and 'published/withdrawn')
53
+
54
+ ### So:
55
+
56
+ 1. If you would prefer that this default scope **NOT** be applied, then simply set `HasPublishing.config.scope_records` to `false`.
57
+ 2. If you want the default scope to apply properly, ensure that you set the Rails environment of your **published** application in `HasPublishing.config.published_rails_environment`.
58
+
59
+
60
+
61
+ ## Contributing
62
+
63
+ 1. Fork it
64
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
65
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
66
+ 4. Push to the branch (`git push origin my-new-feature`)
67
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'has_publishing/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "has_publishing"
8
+ gem.version = HasPublishing::VERSION
9
+ gem.authors = ["Josh McArthur @ 3months"]
10
+ gem.email = ["joshua.mcarthur@gmail.com"]
11
+ gem.description = %q{Add ability to draft/publish/withdraw/embargo models}
12
+ gem.summary = %q{Add publishing to your ActiveRecord models}
13
+ gem.homepage = "https://github.com/3months/has_publishing"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "activerecord"
21
+ gem.add_dependency "activesupport"
22
+ gem.add_development_dependency "rspec-rails"
23
+ gem.add_development_dependency "sqlite3"
24
+ end
@@ -0,0 +1,18 @@
1
+ module HasPublishing
2
+ module ClassMethods
3
+ # This default scope allows published and draft viewing modes to share the
4
+ # same code. This is good. However if you need to access the other, draft
5
+ # from published or published from draft e.g from admin for editing, then
6
+ # you must explicitly use .unscoped to remove the default scope.
7
+
8
+ def default_scope
9
+ return scoped if HasPublishing.config.scope_records == false
10
+
11
+ if Rails.env == (HasPublishing.config.published_rails_environment)
12
+ published
13
+ else
14
+ draft
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module HasPublishing
2
+ include ActiveSupport::Configurable
3
+
4
+ # Set some default config
5
+ self.config.scope_records = true
6
+ self.config.published_rails_environment = "production"
7
+ end
@@ -0,0 +1,28 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class HasPublishing::Generators::PublishingGenerator < ::Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+
7
+ def self.source_root
8
+ @source_root ||= File.join(File.dirname(__FILE__), 'templates')
9
+ end
10
+
11
+ def self.next_migration_number(dirname)
12
+ if ActiveRecord::Base.timestamped_migrations
13
+ Time.new.utc.strftime("%Y%m%d%H%M%S")
14
+ else
15
+ "%.3d" % (current_migration_number(dirname) + 1)
16
+ end
17
+ end
18
+
19
+ def create_migration_file
20
+ set_local_assigns!
21
+ validate_file_name!
22
+ migration_template 'migration.rb', "db/migrate/publishing_fields_for_#{@table_name}.rb"
23
+ end
24
+
25
+ def set_local_assigns!
26
+ @table_name = file_name.pluralize
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ class PublishingFieldsFor<%= @table_name %> < ActiveRecord::Migration
2
+ def self.change
3
+ change_table <%= @table_name %> do |t|
4
+ t.datetime :published_at
5
+ t.datetime :embargoed_until
6
+ t.string :kind, :null => false, :index => true
7
+ t.boolean :dirty
8
+
9
+ # These should already be present
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,72 @@
1
+ module HasPublishing
2
+ module InstanceMethods
3
+
4
+
5
+ # Publishing "states"
6
+ # Draft = draft only (no published version, i.e new)
7
+ # Dirty = published + draft dirty (this is a kind of Draft state,
8
+ # has been published but draft has been edited since)
9
+ # Published = published + draft NOT dirty
10
+ # Under imbargo = published but future dated (embargo_until field)
11
+
12
+
13
+ def publish!(extra_attrs = {})
14
+ self.save! if self.new_record?
15
+ self.class.unscoped {
16
+ return false unless draft?
17
+ if published.nil? # first time publishing
18
+ published_obj = self.class.create!(attributes.merge(:kind => 'published', :published_at => Time.zone.now, :dirty => nil).merge(extra_attrs))
19
+ self.published_id = published_obj.id
20
+ else
21
+ published.update_attributes!(attributes.merge(:kind => 'published', :published_id => nil, :published_at => Time.zone.now, :dirty => nil).merge(extra_attrs))
22
+ end
23
+ self.class.record_timestamps = false # want same updated_at
24
+ self.save! # make sure this model is in sync
25
+ update_attributes!(:published_at => published.published_at, :dirty => false, :updated_at => published.updated_at)
26
+ self.class.record_timestamps = true
27
+ return published
28
+ }
29
+ end
30
+
31
+ def withdraw!
32
+ self.class.unscoped {
33
+ return false unless draft? && ever_published?
34
+ self.class.record_timestamps = false # want same updated_at
35
+ published.update_attributes!(:kind => 'withdrawn') and update_attributes!(published.attributes.merge({:kind => 'draft', :published_id => published_id, :published_at => nil, :dirty => false}))
36
+ self.class.record_timestamps = true
37
+ return published
38
+ }
39
+ end
40
+
41
+ def draft?
42
+ kind == 'draft'
43
+ end
44
+
45
+ def published?
46
+ self.class.unscoped { (draft? && published && published.kind == 'published') || kind == 'published' }
47
+ end
48
+
49
+ def withdrawn?
50
+ self.class.unscoped { (draft? && published && published.kind == 'withdrawn') || kind == 'withdrawn' }
51
+ end
52
+
53
+ def ever_published?
54
+ published? || withdrawn?
55
+ end
56
+
57
+ def under_embargo?
58
+ published? && embargoed_until && embargoed_until > Time.zone.now
59
+ end
60
+
61
+ private
62
+
63
+ def set_dirty
64
+ self.class.unscoped { update_attributes(:dirty => true) if draft? && published && published.updated_at != updated_at && !dirty? && !withdrawn? }
65
+ end
66
+
67
+ def set_draft
68
+ self.kind = 'draft' if kind.nil?
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ module HasPublishing
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,30 @@
1
+ require 'has_publishing/version'
2
+ require 'has_publishing/class_methods'
3
+ require 'has_publishing/instance_methods'
4
+ require 'has_publishing/configuration'
5
+
6
+
7
+ class << ActiveRecord::Base
8
+ def has_publishing
9
+
10
+ # Include instance methods
11
+ include HasPublishing::InstanceMethods
12
+
13
+ # Include dynamic class methods
14
+ extend HasPublishing::ClassMethods
15
+
16
+
17
+ scope :published, lambda { where(:kind => "published").not_embargoed }
18
+ scope :draft, where(:kind => 'draft')
19
+
20
+ scope :embargoed, lambda { where("embargoed_until IS NOT NULL AND ? > embargoed_until", Time.zone.now.round) }
21
+ scope :not_embargoed, lambda { where("embargoed_until IS NULL OR embargoed_until < ?", Time.zone.now.round) }
22
+
23
+ before_create :set_draft
24
+ after_save :set_dirty
25
+
26
+ belongs_to :published, :class_name => self.name, :foreign_key => :published_id, :dependent => :destroy
27
+ has_one :draft, :class_name => self.name, :foreign_key => :published_id
28
+
29
+ end
30
+ end
@@ -0,0 +1,328 @@
1
+ require 'active_record'
2
+ require 'ostruct'
3
+ require 'has_publishing'
4
+
5
+
6
+ # This should be all of the rails we need
7
+ class Rails
8
+ @@env = "draft"
9
+ def self.env
10
+ @@env
11
+ end
12
+
13
+ def self.env=(env)
14
+ @@env = env
15
+ end
16
+ end
17
+
18
+ class Time
19
+ def self.zone
20
+ OpenStruct.new(:now => Time.now)
21
+ end
22
+ end
23
+
24
+ ActiveRecord::Base.establish_connection(
25
+ :adapter => 'sqlite3',
26
+ :database => File.join(File.dirname(__FILE__), 'has_publishing_test.db')
27
+ )
28
+
29
+
30
+ class CreateTestModels < ActiveRecord::Migration
31
+ def self.up
32
+ if ActiveRecord::Base.connection.table_exists? "test_models"
33
+ drop_table :test_models
34
+ end
35
+
36
+ create_table :test_models do |t|
37
+ t.datetime :published_at
38
+ t.datetime :embargoed_until
39
+ t.string :kind
40
+ t.boolean :dirty
41
+ t.references :published
42
+
43
+ t.timestamps
44
+ end
45
+ end
46
+
47
+ def self.down
48
+ drop_table :test_models
49
+ end
50
+ end
51
+
52
+ CreateTestModels.migrate(:up)
53
+
54
+ class TestModel < ActiveRecord::Base
55
+ has_publishing
56
+ end
57
+
58
+ describe "has_publishing" do
59
+
60
+ before do
61
+ TestModel.delete_all
62
+ end
63
+
64
+ subject do
65
+ TestModel.new
66
+ end
67
+
68
+ describe "default configuration" do
69
+ it { HasPublishing.config.scope_records.should be_true }
70
+ it { HasPublishing.config.published_rails_environment.should eq "production" }
71
+ end
72
+
73
+
74
+ describe "scopes" do
75
+
76
+ describe "default scope" do
77
+ context "scope_records is false" do
78
+ before do
79
+ HasPublishing.config.scope_records = false
80
+ end
81
+
82
+ it "should not append any conditions" do
83
+ TestModel.should_not_receive(:where)
84
+ TestModel.first
85
+ end
86
+ end
87
+
88
+ context "rails production is published" do
89
+ before do
90
+ HasPublishing.config.scope_records = true
91
+ HasPublishing.config.published_rails_environment = "production"
92
+ Rails.env = "production"
93
+ end
94
+
95
+ after do
96
+ HasPublishing.config.scope_records = false
97
+ end
98
+
99
+ it "should only return published records" do
100
+ TestModel.should_receive(:published).at_least(:once)
101
+ TestModel.first
102
+ end
103
+
104
+ it "should not return embargoed records" do
105
+ TestModel.should_receive(:not_embargoed)
106
+ TestModel.first
107
+ end
108
+ end
109
+ end
110
+
111
+ describe "draft" do
112
+ it "should include a draft record" do
113
+ subject.kind = 'draft'
114
+ subject.save
115
+
116
+ subject.class.draft.should include subject
117
+ end
118
+
119
+ it "should not include a published record" do
120
+ subject.kind = 'published'
121
+ subject.save
122
+
123
+ subject.class.draft.should_not include subject
124
+ end
125
+ end
126
+
127
+ describe "published" do
128
+ it "should include a published record" do
129
+ subject.kind = 'published'
130
+ subject.save!
131
+ subject.class.unscoped.published.should include subject
132
+ end
133
+
134
+ it "should not include a draft record" do
135
+ subject.kind = 'draft'
136
+ subject.save
137
+ subject.class.published.should_not include subject
138
+ end
139
+ end
140
+
141
+ describe "embargoed" do
142
+ it "should include an embargoed record" do
143
+ subject.embargoed_until = Time.now - 3600
144
+ subject.save
145
+
146
+ subject.class.embargoed.should include subject
147
+ end
148
+
149
+ it "should not include an embargoed record whose time has not passed" do
150
+ subject.embargoed_until = Time.now + 5.minutes
151
+ subject.save
152
+ subject.class.embargoed.should_not include subject
153
+ end
154
+ end
155
+
156
+ describe "non_embargoed" do
157
+ it "should include a non embargoed record" do
158
+ subject.save
159
+ subject.class.not_embargoed.should include subject
160
+ end
161
+
162
+ it "should include a non-expired embargoed record" do
163
+ subject.embargoed_until = Time.now - 3600
164
+ subject.save
165
+ subject.class.not_embargoed.should include subject
166
+ end
167
+
168
+ it "should not include an embargoed record" do
169
+ subject.embargoed_until = Time.now + 3600
170
+ subject.save
171
+ subject.class.not_embargoed.should_not include subject
172
+ end
173
+ end
174
+ end
175
+
176
+ describe "associations" do
177
+ it { subject.methods.should include :draft }
178
+ it { subject.methods.should include :published_id }
179
+ end
180
+
181
+ describe "callbacks" do
182
+ it "should set the default status to draft" do
183
+ subject.save
184
+ subject.kind.should eq "draft"
185
+ end
186
+
187
+ it "should not change the status if it is already set" do
188
+ subject.kind = "published"
189
+ subject.save
190
+ subject.kind.should_not eq "draft"
191
+ end
192
+
193
+ it "should set the record to dirty once it has been created and is already published" do
194
+ subject.kind = "draft"
195
+ subject.published = TestModel.new(:updated_at => Time.now)
196
+ subject.save
197
+ subject.dirty.should be_true
198
+ end
199
+ end
200
+
201
+ describe "instance methods" do
202
+ describe "publish!" do
203
+ before do
204
+ subject.kind = "draft"
205
+ subject.save
206
+ end
207
+
208
+ context "first time publishing" do
209
+ it "should create a published record" do
210
+ subject.class.should_receive(:create!).and_call_original
211
+ subject.publish!
212
+ end
213
+
214
+ it "should set the inverse record on the original" do
215
+ expect {
216
+ subject.publish!
217
+ }.to change(subject, :published).to(an_instance_of(TestModel))
218
+ end
219
+
220
+ it "should record the published date" do
221
+ expect {
222
+ subject.publish!
223
+ }.to change(subject, :published_at).to(an_instance_of(Time))
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "withdraw!" do
229
+ before do
230
+ subject.kind = 'draft'
231
+ subject.save
232
+ end
233
+
234
+ it "should not withdraw if the record is not published" do
235
+ subject.withdraw!.should be_false
236
+ end
237
+
238
+ it "should withdraw the published record" do
239
+ subject.publish!
240
+ subject.withdraw!
241
+ subject.withdrawn?.should be_true
242
+ end
243
+ end
244
+
245
+ describe "draft?" do
246
+ it { subject.kind = "draft"; subject.draft?.should be_true }
247
+ it { subject.kind = "published"; subject.draft?.should be_false }
248
+ end
249
+
250
+ describe "published?" do
251
+ context "record is draft, inverse is published" do
252
+ before do
253
+ subject.kind = 'draft'
254
+ subject.published = TestModel.new(:kind => "published")
255
+ end
256
+
257
+ it { subject.published?.should be_true }
258
+ end
259
+
260
+ context "record is published" do
261
+ it { subject.kind = "published"; subject.published?.should be_true }
262
+ it { subject.kind = "draft"; subject.published?.should be_false }
263
+ end
264
+ end
265
+
266
+ describe "ever_published?" do
267
+ before do
268
+ subject.save
269
+ end
270
+
271
+ context "record is published" do
272
+ before do
273
+ subject.publish!
274
+ end
275
+
276
+ it { subject.ever_published?.should be_true }
277
+ end
278
+
279
+ context "record is withdrawn" do
280
+ before do
281
+ subject.publish!
282
+ subject.withdraw!
283
+ end
284
+
285
+ it { subject.ever_published?.should be_true }
286
+ end
287
+
288
+ it { subject.ever_published?.should be_false }
289
+ end
290
+
291
+ describe "under_embargo?" do
292
+ before do
293
+ subject.publish!
294
+ end
295
+
296
+ context "record is published and embargo has finished" do
297
+ before do
298
+ subject.embargoed_until = Time.now + 5.minutes
299
+ subject.save
300
+ end
301
+
302
+ it { subject.under_embargo?.should be_true }
303
+ end
304
+
305
+ context "embargo is not present" do
306
+ it { subject.under_embargo?.should be_false }
307
+ end
308
+
309
+ it { subject.under_embargo?.should be_false }
310
+ end
311
+
312
+ describe "withdrawn?" do
313
+ context "record is draft, inverse is withdrawn" do
314
+ before do
315
+ subject.kind = 'draft'
316
+ subject.published = TestModel.new(:kind => "withdrawn")
317
+ end
318
+
319
+ it { subject.withdrawn?.should be_true }
320
+ end
321
+
322
+ context "record is withdrawn" do
323
+ it { subject.kind = "withdrawn"; subject.withdrawn?.should be_true }
324
+ it { subject.kind = "draft"; subject.withdrawn?.should be_false }
325
+ end
326
+ end
327
+ end
328
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_publishing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh McArthur @ 3months
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec-rails
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: sqlite3
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Add ability to draft/publish/withdraw/embargo models
79
+ email:
80
+ - joshua.mcarthur@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .rspec
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - has_publishing.gemspec
92
+ - lib/has_publishing.rb
93
+ - lib/has_publishing/class_methods.rb
94
+ - lib/has_publishing/configuration.rb
95
+ - lib/has_publishing/generators/publishing_generator.rb
96
+ - lib/has_publishing/generators/templates/migration.rb.erb
97
+ - lib/has_publishing/instance_methods.rb
98
+ - lib/has_publishing/version.rb
99
+ - spec/has_publishing_spec.rb
100
+ homepage: https://github.com/3months/has_publishing
101
+ licenses: []
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ segments:
113
+ - 0
114
+ hash: -2118166424192642894
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ segments:
122
+ - 0
123
+ hash: -2118166424192642894
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.24
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: Add publishing to your ActiveRecord models
130
+ test_files:
131
+ - spec/has_publishing_spec.rb