railsgarden-has_draft 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ * [0.1.0] Initial Version
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,18 @@
1
+ CHANGELOG
2
+ has_draft_plugin.sqlite3
3
+ init.rb
4
+ install.rb
5
+ lib/has_draft.rb
6
+ Manifest
7
+ MIT-LICENSE
8
+ Rakefile
9
+ README.rdoc
10
+ tasks/has_draft_tasks.rake
11
+ test/config/database.yml
12
+ test/fixtures/article_drafts.yml
13
+ test/fixtures/articles.yml
14
+ test/has_draft_test.rb
15
+ test/models/article.rb
16
+ test/schema.rb
17
+ test/test_helper.rb
18
+ uninstall.rb
data/README.rdoc ADDED
@@ -0,0 +1,158 @@
1
+ == Has Draft
2
+
3
+ Allows for multiple "drafts" of a model which can be useful when developing:
4
+ * Draft/Live Version of Pages, for examples
5
+ * A workflow system whereby a live copy may need to be active while a draft copy is
6
+ awaiting approval.
7
+
8
+ The semantics of this as well as most of the inspiration comes from version_fu,
9
+ an excellent plugin for a similar purpose of maintaining several "versions" of a model.
10
+
11
+ This was built to be able to be tacked on to existing models, so the data schema doesn't need to change
12
+ at all for the model this is applied to. As such, drafts are actually stored in a nearly-identical table
13
+ and there is a has_one relationship to this. This separation allows the base model to really be treated
14
+ just as before without having to apply conditions in queries to make sure you are really getting the
15
+ "live" (non-draft) copy: Page.all will still only return the non-draft pages. This separate table is backed by
16
+ a model created on the fly as a constant on the original model class. For example if a Page has_draft,
17
+ a Page::Draft class will exist as the model for the page_drafts table.
18
+
19
+ == Installation
20
+
21
+ # In environment.rb
22
+ config.gem 'railsgarden-has_draft', :lib => 'has_draft', :source => 'http://gems.github.com'
23
+
24
+ == Basic Example
25
+
26
+ ## First Migration (If Creating base model and drafts at the same time):
27
+ class InitialSchema < ActiveRecord::Migration
28
+
29
+ [:articles, :article_drafts].each do |table_name|
30
+ create_table table_name, :force => true do |t|
31
+ t.references :article if table_name == :article_drafts
32
+
33
+ t.string :title
34
+ t.text :summary
35
+ t.text :body
36
+ t.date :post_date
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+
43
+ ## Model Class
44
+ class Article < ActiveRecord::Base
45
+ has_draft
46
+ end
47
+
48
+ ## Exposed Class Methods & Scopes:
49
+ Article.draft_class
50
+ => Article::Draft
51
+ Article.with_draft.all
52
+ => (Articles that have an associated draft)
53
+ Article.without_draft.all
54
+ => (Articles with no associated draft)
55
+
56
+
57
+
58
+ ## Usage Examples:
59
+
60
+ article = Article.create(
61
+ :title => "My Title",
62
+ :summary => "Information here.",
63
+ :body => "Full body",
64
+ :post_date => Date.today
65
+ )
66
+
67
+ article.has_draft?
68
+ => false
69
+
70
+ article.instantiate_draft!
71
+
72
+ article.has_draft?
73
+ => true
74
+
75
+ article.draft
76
+ => Article::Draft Instance
77
+
78
+ article.draft.update_attributes(
79
+ :title => "New Title"
80
+ )
81
+
82
+ article.replace_with_draft!
83
+
84
+ article.title
85
+ => "New Title"
86
+
87
+ article.destroy_draft!
88
+
89
+ article.has_draft?
90
+ => false
91
+
92
+ == Custom Options
93
+
94
+ ## First Migration (If Creating base model and drafts at the same time):
95
+ class InitialSchema < ActiveRecord::Migration
96
+
97
+ [:articles, :article_copies].each do |table_name|
98
+ create_table table_name, :force => true do |t|
99
+ t.integer :news_article_id if table_name == :article_copies
100
+
101
+ t.string :title
102
+ t.text :summary
103
+ t.text :body
104
+ t.date :post_date
105
+ end
106
+ end
107
+
108
+ end
109
+
110
+ ## Model Class
111
+ class Article < ActiveRecord::Base
112
+ has_draft :class_name => 'Copy', :foreign_key => :news_article_id, :table_name => 'article_copies'
113
+ end
114
+
115
+ == Method Callbacks
116
+
117
+ There are three callbacks you can specify directly as methods:
118
+
119
+ class Article < ActiveRecord::Base
120
+ has_draft
121
+
122
+ def before_instantiate_draft
123
+ # Do Something
124
+ end
125
+
126
+ def before_replace_with_draft
127
+ # Do Something
128
+ end
129
+
130
+ def before_destroy_draft
131
+ # Do Something
132
+ end
133
+ end
134
+
135
+
136
+
137
+ == Extending the Draft Class
138
+
139
+ Because you don't directly define the draft class, you can specify a block of code to be run in its
140
+ context by passing a block to has_draft:
141
+
142
+ class Article < ActiveRecord::Base
143
+ belongs_to :user
144
+
145
+ has_draft do
146
+ belongs_to :last_updated_user
147
+
148
+ def approve!
149
+ self.approved_at = Time.now
150
+ self.save
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+
157
+
158
+ Copyright (c) 2008 Ben Hughes, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the has_draft plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the has_draft plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'HasDraft'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+
27
+ Echoe.new('has_draft', '0.1.0') do |p|
28
+ p.description = "Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table."
29
+ p.url = "http://github.com/railsgarden/has_draft"
30
+ p.author = "Ben Hughes"
31
+ p.email = "ben@railsgarden.com"
32
+ p.ignore_pattern = ["tmp/*", "script/*"]
33
+ p.development_dependencies = []
34
+ end
35
+
36
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
37
+
data/has_draft.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{has_draft}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ben Hughes"]
9
+ s.date = %q{2009-01-16}
10
+ s.description = %q{Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.}
11
+ s.email = %q{ben@railsgarden.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/has_draft.rb", "README.rdoc", "tasks/has_draft_tasks.rake"]
13
+ s.files = ["CHANGELOG", "has_draft_plugin.sqlite3", "init.rb", "install.rb", "lib/has_draft.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "tasks/has_draft_tasks.rake", "test/config/database.yml", "test/fixtures/article_drafts.yml", "test/fixtures/articles.yml", "test/has_draft_test.rb", "test/models/article.rb", "test/schema.rb", "test/test_helper.rb", "uninstall.rb", "has_draft.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/railsgarden/has_draft}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Has_draft", "--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{has_draft}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.}
21
+ s.test_files = ["test/has_draft_test.rb", "test/test_helper.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'has_draft'
2
+
3
+ ActiveRecord::Base.send(:include, Rubiety::HasDraft)
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
data/lib/has_draft.rb ADDED
@@ -0,0 +1,120 @@
1
+ module Rubiety
2
+ module HasDraft
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def has_draft(options = {}, &block)
9
+ return if self.included_modules.include?(HasDraft::InstanceMethods)
10
+ include HasDraft::InstanceMethods
11
+
12
+ cattr_accessor :draft_class_name, :draft_foreign_key, :draft_table_name, :draft_columns
13
+
14
+ self.draft_class_name = options[:class_name] || 'Draft'
15
+ self.draft_foreign_key = options[:foreign_key] || self.to_s.foreign_key
16
+ self.draft_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_drafts#{table_name_suffix}"
17
+
18
+ # Create Relationship to Draft Copy
19
+ class_eval do
20
+ has_one :draft, :class_name => "#{self.to_s}::#{draft_class_name}",
21
+ :foreign_key => draft_foreign_key,
22
+ :dependent => :destroy
23
+
24
+ named_scope :with_draft, :include => [:draft], :conditions => "#{draft_table_name}.id IS NOT NULL"
25
+ named_scope :without_draft, :include => [:draft], :conditions => "#{draft_table_name}.id IS NULL"
26
+ end
27
+
28
+ # Dynamically Create Model::Draft Class
29
+ const_set(draft_class_name, Class.new(ActiveRecord::Base))
30
+
31
+ draft_class.cattr_accessor :original_class
32
+ draft_class.original_class = self
33
+ draft_class.set_table_name(draft_table_name)
34
+
35
+ # Draft Parent Association
36
+ draft_class.belongs_to self.to_s.demodulize.underscore.to_sym, :class_name => "::#{self.to_s}", :foreign_key => draft_foreign_key
37
+
38
+ # Block extension
39
+ draft_class.class_eval(&block) if block_given?
40
+
41
+ # Finally setup which columns to draft
42
+ self.draft_columns = draft_class.new.attributes.keys - [draft_class.primary_key, draft_foreign_key, 'created_at', 'updated_at', inheritance_column]
43
+ end
44
+
45
+ def draft_class
46
+ const_get(draft_class_name)
47
+ end
48
+ end
49
+
50
+ module InstanceMethods
51
+ def has_draft?
52
+ !self.draft.nil?
53
+ end
54
+
55
+ def save_to_draft(perform_validation = true)
56
+ return false if perform_validation and !self.valid?
57
+
58
+ instantiate_draft! unless has_draft?
59
+ copy_attributes_to_draft
60
+
61
+ self.draft.save(perform_validation)
62
+ self.reload
63
+ end
64
+
65
+ def instantiate_draft
66
+ self.draft = self.build_draft
67
+
68
+ copy_attributes_to_draft
69
+ before_instantiate_draft
70
+
71
+ self.draft
72
+ end
73
+
74
+ def instantiate_draft!
75
+ returning instantiate_draft do |draft|
76
+ draft.save unless self.new_record?
77
+ end
78
+ end
79
+
80
+ def copy_attributes_to_draft
81
+ self.class.draft_columns.each do |attribute|
82
+ self.draft.send("#{attribute}=", send(attribute))
83
+ end
84
+ self
85
+ end
86
+
87
+ def copy_attributes_from_draft
88
+ self.class.draft_columns.each do |attribute|
89
+ self.send("#{attribute}=", self.draft.send(attribute))
90
+ end
91
+ self
92
+ end
93
+
94
+ def before_instantiate_draft
95
+ end
96
+
97
+ def replace_with_draft!
98
+ copy_attributes_from_draft
99
+
100
+ before_replace_with_draft
101
+
102
+ self.save unless self.new_record?
103
+ self
104
+ end
105
+
106
+ def before_replace_with_draft
107
+ end
108
+
109
+ def destroy_draft!
110
+ before_destroy_draft
111
+
112
+ self.draft.destroy if self.draft
113
+ self.draft(true)
114
+ end
115
+
116
+ def before_destroy_draft
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :has_draft do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: has_draft_plugin.sqlite
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: has_draft_plugin.sqlite3
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: has_draft_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: root
17
+ :password:
18
+ :database: has_draft_plugin_test
@@ -0,0 +1,12 @@
1
+ article_with_draft:
2
+ article_id: <%= Fixtures.identify('article_with_draft') %>
3
+ title: Article With Draft Changed
4
+ summary: >
5
+ Changed: Sed cursus cursus velit. Sed cursus cursus velit.
6
+ body: >
7
+ Changed: Nunc auctor bibendum eros. Maecenas porta accumsan mauris. Etiam enim enim, elementum sed, bibendum quis, rhoncus non,
8
+ metus. Fusce neque dolor, adipiscing sed, consectetuer et, lacinia sit amet, quam. Suspendisse wisi quam,
9
+ consectetuer in, blandit sed, suscipit eu, eros. Etiam ligula enim, tempor ut, blandit nec, mollis eu, lectus.
10
+ Nam cursus. Vivamus iaculis. Aenean risus purus, pharetra in, blandit quis, gravida a, turpis. Donec nisl.
11
+ Aenean eget mi. Fusce mattis est id diam. Phasellus faucibus interdum sapien. Duis quis nunc. Sed enim.
12
+ post_date: <%= Date.today.to_s(:db) %>
@@ -0,0 +1,23 @@
1
+ article_without_draft:
2
+ title: Article Without Draft
3
+ summary: >
4
+ Sed cursus cursus velit. Sed cursus cursus velit.
5
+ body: >
6
+ Nunc auctor bibendum eros. Maecenas porta accumsan mauris. Etiam enim enim, elementum sed, bibendum quis, rhoncus non,
7
+ metus. Fusce neque dolor, adipiscing sed, consectetuer et, lacinia sit amet, quam. Suspendisse wisi quam,
8
+ consectetuer in, blandit sed, suscipit eu, eros. Etiam ligula enim, tempor ut, blandit nec, mollis eu, lectus.
9
+ Nam cursus. Vivamus iaculis. Aenean risus purus, pharetra in, blandit quis, gravida a, turpis. Donec nisl.
10
+ Aenean eget mi. Fusce mattis est id diam. Phasellus faucibus interdum sapien. Duis quis nunc. Sed enim.
11
+ post_date: <%= Date.today.to_s(:db) %>
12
+
13
+ article_with_draft:
14
+ title: Article With Draft
15
+ summary: >
16
+ Sed cursus cursus velit. Sed cursus cursus velit.
17
+ body: >
18
+ Nunc auctor bibendum eros. Maecenas porta accumsan mauris. Etiam enim enim, elementum sed, bibendum quis, rhoncus non,
19
+ metus. Fusce neque dolor, adipiscing sed, consectetuer et, lacinia sit amet, quam. Suspendisse wisi quam,
20
+ consectetuer in, blandit sed, suscipit eu, eros. Etiam ligula enim, tempor ut, blandit nec, mollis eu, lectus.
21
+ Nam cursus. Vivamus iaculis. Aenean risus purus, pharetra in, blandit quis, gravida a, turpis. Donec nisl.
22
+ Aenean eget mi. Fusce mattis est id diam. Phasellus faucibus interdum sapien. Duis quis nunc. Sed enim.
23
+ post_date: <%= Date.today.to_s(:db) %>
@@ -0,0 +1,96 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+ require File.join(File.dirname(__FILE__), 'models/article')
3
+
4
+ class ArticleTest < Test::Unit::TestCase
5
+ fixtures :articles, :article_drafts
6
+ set_fixture_class :article_drafts => Article::Draft
7
+
8
+ context "Article model" do
9
+ should_have_one :draft
10
+ should_have_named_scope :with_draft
11
+ should_have_named_scope :without_draft
12
+
13
+ should_have_class_methods :draft_class_name, :draft_foreign_key, :draft_table_name
14
+
15
+ should "default class name to Draft" do
16
+ assert_equal "Draft", Article.draft_class_name
17
+ end
18
+
19
+ should "expose draft class constant" do
20
+ assert_equal Article::Draft, Article.draft_class
21
+ end
22
+
23
+ should "default foreign key to article_id" do
24
+ assert_equal "article_id", Article.draft_foreign_key
25
+ end
26
+
27
+ should "default table name to article_drafts" do
28
+ assert_equal "article_drafts", Article.draft_table_name
29
+ end
30
+
31
+ context "Draft model" do
32
+ should "have a be defined under Article" do
33
+ assert Article.constants.include?('Draft')
34
+ end
35
+
36
+ should "load" do
37
+ assert_nothing_raised do
38
+ Article::Draft
39
+ end
40
+ end
41
+
42
+ should "expose original class name of Article" do
43
+ assert_equal Article, Article::Draft.original_class
44
+ end
45
+ end
46
+ end
47
+
48
+ context "an article" do
49
+ setup { @article = articles(:article_without_draft) }
50
+
51
+ context "when instantiating a new draft" do
52
+ setup { @article.instantiate_draft! }
53
+
54
+ should "create draft" do
55
+ assert_not_nil @article.draft
56
+ assert !@article.draft.new_record?
57
+ end
58
+
59
+ should "copy draft fields" do
60
+ Article.draft_columns.each do |column|
61
+ assert_equal @article.send(column), @article.draft.send(column)
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when destroying an existing draft" do
67
+ setup do
68
+ @article = articles(:article_with_draft)
69
+ @article.destroy_draft!
70
+ end
71
+
72
+ should "destroy associated draft" do
73
+ assert_nil @article.draft
74
+ end
75
+ end
76
+
77
+ context "when replacing with draft" do
78
+ setup do
79
+ @article = articles(:article_with_draft)
80
+ @article.replace_with_draft!
81
+ end
82
+
83
+ should "still have draft" do
84
+ assert_not_nil @article.draft
85
+ end
86
+
87
+ should "now have the same field values as draft" do
88
+ Article.draft_columns.each do |column|
89
+ assert_equal @article.send(column), @article.draft.send(column)
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,3 @@
1
+ class Article < ActiveRecord::Base
2
+ has_draft
3
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,14 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+
3
+ [:articles, :article_drafts].each do |table_name|
4
+ create_table table_name, :force => true do |t|
5
+ t.references :article if table_name == :article_drafts
6
+
7
+ t.string :title
8
+ t.text :summary
9
+ t.text :body
10
+ t.date :post_date
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,24 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ require 'active_record/fixtures'
5
+ require 'shoulda/rails'
6
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/has_draft'))
7
+
8
+ config = YAML::load(IO.read(File.join(File.dirname(__FILE__), 'config', '/database.yml')))
9
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
10
+ ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']}
11
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
12
+
13
+ load(File.dirname(__FILE__) + "/schema.rb")
14
+
15
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
16
+ $:.unshift(Test::Unit::TestCase.fixture_path)
17
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
18
+
19
+ class Test::Unit::TestCase
20
+ self.use_transactional_fixtures = true
21
+ self.use_instantiated_fixtures = false
22
+ end
23
+
24
+ require File.expand_path(File.join(File.dirname(__FILE__), '../init'))
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: railsgarden-has_draft
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Hughes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-16 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.
17
+ email: ben@railsgarden.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - CHANGELOG
24
+ - lib/has_draft.rb
25
+ - README.rdoc
26
+ - tasks/has_draft_tasks.rake
27
+ files:
28
+ - CHANGELOG
29
+ - has_draft_plugin.sqlite3
30
+ - init.rb
31
+ - install.rb
32
+ - lib/has_draft.rb
33
+ - Manifest
34
+ - MIT-LICENSE
35
+ - Rakefile
36
+ - README.rdoc
37
+ - tasks/has_draft_tasks.rake
38
+ - test/config/database.yml
39
+ - test/fixtures/article_drafts.yml
40
+ - test/fixtures/articles.yml
41
+ - test/has_draft_test.rb
42
+ - test/models/article.rb
43
+ - test/schema.rb
44
+ - test/test_helper.rb
45
+ - uninstall.rb
46
+ - has_draft.gemspec
47
+ has_rdoc: true
48
+ homepage: http://github.com/railsgarden/has_draft
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --line-numbers
52
+ - --inline-source
53
+ - --title
54
+ - Has_draft
55
+ - --main
56
+ - README.rdoc
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "1.2"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project: has_draft
74
+ rubygems_version: 1.2.0
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.
78
+ test_files:
79
+ - test/has_draft_test.rb
80
+ - test/test_helper.rb