revisions 0.0.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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +103 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/revisions.rb +96 -0
- data/revisions.gemspec +58 -0
- data/test/helper.rb +29 -0
- data/test/models.rb +4 -0
- data/test/schema.rb +13 -0
- data/test/test_revisions.rb +203 -0
- metadata +88 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Rajkumar
|
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/README.rdoc
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
= revisions
|
2
|
+
|
3
|
+
Revisions provides a simple, wordpress-like, interface for tracking revisions to a model within a single table. It's a bit rudimentary now, but I hope to add to it as necessary.
|
4
|
+
|
5
|
+
The basics:
|
6
|
+
* Stores drafts, published items, and revisions
|
7
|
+
*
|
8
|
+
|
9
|
+
== INSTALLATION
|
10
|
+
|
11
|
+
sudo gem install revisions --source http://gemcutter.org
|
12
|
+
|
13
|
+
then add to environment.rb
|
14
|
+
|
15
|
+
config.gem 'revisions', :source => 'http://gemcutter.org'
|
16
|
+
|
17
|
+
|
18
|
+
== USAGE
|
19
|
+
|
20
|
+
The gem is a bit rigid at the moment, so you'll need to setup two columns for it to use:
|
21
|
+
|
22
|
+
t.string :status # draft, published, revision
|
23
|
+
t.integer :revision_of # Foreign Key that tracks what a model is revising.
|
24
|
+
|
25
|
+
You may also want to index these fields.
|
26
|
+
|
27
|
+
Once your models are setup, need to declare revisions within any model you intend to track. ie.
|
28
|
+
|
29
|
+
class Response < ActiveRecord::Base
|
30
|
+
has_revisions
|
31
|
+
end
|
32
|
+
|
33
|
+
You can also declare variables that you DON'T want to track (like a slug that has to be unique on the table, publication date, etc.)
|
34
|
+
|
35
|
+
class Response < ActiveRecord::Base
|
36
|
+
has_revisions :ignore => ['published_at', 'slug']
|
37
|
+
end
|
38
|
+
|
39
|
+
In addition to the variables you declare, revisions will ignore the status, id, revision_of, and created_at fields.
|
40
|
+
|
41
|
+
Now you're all set to save and apply revisions. Revisions exposes three methods: latest_revision, pending_revisions?, save_revision and apply_revision.
|
42
|
+
|
43
|
+
latest_revision:
|
44
|
+
* returns the latest revision
|
45
|
+
|
46
|
+
pending_revisions:
|
47
|
+
* returns true if there are revisions with a more recent updated_at than the model.
|
48
|
+
|
49
|
+
save_revision:
|
50
|
+
* If your model is a draft, it simply saves the model.
|
51
|
+
* If your model is published, it saves a revision (does not modify the core model)
|
52
|
+
* OG model doesn't change, so all associations are intact
|
53
|
+
* Behaves like standard ActiveRecord save (ie. returns true/false if it saves succesfully and creates an errors array if not)
|
54
|
+
* can be called with bang (save_revision!) to throw an exception if it doesn't save.
|
55
|
+
|
56
|
+
apply_revision
|
57
|
+
* If called without params, maps the latest revision onto the model, but DOES NOT SAVE.
|
58
|
+
* If called with a revision, maps that revision, but doesn't save
|
59
|
+
* if called with bang (apply_revision!), maps a revision AND saves
|
60
|
+
|
61
|
+
How about some examples.
|
62
|
+
|
63
|
+
Saving a Revision:
|
64
|
+
|
65
|
+
response = Response.create({:title => 'donkey', :status => 'published'})
|
66
|
+
response.title = 'monkey'
|
67
|
+
response.save_revision # => true
|
68
|
+
response.revisions.size # => 1
|
69
|
+
response.pending_revision? # => true
|
70
|
+
|
71
|
+
save_revision doesn't affect the original response
|
72
|
+
|
73
|
+
response.reload
|
74
|
+
revision = response.latest_revision # => new response object.
|
75
|
+
response.title # => 'donkey'
|
76
|
+
revision.title # => 'monkey'
|
77
|
+
|
78
|
+
apply_revision will affect the original response
|
79
|
+
|
80
|
+
response.apply_revision # => true
|
81
|
+
response.title # => 'monkey'
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
==Final Suggestion
|
86
|
+
|
87
|
+
Since revisions all live within the same table, you probably want to setup a default scope on your model so you don't access revisions directly.
|
88
|
+
|
89
|
+
default_scope :conditions => "status <> 'revision'"
|
90
|
+
|
91
|
+
|
92
|
+
== LIMITATIONS
|
93
|
+
|
94
|
+
There are a few things on the to-do list, among them:
|
95
|
+
|
96
|
+
* There's no way to prune revisions yet. But that's coming ASAP.
|
97
|
+
* Revisions assumes your model uses a standard rails Table Name (ie Response => Responses)
|
98
|
+
* Revisions requires the status and revision_of columns (for now)
|
99
|
+
|
100
|
+
|
101
|
+
==Author
|
102
|
+
|
103
|
+
Brian Hamman, hamman+github [ @ ] gmail.com
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "revisions"
|
8
|
+
gem.summary = %Q{A lightweight way to handle Wordpress-like revisions}
|
9
|
+
gem.description = %Q{Save and apply revisions to a model, while keeping track of old revisiions}
|
10
|
+
gem.email = "hamman@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/hamman/revisions"
|
12
|
+
gem.authors = ["Brian Hamman"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "revisions #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/lib/revisions.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
module Revisions
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
STATUSES = ['draft', 'published', 'revision']
|
5
|
+
|
6
|
+
def has_revisions opts={}
|
7
|
+
class_inheritable_accessor :unrevised_attributes
|
8
|
+
|
9
|
+
has_many :revisions,
|
10
|
+
:class_name => self.name,
|
11
|
+
:conditions => "status='revision'",
|
12
|
+
:foreign_key => 'revision_of'
|
13
|
+
|
14
|
+
include InstanceMethods
|
15
|
+
|
16
|
+
self.unrevised_attributes = opts[:ignore] || []
|
17
|
+
self.unrevised_attributes.concat ['revision_of', 'status', 'created_at']
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
module InstanceMethods
|
22
|
+
|
23
|
+
def self.included(klass)
|
24
|
+
klass.extend(ClassMethods)
|
25
|
+
end
|
26
|
+
|
27
|
+
def published?
|
28
|
+
status == 'published'
|
29
|
+
end
|
30
|
+
|
31
|
+
def revision?
|
32
|
+
status == 'revision'
|
33
|
+
end
|
34
|
+
|
35
|
+
def draft?
|
36
|
+
status == 'draft'
|
37
|
+
end
|
38
|
+
|
39
|
+
def save_revision
|
40
|
+
if self.published?
|
41
|
+
new_copy = self.clone
|
42
|
+
attributes_to_nil = {}
|
43
|
+
self.unrevised_attributes.each {|a| attributes_to_nil[a] = nil }
|
44
|
+
new_copy.attributes=attributes_to_nil
|
45
|
+
new_copy.created_at = new_copy.updated_at = Time.zone.now
|
46
|
+
new_copy.status = 'revision'
|
47
|
+
new_copy.revision_of = self.id
|
48
|
+
if new_copy.save
|
49
|
+
true
|
50
|
+
else
|
51
|
+
new_copy.errors.each {|attribute,message| self.errors.add(attribute,message)}
|
52
|
+
false
|
53
|
+
end
|
54
|
+
else
|
55
|
+
save
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def save_revision!
|
60
|
+
save_revision || raise(ActiveRecord::RecordNotSaved)
|
61
|
+
end
|
62
|
+
|
63
|
+
def latest_revision
|
64
|
+
revisions.last
|
65
|
+
end
|
66
|
+
|
67
|
+
def pending_revisions?
|
68
|
+
!latest_revision.nil? && latest_revision.updated_at > self.updated_at
|
69
|
+
end
|
70
|
+
|
71
|
+
# maps a revision's changes onto the main object
|
72
|
+
def apply_revision(revision=nil)
|
73
|
+
revision = latest_revision if revision.nil?
|
74
|
+
unless revision.nil?
|
75
|
+
revised_attributes = revision.attributes.reject {|k,v| self.unrevised_attributes.include?(k) || k == 'id'}
|
76
|
+
self.attributes=revised_attributes
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def apply_revision!(revision=nil)
|
83
|
+
if apply_revision(revision)
|
84
|
+
save!
|
85
|
+
else
|
86
|
+
raise RuntimeError.new("No revision to apply!")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
if defined?(ActiveRecord)
|
95
|
+
ActiveRecord::Base.instance_eval { extend Revisions::ClassMethods }
|
96
|
+
end
|
data/revisions.gemspec
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{revisions}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Brian Hamman"]
|
12
|
+
s.date = %q{2010-04-29}
|
13
|
+
s.description = %q{Save and apply revisions to a model, while keeping track of old revisiions}
|
14
|
+
s.email = %q{hamman@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/revisions.rb",
|
27
|
+
"revisions.gemspec",
|
28
|
+
"test/helper.rb",
|
29
|
+
"test/models.rb",
|
30
|
+
"test/schema.rb",
|
31
|
+
"test/test_revisions.rb"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/hamman/revisions}
|
34
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.6}
|
37
|
+
s.summary = %q{A lightweight way to handle Wordpress-like revisions}
|
38
|
+
s.test_files = [
|
39
|
+
"test/helper.rb",
|
40
|
+
"test/models.rb",
|
41
|
+
"test/schema.rb",
|
42
|
+
"test/test_revisions.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
50
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
class Test::Unit::TestCase
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
# You can use "rake test AR_VERSION=2.0.5" to test against 2.0.5, for example.
|
10
|
+
# The default is to use the latest installed ActiveRecord.
|
11
|
+
if ENV["AR_VERSION"]
|
12
|
+
gem 'activerecord', "#{ENV["AR_VERSION"]}"
|
13
|
+
gem 'activesupport', "#{ENV["AR_VERSION"]}"
|
14
|
+
gem 'iridesco-time-warp', :lib => 'time_warp', :source => "http://gems.github.com"
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'active_record'
|
18
|
+
require 'active_support'
|
19
|
+
require 'time_warp'
|
20
|
+
|
21
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
22
|
+
require 'revisions'
|
23
|
+
|
24
|
+
ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
|
25
|
+
silence_stream(STDOUT) do
|
26
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'models'
|
data/test/models.rb
ADDED
data/test/schema.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 1) do
|
2
|
+
create_table "responses", :force => true do |t|
|
3
|
+
t.text "body"
|
4
|
+
t.string "title"
|
5
|
+
t.string "slug"
|
6
|
+
t.string "intro"
|
7
|
+
t.datetime "published_at"
|
8
|
+
t.datetime "created_at"
|
9
|
+
t.datetime "updated_at"
|
10
|
+
t.string "status"
|
11
|
+
t.integer "revision_of"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestRevisions < Test::Unit::TestCase
|
4
|
+
|
5
|
+
Time.zone = 'Eastern Time (US & Canada)'
|
6
|
+
|
7
|
+
|
8
|
+
context "a response" do
|
9
|
+
|
10
|
+
setup do
|
11
|
+
@response = Response.create({
|
12
|
+
:title => "This is a post about Donkey",
|
13
|
+
:slug => "this-is-a-post-about-donkey",
|
14
|
+
:body => "This is the body of Donkey",
|
15
|
+
})
|
16
|
+
end
|
17
|
+
|
18
|
+
context "When saving with revisions" do
|
19
|
+
|
20
|
+
setup do
|
21
|
+
@response.status = 'published'
|
22
|
+
@response.intro = "donkey intro"
|
23
|
+
pretend_now_is(5.minutes.from_now) do
|
24
|
+
assert @response.save_revision
|
25
|
+
@revision = @response.latest_revision
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
should "just save to the same record when in draft mode" do
|
30
|
+
@response.revisions.delete_all
|
31
|
+
@response.status = 'draft'
|
32
|
+
assert @response.save_revision
|
33
|
+
assert_equal 0, @response.revisions.size
|
34
|
+
end
|
35
|
+
|
36
|
+
should "save a revision that copies all fields" do
|
37
|
+
assert_equal @revision.title, @response.title
|
38
|
+
assert_equal @revision.body, @response.body
|
39
|
+
end
|
40
|
+
|
41
|
+
should "set more updated timestamps" do
|
42
|
+
assert @revision.created_at > @response.created_at
|
43
|
+
assert @revision.updated_at > @response.updated_at
|
44
|
+
end
|
45
|
+
|
46
|
+
should "say it's a revision of the first guy" do
|
47
|
+
assert @revision.revision_of = @response.id
|
48
|
+
end
|
49
|
+
|
50
|
+
should "set the status to revision" do
|
51
|
+
assert_equal 'revision', @revision.status
|
52
|
+
end
|
53
|
+
|
54
|
+
should "copy attributes not yet saved to the DB" do
|
55
|
+
@response.reload
|
56
|
+
assert_equal "donkey intro", @revision.intro
|
57
|
+
assert_not_equal @revision.intro, @response.intro
|
58
|
+
end
|
59
|
+
|
60
|
+
should "not copy ignored attributes" do
|
61
|
+
assert_not_equal @revision.slug, @response.slug
|
62
|
+
end
|
63
|
+
|
64
|
+
should "return true when it saves" do
|
65
|
+
assert @response.save_revision
|
66
|
+
end
|
67
|
+
|
68
|
+
should "return false when it doesn't save" do
|
69
|
+
@response.title = nil
|
70
|
+
assert_equal false, @response.save_revision
|
71
|
+
end
|
72
|
+
|
73
|
+
should "attach errors to the base object if a revision save fails" do
|
74
|
+
@response.title = nil
|
75
|
+
@response.save_revision
|
76
|
+
assert_equal "can't be blank", @response.errors.on(:title)
|
77
|
+
end
|
78
|
+
|
79
|
+
should "return true when it saves!" do
|
80
|
+
assert @response.save_revision!
|
81
|
+
end
|
82
|
+
|
83
|
+
should "raise an exception when it saves! and has bad data" do
|
84
|
+
assert_raises ActiveRecord::RecordNotSaved do
|
85
|
+
@response.title = nil
|
86
|
+
@response.save_revision!
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when accessing revisions" do
|
93
|
+
|
94
|
+
should "return null if there aren't revisions" do
|
95
|
+
assert_equal nil, @response.latest_revision
|
96
|
+
end
|
97
|
+
|
98
|
+
should "show if there are no pending revisions if none exist" do
|
99
|
+
assert_equal false, @response.pending_revisions?
|
100
|
+
end
|
101
|
+
|
102
|
+
context "with a revision" do
|
103
|
+
setup do
|
104
|
+
@response.status = 'published'
|
105
|
+
pretend_now_is(5.minutes.from_now) do
|
106
|
+
@response.save_revision!
|
107
|
+
@response.save_revision!
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
should "return the revision if there is one" do
|
112
|
+
latest = Response.find(:first, :conditions => 'status=\'revision\'', :order => 'id DESC')
|
113
|
+
assert_equal latest.id, @response.latest_revision.id
|
114
|
+
end
|
115
|
+
|
116
|
+
should "say there are pending revisions if there are some" do
|
117
|
+
assert @response.pending_revisions?
|
118
|
+
end
|
119
|
+
|
120
|
+
should "say there aren't pending revisions if they are old" do
|
121
|
+
@response.updated_at = 2.days.from_now
|
122
|
+
assert_equal false, @response.pending_revisions?
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
context "when applying a revision" do
|
133
|
+
|
134
|
+
setup do
|
135
|
+
@response.update_attribute(:status, 'published')
|
136
|
+
assert @response.save_revision
|
137
|
+
@revision = @response.latest_revision
|
138
|
+
@revision.title = "new revision title"
|
139
|
+
@revision.body = "new revision body"
|
140
|
+
@revision.slug = "new-donkey-slug"
|
141
|
+
@revision.save
|
142
|
+
end
|
143
|
+
|
144
|
+
should "copy over parameters we want (title, body, etc.)" do
|
145
|
+
assert @response.apply_revision
|
146
|
+
assert_equal @revision.title, @response.title
|
147
|
+
assert_equal @revision.body, @response.body
|
148
|
+
end
|
149
|
+
|
150
|
+
should "do nothing (ie not raise an exception)" do
|
151
|
+
@response.revisions.delete_all
|
152
|
+
assert_equal false, @response.apply_revision
|
153
|
+
end
|
154
|
+
|
155
|
+
should "not copy over parameters we want to keep (slug, status, revision_of, etc.)" do
|
156
|
+
@response.apply_revision
|
157
|
+
assert_equal 'published', @response.status
|
158
|
+
assert_equal nil, @response.revision_of
|
159
|
+
assert_not_equal @response.slug, @revision.slug
|
160
|
+
end
|
161
|
+
|
162
|
+
should "not save the response" do
|
163
|
+
@response.apply_revision
|
164
|
+
@response.reload
|
165
|
+
assert_not_equal @revision.title, @response.title
|
166
|
+
end
|
167
|
+
|
168
|
+
should "save the response when using bang" do
|
169
|
+
@response.apply_revision!
|
170
|
+
@response.reload
|
171
|
+
assert_equal @revision.title, @response.title
|
172
|
+
assert_equal 'published', @response.status
|
173
|
+
assert_equal "this-is-a-post-about-donkey", @response.slug #still keep og slug
|
174
|
+
end
|
175
|
+
|
176
|
+
should "throw an exception on bang when no response" do
|
177
|
+
@response.revisions.delete_all
|
178
|
+
assert_raises RuntimeError do
|
179
|
+
@response.apply_revision!
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "with multiple revisions" do
|
184
|
+
setup do
|
185
|
+
@response.save_revision
|
186
|
+
@newer_revision = @response.latest_revision
|
187
|
+
@newer_revision.update_attribute(:title, 'even newer title')
|
188
|
+
end
|
189
|
+
|
190
|
+
should "copy over the latest revision if nothing passed" do
|
191
|
+
@response.apply_revision
|
192
|
+
assert_equal @newer_revision.title, @response.title
|
193
|
+
end
|
194
|
+
|
195
|
+
should "use a selected revision if passed" do
|
196
|
+
@response.apply_revision(@revision)
|
197
|
+
assert_equal @revision.title, @response.title
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: revisions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 0.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Brian Hamman
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-29 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: thoughtbot-shoulda
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
description: Save and apply revisions to a model, while keeping track of old revisiions
|
33
|
+
email: hamman@gmail.com
|
34
|
+
executables: []
|
35
|
+
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files:
|
39
|
+
- LICENSE
|
40
|
+
- README.rdoc
|
41
|
+
files:
|
42
|
+
- .document
|
43
|
+
- .gitignore
|
44
|
+
- LICENSE
|
45
|
+
- README.rdoc
|
46
|
+
- Rakefile
|
47
|
+
- VERSION
|
48
|
+
- lib/revisions.rb
|
49
|
+
- revisions.gemspec
|
50
|
+
- test/helper.rb
|
51
|
+
- test/models.rb
|
52
|
+
- test/schema.rb
|
53
|
+
- test/test_revisions.rb
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: http://github.com/hamman/revisions
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options:
|
60
|
+
- --charset=UTF-8
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.3.6
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: A lightweight way to handle Wordpress-like revisions
|
84
|
+
test_files:
|
85
|
+
- test/helper.rb
|
86
|
+
- test/models.rb
|
87
|
+
- test/schema.rb
|
88
|
+
- test/test_revisions.rb
|