rails4: gemify simply_versioned

closes CNVS-14287

test plan: versions should work same as before. for instance, wiki page
versions and quiz versions.

Change-Id: Ibbf9dd9787711c9d6d08f40add6378a906fde968
Reviewed-on: https://gerrit.instructure.com/41243
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Brian Palmer <brianp@instructure.com>
This commit is contained in:
Brian Palmer 2014-09-17 08:47:04 -06:00
parent a9d5a905c0
commit 6736b69401
34 changed files with 336 additions and 2526 deletions

View File

@ -0,0 +1,8 @@
Version.class_eval do
include PolymorphicTypeOverride
override_polymorphic_types versionable_type: {
'Quiz' => 'Quizzes::Quiz',
'QuizSubmission' => 'Quizzes::QuizSubmission'
}
end

View File

@ -1,4 +1,5 @@
Copyright (c) 2007 Matt Mower
Portions Copyright (c) 2007 Matt Mower
Portions Copyright (c) 2011-2014 Instructure, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -0,0 +1,304 @@
# SimplyVersioned 0.9.3
#
# Simple ActiveRecord versioning
# Copyright (c) 2007,2008 Matt Mower <self@mattmower.com>
# Released under the MIT license (see accompany MIT-LICENSE file)
#
require 'simply_versioned/gem_version'
require 'simply_versioned/version'
module SimplyVersioned
class BadOptions < StandardError
def initialize( keys )
super( "Keys: #{keys.join( "," )} are not known by SimplyVersioned" )
end
end
DEFAULTS = {
:keep => nil,
:automatic => true,
:exclude => [],
:explicit => false,
# callbacks
:when => nil,
:on_create => nil,
:on_update => nil,
:on_load => nil
}
module ClassMethods
# Marks this ActiveRecord model as being versioned. Calls to +create+ or +save+ will,
# in future, create a series of associated Version instances that can be accessed via
# the +versions+ association.
#
# Options:
# +keep+ - specifies the number of old versions to keep (default = nil, never delete old versions)
# +automatic+ - controls whether versions are created automatically (default = true, save versions)
# +exclude+ - specify columns that will not be saved (default = [], save all columns)
#
# Additional INSTRUCTURE options:
# +explicit+ - explicit versioning keeps the last version up to date,
# but doesn't automatically create new versions (default = false)
# +when+ - callback to indicate whether an instance needs a version
# saved or not. if present, the model is passed to the
# callback which should return true or false, true indicating
# a version should be saved. if absent, versions are saved if
# any attribute other than updated_at is changed.
# +on_create+ - callback to allow additional changes to a new version
# that's about to be saved.
# +on_update+ - callback to allow additional changes to an updated (see
# +explicit+ parameter) version that's about to be saved.
# +on_load+ - callback to allow processing or changes after loading
# (finding) the version from the database.
#
# To save the record without creating a version either set +versioning_enabled+ to false
# on the model before calling save or, alternatively, use +without_versioning+ and save
# the model from its block.
#
def simply_versioned( options = {} )
bad_keys = options.keys - SimplyVersioned::DEFAULTS.keys
raise SimplyVersioned::BadOptions.new( bad_keys ) unless bad_keys.empty?
options.reverse_merge!(DEFAULTS)
options[:exclude] = Array( options[ :exclude ] ).map( &:to_s )
has_many :versions, :order => 'number DESC', :as => :versionable,
:dependent => :destroy,
:inverse_of => :versionable, :extend => VersionsProxyMethods
# INSTRUCTURE: Added to allow quick access to the most recent version
# See 'current_version' below for the common use of current_version_unidirectional
has_one :current_version_unidirectional, :class_name => 'Version', :order => 'number DESC', :as => :versionable, :dependent => :destroy
# INSTRUCTURE: Lets us ignore certain things when deciding whether to store a new version
before_save :check_if_changes_are_worth_versioning
after_save :simply_versioned_create_version
cattr_accessor :simply_versioned_options
self.simply_versioned_options = options
class_eval do
def versioning_enabled=( enabled )
self.instance_variable_set( :@simply_versioned_enabled, enabled )
end
def versioning_enabled?
enabled = self.instance_variable_get( :@simply_versioned_enabled )
if enabled.nil?
enabled = self.instance_variable_set( :@simply_versioned_enabled, self.simply_versioned_options[:automatic] )
end
enabled
end
end
end
end
# Methods that will be defined on the ActiveRecord model being versioned
module InstanceMethods
# Revert the attributes of this model to their values as of an earlier version.
#
# Pass either a Version instance or a version number.
#
# options:
# +except+ specify a list of attributes that are not restored (default: created_at, updated_at)
#
def revert_to_version( version, options = {} )
options.reverse_merge!({
:except => [:created_at,:updated_at]
})
version = if version.kind_of?( Version )
version
elsif version.kind_of?( Fixnum )
self.versions.find_by_number( version )
end
raise "Invalid version (#{version.inspect}) specified!" unless version
options[:except] = options[:except].map( &:to_s )
self.update_attributes( YAML::load( version.yaml ).except( *options[:except] ) )
end
# Invoke the supplied block passing the receiver as the sole block argument with
# versioning enabled or disabled depending upon the value of the +enabled+ parameter
# for the duration of the block.
def with_versioning( enabled = true)
versioning_was_enabled = self.versioning_enabled?
explicit_versioning_was_enabled = @simply_versioned_explicit_enabled
explicit_enabled = false
if enabled.is_a?(Hash)
opts = enabled
enabled = true
explicit_enabled = true if opts[:explicit]
end
self.versioning_enabled = enabled
@simply_versioned_explicit_enabled = explicit_enabled
# INSTRUCTURE: always create a version if explicitly told to do so
@versioning_explicitly_enabled = enabled == true
begin
yield self
ensure
@versioning_explicitly_enabled = nil
self.versioning_enabled = versioning_was_enabled
@simply_versioned_explicit_enabled = explicit_enabled
end
end
def without_versioning(&block)
with_versioning(false, &block)
end
def unversioned?
self.versions.nil? || !self.versions.exists?
end
def versioned?
!unversioned?
end
# INSTRUCTURE: Added to allow model instances pulled out
# of versions to still know their version number
def force_version_number(number)
@simply_versioned_version_number = number
end
attr_accessor :simply_versioned_version_model
def version_number
if @simply_versioned_version_number
@simply_versioned_version_number
else
self.versions.maximum(:number) || 0
end
end
def current_version?
!@simply_versioned_version_number
end
# Create a bi-directional current_version association so we don't need
# to reload the 'versionable' object each time we access the model
def current_version
current_version_unidirectional.tap do |version|
version.versionable = self
end
end
protected
# INSTRUCTURE: If defined on a method, allow a check
# on the before_save to see if the changes are worth
# creating a new version for
def check_if_changes_are_worth_versioning
@changes_are_worth_versioning = simply_versioned_options[:when] ?
simply_versioned_options[:when].call(self) :
(self.changes.keys.map(&:to_s) - simply_versioned_options[:exclude] - ["updated_at"]).present?
true
end
def simply_versioned_create_version
if self.versioning_enabled?
# INSTRUCTURE
if @versioning_explicitly_enabled || @changes_are_worth_versioning
@changes_are_worth_versioning = nil
if simply_versioned_options[:explicit] && !@simply_versioned_explicit_enabled && versioned?
version = self.versions.current
version.yaml = self.attributes.except( *simply_versioned_options[:exclude] ).to_yaml
simply_versioned_options[:on_update].try(:call, self, version)
version.save
else
version = self.versions.create( :yaml => self.attributes.except( *simply_versioned_options[:exclude] ).to_yaml )
if version
simply_versioned_options[:on_create].try(:call, self, version)
self.versions.clean_old_versions( simply_versioned_options[:keep].to_i ) if simply_versioned_options[:keep]
end
end
end
end
true
end
end
module VersionsProxyMethods
# Anything that returns a Version should have its versionable pre-
# populated. This is basically a way of getting around the fact that
# ActiveRecord doesn't have a polymorphic :inverse_of option.
def method_missing(method, *a, &b)
case method
when :minimum, :maximum, :exists?, :all, :find_all, :each then
populate_versionables(super)
when :find then
case a.first
when :all then populate_versionables(super)
when :first, :last then populate_versionable(super)
else super
end
else
super
end
end
def populate_versionables(versions)
versions.each{ |v| populate_versionable(v) } if versions.is_a?(Array)
versions
end
def populate_versionable(version)
if version && !version.frozen?
version.versionable = proxy_association.owner
end
version
end
# Get the Version instance corresponding to this models for the specified version number.
def get_version( number )
populate_versionable find_by_number( number )
end
alias_method :get, :get_version
# Get the first Version corresponding to this model.
def first_version
populate_versionable reorder( 'number ASC' ).limit(1).to_a.first
end
alias_method :first, :first_version
# Get the current Version corresponding to this model.
def current_version
populate_versionable reorder( 'number DESC' ).limit(1).to_a.first
end
alias_method :current, :current_version
# If the model instance has more versions than the limit specified, delete all excess older versions.
def clean_old_versions( versions_to_keep )
where( 'number <= ?', self.maximum( :number ) - versions_to_keep ).each do |version|
version.destroy
end
end
alias_method :purge, :clean_old_versions
# Return the Version for this model with the next higher version
def next_version( number )
populate_versionable reorder( 'number ASC' ).where( "number > ?", number ).limit(1).to_a.first
end
alias_method :next, :next_version
# Return the Version for this model with the next lower version
def previous_version( number )
populate_versionable reorder( 'number DESC' ).where( "number < ?", number ).limit(1).to_a.first
end
alias_method :previous, :previous_version
end
def self.included( receiver )
receiver.extend ClassMethods
receiver.send :include, InstanceMethods
end
end
ActiveRecord::Base.send( :include, SimplyVersioned )

View File

@ -0,0 +1,3 @@
module SimplyVersioned
VERSION = "1.0.0"
end

View File

@ -13,10 +13,6 @@
# class with those attributes.
#
class Version < ActiveRecord::Base #:nodoc:
# INSTRUCTURE: shims for quizzes namespacing
include PolymorphicTypeOverride
override_polymorphic_types versionable_type: {'Quiz' => 'Quizzes::Quiz', 'QuizSubmission' => 'Quizzes::QuizSubmission'}
belongs_to :versionable, :polymorphic => true
before_create :initialize_number

View File

@ -0,0 +1,19 @@
$:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
require "simply_versioned/gem_version"
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "simply_versioned"
s.version = SimplyVersioned::VERSION
s.authors = ["Matt Mower", "Brian Palmer"]
s.email = ["brianp@instructure.com"]
s.homepage = "http://www.instructure.com"
s.summary = "Instructure-maintained fork of simply_versioned"
s.files = Dir["{app,config,db,lib}/**/*"]
s.test_files = Dir["spec_canvas/**/*"]
s.add_dependency "rails", ">= 3.2", "< 4.2"
end

View File

@ -1,31 +0,0 @@
require 'rake'
require 'rake/testtask'
require 'rdoc/task'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the simply_versioned plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the simply_versioned plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'SimplyVersioned'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
desc 'Measures test coverage using rcov'
task :rcov do
rm_f "coverage"
rm_f "coverage.data"
rcov = "rcov --rails --aggregate coverage.data --text-summary -Ilib"
system("#{rcov} --html #{Dir.glob('test/**/*_test.rb').join(' ')}")
system("open coverage/index.html") if PLATFORM['darwin']
end

View File

@ -1,12 +0,0 @@
require 'rails/generators/active_record'
class SimplyVersionedMigrationGenerator < ActiveRecord::Generators::Base
source_root File.expand_path('../templates', __FILE__)
def create_migration_file
migration_template "migration.rb", "db/migrate/#{file_name}.rb"
end
def file_name
"simply_versioned_migration"
end
end

View File

@ -1,18 +0,0 @@
class SimplyVersionedMigration < ActiveRecord::Migration
def self.up
create_table :versions do |t|
t.integer :versionable_id
t.string :versionable_type
t.integer :number
t.text :yaml
t.datetime :created_at
end
add_index :versions, [:versionable_id, :versionable_type]
end
def self.down
drop_table :versions
end
end

View File

@ -1 +0,0 @@
require 'simply_versioned'

View File

@ -1 +0,0 @@
# Install hook code here

View File

@ -1,309 +0,0 @@
# SimplyVersioned 0.9.3
#
# Simple ActiveRecord versioning
# Copyright (c) 2007,2008 Matt Mower <self@mattmower.com>
# Released under the MIT license (see accompany MIT-LICENSE file)
#
module SoftwareHeretics
module ActiveRecord
module SimplyVersioned
class BadOptions < StandardError
def initialize( keys )
super( "Keys: #{keys.join( "," )} are not known by SimplyVersioned" )
end
end
DEFAULTS = {
:keep => nil,
:automatic => true,
:exclude => [],
:explicit => false,
# callbacks
:when => nil,
:on_create => nil,
:on_update => nil,
:on_load => nil
}
module ClassMethods
# Marks this ActiveRecord model as being versioned. Calls to +create+ or +save+ will,
# in future, create a series of associated Version instances that can be accessed via
# the +versions+ association.
#
# Options:
# +keep+ - specifies the number of old versions to keep (default = nil, never delete old versions)
# +automatic+ - controls whether versions are created automatically (default = true, save versions)
# +exclude+ - specify columns that will not be saved (default = [], save all columns)
#
# Additional INSTRUCTURE options:
# +explicit+ - explicit versioning keeps the last version up to date,
# but doesn't automatically create new versions (default = false)
# +when+ - callback to indicate whether an instance needs a version
# saved or not. if present, the model is passed to the
# callback which should return true or false, true indicating
# a version should be saved. if absent, versions are saved if
# any attribute other than updated_at is changed.
# +on_create+ - callback to allow additional changes to a new version
# that's about to be saved.
# +on_update+ - callback to allow additional changes to an updated (see
# +explicit+ parameter) version that's about to be saved.
# +on_load+ - callback to allow processing or changes after loading
# (finding) the version from the database.
#
# To save the record without creating a version either set +versioning_enabled+ to false
# on the model before calling save or, alternatively, use +without_versioning+ and save
# the model from its block.
#
def simply_versioned( options = {} )
bad_keys = options.keys - SimplyVersioned::DEFAULTS.keys
raise SimplyVersioned::BadOptions.new( bad_keys ) unless bad_keys.empty?
options.reverse_merge!(DEFAULTS)
options[:exclude] = Array( options[ :exclude ] ).map( &:to_s )
has_many :versions, :order => 'number DESC', :as => :versionable,
:dependent => :destroy,
:inverse_of => :versionable, :extend => VersionsProxyMethods
# INSTRUCTURE: Added to allow quick access to the most recent version
# See 'current_version' below for the common use of current_version_unidirectional
has_one :current_version_unidirectional, :class_name => 'Version', :order => 'number DESC', :as => :versionable, :dependent => :destroy
# INSTRUCTURE: Lets us ignore certain things when deciding whether to store a new version
before_save :check_if_changes_are_worth_versioning
after_save :simply_versioned_create_version
cattr_accessor :simply_versioned_options
self.simply_versioned_options = options
class_eval do
def versioning_enabled=( enabled )
self.instance_variable_set( :@simply_versioned_enabled, enabled )
end
def versioning_enabled?
enabled = self.instance_variable_get( :@simply_versioned_enabled )
if enabled.nil?
enabled = self.instance_variable_set( :@simply_versioned_enabled, self.simply_versioned_options[:automatic] )
end
enabled
end
end
end
end
# Methods that will be defined on the ActiveRecord model being versioned
module InstanceMethods
# Revert the attributes of this model to their values as of an earlier version.
#
# Pass either a Version instance or a version number.
#
# options:
# +except+ specify a list of attributes that are not restored (default: created_at, updated_at)
#
def revert_to_version( version, options = {} )
options.reverse_merge!({
:except => [:created_at,:updated_at]
})
version = if version.kind_of?( Version )
version
elsif version.kind_of?( Fixnum )
self.versions.find_by_number( version )
end
raise "Invalid version (#{version.inspect}) specified!" unless version
options[:except] = options[:except].map( &:to_s )
self.update_attributes( YAML::load( version.yaml ).except( *options[:except] ) )
end
# Invoke the supplied block passing the receiver as the sole block argument with
# versioning enabled or disabled depending upon the value of the +enabled+ parameter
# for the duration of the block.
def with_versioning( enabled = true)
versioning_was_enabled = self.versioning_enabled?
explicit_versioning_was_enabled = @simply_versioned_explicit_enabled
explicit_enabled = false
if enabled.is_a?(Hash)
opts = enabled
enabled = true
explicit_enabled = true if opts[:explicit]
end
self.versioning_enabled = enabled
@simply_versioned_explicit_enabled = explicit_enabled
# INSTRUCTURE: always create a version if explicitly told to do so
@versioning_explicitly_enabled = enabled == true
begin
yield self
ensure
@versioning_explicitly_enabled = nil
self.versioning_enabled = versioning_was_enabled
@simply_versioned_explicit_enabled = explicit_enabled
end
end
def without_versioning(&block)
with_versioning(false, &block)
end
def unversioned?
self.versions.nil? || !self.versions.exists?
end
def versioned?
!unversioned?
end
# INSTRUCTURE: Added to allow model instances pulled out
# of versions to still know their version number
def force_version_number(number)
@simply_versioned_version_number = number
end
attr_accessor :simply_versioned_version_model
def version_number
if @simply_versioned_version_number
@simply_versioned_version_number
else
self.versions.maximum(:number) || 0
end
end
def current_version?
!@simply_versioned_version_number
end
# Create a bi-directional current_version association so we don't need
# to reload the 'versionable' object each time we access the model
def current_version
current_version_unidirectional.tap do |version|
version.versionable = self
end
end
protected
# INSTRUCTURE: If defined on a method, allow a check
# on the before_save to see if the changes are worth
# creating a new version for
def check_if_changes_are_worth_versioning
@changes_are_worth_versioning = simply_versioned_options[:when] ?
simply_versioned_options[:when].call(self) :
(self.changes.keys.map(&:to_s) - simply_versioned_options[:exclude] - ["updated_at"]).present?
true
end
def simply_versioned_create_version
if self.versioning_enabled?
# INSTRUCTURE
if @versioning_explicitly_enabled || @changes_are_worth_versioning
@changes_are_worth_versioning = nil
if simply_versioned_options[:explicit] && !@simply_versioned_explicit_enabled && versioned?
version = self.versions.current
version.yaml = self.attributes.except( *simply_versioned_options[:exclude] ).to_yaml
simply_versioned_options[:on_update].try(:call, self, version)
version.save
else
version = self.versions.create( :yaml => self.attributes.except( *simply_versioned_options[:exclude] ).to_yaml )
if version
simply_versioned_options[:on_create].try(:call, self, version)
self.versions.clean_old_versions( simply_versioned_options[:keep].to_i ) if simply_versioned_options[:keep]
end
end
end
end
true
end
end
module VersionsProxyMethods
# Anything that returns a Version should have its versionable pre-
# populated. This is basically a way of getting around the fact that
# ActiveRecord doesn't have a polymorphic :inverse_of option.
def method_missing(method, *a, &b)
case method
when :minimum, :maximum, :exists?, :all, :find_all, :each then
populate_versionables(super)
when :find then
case a.first
when :all then populate_versionables(super)
when :first, :last then populate_versionable(super)
else super
end
else
super
end
end
def populate_versionables(versions)
versions.each{ |v| populate_versionable(v) } if versions.is_a?(Array)
versions
end
def populate_versionable(version)
if version && !version.frozen?
version.versionable = proxy_association.owner
end
version
end
# Get the Version instance corresponding to this models for the specified version number.
def get_version( number )
populate_versionable find_by_number( number )
end
alias_method :get, :get_version
# Get the first Version corresponding to this model.
def first_version
populate_versionable reorder( 'number ASC' ).limit(1).to_a.first
end
alias_method :first, :first_version
# Get the current Version corresponding to this model.
def current_version
populate_versionable reorder( 'number DESC' ).limit(1).to_a.first
end
alias_method :current, :current_version
# If the model instance has more versions than the limit specified, delete all excess older versions.
def clean_old_versions( versions_to_keep )
where( 'number <= ?', self.maximum( :number ) - versions_to_keep ).each do |version|
version.destroy
end
end
alias_method :purge, :clean_old_versions
# Return the Version for this model with the next higher version
def next_version( number )
populate_versionable reorder( 'number ASC' ).where( "number > ?", number ).limit(1).to_a.first
end
alias_method :next, :next_version
# Return the Version for this model with the next lower version
def previous_version( number )
populate_versionable reorder( 'number DESC' ).where( "number < ?", number ).limit(1).to_a.first
end
alias_method :previous, :previous_version
end
def self.included( receiver )
receiver.extend ClassMethods
receiver.send :include, InstanceMethods
end
end
end
end
ActiveRecord::Base.send( :include, SoftwareHeretics::ActiveRecord::SimplyVersioned )

View File

@ -1,4 +0,0 @@
# desc "Explaining what the task does"
# task :simply_versioned do
# # Task goes here
# end

View File

@ -1,122 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Module: SoftwareHeretics</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="classHeader">
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Module</strong></td>
<td class="class-name-in-header">SoftwareHeretics</td>
</tr>
<tr class="top-aligned-row">
<td><strong>In:</strong></td>
<td>
<a href="../files/lib/simply_versioned_rb.html">
lib/simply_versioned.rb
</a>
<br />
</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<p>
SimplyVersioned 0.1
</p>
<p>
Simple <a href="SoftwareHeretics/ActiveRecord.html">ActiveRecord</a>
versioning Copyright (c) 2007 Matt Mower &lt;self@mattmower.com&gt;
Released under the MIT license (see accompany MIT-LICENSE file)
</p>
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<div id="class-list">
<h3 class="section-bar">Classes and Modules</h3>
Module <a href="SoftwareHeretics/ActiveRecord.html" class="link">SoftwareHeretics::ActiveRecord</a><br />
</div>
<!-- if method_list -->
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,111 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Module: SoftwareHeretics::ActiveRecord</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="classHeader">
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Module</strong></td>
<td class="class-name-in-header">SoftwareHeretics::ActiveRecord</td>
</tr>
<tr class="top-aligned-row">
<td><strong>In:</strong></td>
<td>
<a href="../../files/lib/simply_versioned_rb.html">
lib/simply_versioned.rb
</a>
<br />
</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
</div>
</div>
<!-- if includes -->
<div id="section">
<div id="class-list">
<h3 class="section-bar">Classes and Modules</h3>
Module <a href="ActiveRecord/SimplyVersioned.html" class="link">SoftwareHeretics::ActiveRecord::SimplyVersioned</a><br />
</div>
<!-- if method_list -->
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,149 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Module: SoftwareHeretics::ActiveRecord::SimplyVersioned</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="classHeader">
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Module</strong></td>
<td class="class-name-in-header">SoftwareHeretics::ActiveRecord::SimplyVersioned</td>
</tr>
<tr class="top-aligned-row">
<td><strong>In:</strong></td>
<td>
<a href="../../../files/lib/simply_versioned_rb.html">
lib/simply_versioned.rb
</a>
<br />
</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
</div>
<div id="method-list">
<h3 class="section-bar">Methods</h3>
<div class="name-list">
<a href="#M000001">included</a>&nbsp;&nbsp;
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<div id="class-list">
<h3 class="section-bar">Classes and Modules</h3>
Module <a href="SimplyVersioned/ClassMethods.html" class="link">SoftwareHeretics::ActiveRecord::SimplyVersioned::ClassMethods</a><br />
Module <a href="SimplyVersioned/InstanceMethods.html" class="link">SoftwareHeretics::ActiveRecord::SimplyVersioned::InstanceMethods</a><br />
Module <a href="SimplyVersioned/VersionsProxyMethods.html" class="link">SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods</a><br />
</div>
<!-- if method_list -->
<div id="methods">
<h3 class="section-bar">Public Class methods</h3>
<div id="method-M000001" class="method-detail">
<a name="M000001"></a>
<div class="method-heading">
<a href="#M000001" class="method-signature">
<span class="method-name">included</span><span class="method-args">( receiver )</span>
</a>
</div>
<div class="method-description">
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000001-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000001-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 96</span>
96: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">included</span>( <span class="ruby-identifier">receiver</span> )
97: <span class="ruby-identifier">receiver</span>.<span class="ruby-identifier">extend</span> <span class="ruby-constant">ClassMethods</span>
98: <span class="ruby-identifier">receiver</span>.<span class="ruby-identifier">send</span> <span class="ruby-identifier">:include</span>, <span class="ruby-constant">InstanceMethods</span>
99: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
</div>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,159 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Module: SoftwareHeretics::ActiveRecord::SimplyVersioned::ClassMethods</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="../../../.././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="classHeader">
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Module</strong></td>
<td class="class-name-in-header">SoftwareHeretics::ActiveRecord::SimplyVersioned::ClassMethods</td>
</tr>
<tr class="top-aligned-row">
<td><strong>In:</strong></td>
<td>
<a href="../../../../files/lib/simply_versioned_rb.html">
lib/simply_versioned.rb
</a>
<br />
</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
</div>
<div id="method-list">
<h3 class="section-bar">Methods</h3>
<div class="name-list">
<a href="#M000008">simply_versioned</a>&nbsp;&nbsp;
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<!-- if method_list -->
<div id="methods">
<h3 class="section-bar">Public Instance methods</h3>
<div id="method-M000008" class="method-detail">
<a name="M000008"></a>
<div class="method-heading">
<a href="#M000008" class="method-signature">
<span class="method-name">simply_versioned</span><span class="method-args">( options = {} )</span>
</a>
</div>
<div class="method-description">
<p>
Marks this <a href="../../ActiveRecord.html">ActiveRecord</a> model as
being versioned. Calls to <tt>create</tt> or <tt>save</tt> will, in future,
create a series of associated Version instances that can be accessed via
the <tt>versions</tt> association.
</p>
<p>
Options: <tt>limit</tt> - specifies the number of old versions to keep
(default = 99)
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000008-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000008-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 23</span>
23: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">simply_versioned</span>( <span class="ruby-identifier">options</span> = {} )
24: <span class="ruby-identifier">options</span>.<span class="ruby-identifier">reverse_merge!</span>( {
25: <span class="ruby-identifier">:keep</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-value">99</span>
26: })
27:
28: <span class="ruby-identifier">has_many</span> <span class="ruby-identifier">:versions</span>, <span class="ruby-identifier">:order</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-value str">'number DESC'</span>, <span class="ruby-identifier">:as</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">:versionable</span>, <span class="ruby-identifier">:dependent</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">:destroy</span>, <span class="ruby-identifier">:extend</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-constant">VersionsProxyMethods</span>
29:
30: <span class="ruby-identifier">after_save</span> <span class="ruby-identifier">:simply_versioned_create_version</span>
31:
32: <span class="ruby-identifier">cattr_accessor</span> <span class="ruby-identifier">:simply_versioned_keep_limit</span>
33: <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">simply_versioned_keep_limit</span> = <span class="ruby-identifier">options</span>[<span class="ruby-identifier">:keep</span>]
34: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
</div>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,178 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Module: SoftwareHeretics::ActiveRecord::SimplyVersioned::InstanceMethods</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="../../../.././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="classHeader">
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Module</strong></td>
<td class="class-name-in-header">SoftwareHeretics::ActiveRecord::SimplyVersioned::InstanceMethods</td>
</tr>
<tr class="top-aligned-row">
<td><strong>In:</strong></td>
<td>
<a href="../../../../files/lib/simply_versioned_rb.html">
lib/simply_versioned.rb
</a>
<br />
</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
</div>
<div id="method-list">
<h3 class="section-bar">Methods</h3>
<div class="name-list">
<a href="#M000009">revert_to_version</a>&nbsp;&nbsp;
<a href="#M000010">simply_versioned_create_version</a>&nbsp;&nbsp;
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<!-- if method_list -->
<div id="methods">
<h3 class="section-bar">Public Instance methods</h3>
<div id="method-M000009" class="method-detail">
<a name="M000009"></a>
<div class="method-heading">
<a href="#M000009" class="method-signature">
<span class="method-name">revert_to_version</span><span class="method-args">( version )</span>
</a>
</div>
<div class="method-description">
<p>
Revert this model instance to the attributes it had at the specified
version number.
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000009-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000009-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 41</span>
41: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">revert_to_version</span>( <span class="ruby-identifier">version</span> )
42: <span class="ruby-identifier">version</span> = <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">version</span>.<span class="ruby-identifier">kind_of?</span>( <span class="ruby-constant">Version</span> )
43: <span class="ruby-identifier">version</span>
44: <span class="ruby-keyword kw">else</span>
45: <span class="ruby-identifier">version</span> = <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">versions</span>.<span class="ruby-identifier">find</span>( <span class="ruby-identifier">:first</span>, <span class="ruby-identifier">:conditions</span> =<span class="ruby-operator">&gt;</span> { <span class="ruby-identifier">:number</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-constant">Integer</span>( <span class="ruby-identifier">version</span> ) } )
46: <span class="ruby-keyword kw">end</span>
47: <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">update_attributes</span>( <span class="ruby-constant">YAML</span><span class="ruby-operator">::</span><span class="ruby-identifier">load</span>( <span class="ruby-identifier">version</span>.<span class="ruby-identifier">yaml</span> ) )
48: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
<h3 class="section-bar">Protected Instance methods</h3>
<div id="method-M000010" class="method-detail">
<a name="M000010"></a>
<div class="method-heading">
<a href="#M000010" class="method-signature">
<span class="method-name">simply_versioned_create_version</span><span class="method-args">()</span>
</a>
</div>
<div class="method-description">
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000010-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000010-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 52</span>
52: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">simply_versioned_create_version</span>
53: <span class="ruby-keyword kw">if</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">versions</span>.<span class="ruby-identifier">create</span>( <span class="ruby-identifier">:yaml</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">attributes</span>.<span class="ruby-identifier">to_yaml</span> )
54: <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">versions</span>.<span class="ruby-identifier">clean</span>( <span class="ruby-identifier">simply_versioned_keep_limit</span> )
55: <span class="ruby-keyword kw">end</span>
56: <span class="ruby-keyword kw">true</span>
57: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
</div>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,286 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Module: SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="../../../.././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="classHeader">
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Module</strong></td>
<td class="class-name-in-header">SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods</td>
</tr>
<tr class="top-aligned-row">
<td><strong>In:</strong></td>
<td>
<a href="../../../../files/lib/simply_versioned_rb.html">
lib/simply_versioned.rb
</a>
<br />
</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
</div>
<div id="method-list">
<h3 class="section-bar">Methods</h3>
<div class="name-list">
<a href="#M000005">clean</a>&nbsp;&nbsp;
<a href="#M000004">current</a>&nbsp;&nbsp;
<a href="#M000003">first</a>&nbsp;&nbsp;
<a href="#M000002">get</a>&nbsp;&nbsp;
<a href="#M000006">next</a>&nbsp;&nbsp;
<a href="#M000007">prev</a>&nbsp;&nbsp;
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<!-- if method_list -->
<div id="methods">
<h3 class="section-bar">Public Instance methods</h3>
<div id="method-M000005" class="method-detail">
<a name="M000005"></a>
<div class="method-heading">
<a href="#M000005" class="method-signature">
<span class="method-name">clean</span><span class="method-args">( versions_to_keep )</span>
</a>
</div>
<div class="method-description">
<p>
If the model instance has more versions than the limit specified, delete
all excess older versions.
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000005-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000005-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 79</span>
79: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">clean</span>( <span class="ruby-identifier">versions_to_keep</span> )
80: <span class="ruby-identifier">find</span>( <span class="ruby-identifier">:all</span>, <span class="ruby-identifier">:conditions</span> =<span class="ruby-operator">&gt;</span> [ <span class="ruby-value str">'number &lt;= ?'</span>, <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">maximum</span>( <span class="ruby-identifier">:number</span> ) <span class="ruby-operator">-</span> <span class="ruby-identifier">versions_to_keep</span> ] ).<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">version</span><span class="ruby-operator">|</span>
81: <span class="ruby-identifier">version</span>.<span class="ruby-identifier">destroy</span>
82: <span class="ruby-keyword kw">end</span>
83: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
<div id="method-M000004" class="method-detail">
<a name="M000004"></a>
<div class="method-heading">
<a href="#M000004" class="method-signature">
<span class="method-name">current</span><span class="method-args">()</span>
</a>
</div>
<div class="method-description">
<p>
Get the <a href="VersionsProxyMethods.html#M000004">current</a> Version
corresponding to this model.
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000004-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000004-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 74</span>
74: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">current</span>
75: <span class="ruby-identifier">find</span>( <span class="ruby-identifier">:first</span>, <span class="ruby-identifier">:order</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-value str">'number DESC'</span> )
76: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
<div id="method-M000003" class="method-detail">
<a name="M000003"></a>
<div class="method-heading">
<a href="#M000003" class="method-signature">
<span class="method-name">first</span><span class="method-args">()</span>
</a>
</div>
<div class="method-description">
<p>
Get the <a href="VersionsProxyMethods.html#M000003">first</a> Version
corresponding to this model.
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000003-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000003-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 69</span>
69: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">first</span>
70: <span class="ruby-identifier">find</span>( <span class="ruby-identifier">:first</span>, <span class="ruby-identifier">:order</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-value str">'number ASC'</span> )
71: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
<div id="method-M000002" class="method-detail">
<a name="M000002"></a>
<div class="method-heading">
<a href="#M000002" class="method-signature">
<span class="method-name">get</span><span class="method-args">( number )</span>
</a>
</div>
<div class="method-description">
<p>
Get the Version instance corresponding to this models for the specified
version number.
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000002-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000002-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 64</span>
64: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">get</span>( <span class="ruby-identifier">number</span> )
65: <span class="ruby-identifier">find_by_number</span>( <span class="ruby-identifier">number</span> )
66: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
<div id="method-M000006" class="method-detail">
<a name="M000006"></a>
<div class="method-heading">
<a href="#M000006" class="method-signature">
<span class="method-name">next</span><span class="method-args">( number )</span>
</a>
</div>
<div class="method-description">
<p>
Return the Version for this model with the <a
href="VersionsProxyMethods.html#M000006">next</a> higher version
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000006-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000006-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 86</span>
86: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">next</span>( <span class="ruby-identifier">number</span> )
87: <span class="ruby-identifier">find</span>( <span class="ruby-identifier">:first</span>, <span class="ruby-identifier">:order</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-value str">'number ASC'</span>, <span class="ruby-identifier">:conditions</span> =<span class="ruby-operator">&gt;</span> [ <span class="ruby-value str">&quot;number &gt; ?&quot;</span>, <span class="ruby-identifier">number</span> ] )
88: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
<div id="method-M000007" class="method-detail">
<a name="M000007"></a>
<div class="method-heading">
<a href="#M000007" class="method-signature">
<span class="method-name">prev</span><span class="method-args">( number )</span>
</a>
</div>
<div class="method-description">
<p>
Return the Version for this model with the <a
href="VersionsProxyMethods.html#M000006">next</a> lower version
</p>
<p><a class="source-toggle" href="#"
onclick="toggleCode('M000007-source');return false;">[Source]</a></p>
<div class="method-source-code" id="M000007-source">
<pre>
<span class="ruby-comment cmt"># File lib/simply_versioned.rb, line 91</span>
91: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">prev</span>( <span class="ruby-identifier">number</span> )
92: <span class="ruby-identifier">find</span>( <span class="ruby-identifier">:first</span>, <span class="ruby-identifier">:order</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-value str">'number DESC'</span>, <span class="ruby-identifier">:conditions</span> =<span class="ruby-operator">&gt;</span> [ <span class="ruby-value str">&quot;number &lt; ?&quot;</span>, <span class="ruby-identifier">number</span> ] )
93: <span class="ruby-keyword kw">end</span>
</pre>
</div>
</div>
</div>
</div>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1 +0,0 @@
Sun, 30 Dec 2007 11:52:57 +0000

View File

@ -1,216 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>File: README</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="fileHeader">
<h1>README</h1>
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Path:</strong></td>
<td>README
</td>
</tr>
<tr class="top-aligned-row">
<td><strong>Last Update:</strong></td>
<td>Sun Dec 30 11:51:41 +0000 2007</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<p>
SimplyVersioned
</p>
<h6>=========</h6>
<p>
Release: 0.2 Date: 30-12-2007 Author: Matt Mower &lt;self@mattmower.com&gt;
</p>
<p>
SimplyVersioned is a simple, non-invasive, approach to versioning
ActiveRecord models.
</p>
<p>
SimplyVersioned does not require any structural change to the models to be
versioned and requires only one versions table to be created (a migration
generator is supplied with the plugin) regardless of the number of models
being versioned.
</p>
<p>
The plugin introduces a &#8216;Version&#8217; ActiveRecord model (that
reflects changes to model attributes) to which versioned models are
polymorphically associated. Version records store the model information as
a YAML hash.
</p>
<p>
SimplyVersioned meets a simple need for model versioning. If your needs are
more complex maybe try Rick Olsen&#8216;s acts_as_versioned (<a
href="http://svn.techno-weenie.net/projects/plugins/acts_as_versioned">svn.techno-weenie.net/projects/plugins/acts_as_versioned</a>/).
</p>
<p>
SimplyVersioned has (so far) been tested and found to work with Rails 2.0.1
and Ruby 1.8.6p111.
</p>
<p>
Usage
</p>
<h5></h5>
<ol>
<li>Install the plugin
</li>
</ol>
<pre>
./script/plugin install http://rubymatt.rubyforge.org/svn/simply_versioned
</pre>
<ol>
<li>Generate the migration
</li>
</ol>
<pre>
./script/generate simply_versioned_migration
</pre>
<ol>
<li>Create the versions table
</li>
</ol>
<pre>
rake db:migrate
</pre>
<ol>
<li>Annotate the models you want to version specifying how many versions to
keep
<pre>
class Thing &lt; ActiveRecord::Base
simply_versioned :keep =&gt; 10
end
</pre>
</li>
<li>Create versions
<pre>
thing = Thing.create!( :foo =&gt; bar ) # creates v1
thing.foo = baz
thing.save! # creates v2
</pre>
</li>
<li>Find versions
<pre>
thing.versions.each do |version| ... end
render :partial =&gt; 'thing_version', :collection =&gt; thing.versions
thing.versions.current
thing.versions.first
thing.versions.get( 3 )
</pre>
</li>
<li>Revert to a previous version
<pre>
thing.revert_to_version( 5 )
</pre>
</li>
<li>Traverse versions
<pre>
thing.versions.current.previous
thing.versions.first.next
</pre>
</li>
<li>Obtain a copy of a previous versioned model
<pre>
thing.versions.first.model # =&gt; Instantiated Thing with versioned values
</pre>
</li>
</ol>
<p>
Copyright (c) 2007 Matt Mower &lt;self@mattmower.com&gt; and released under
the MIT license
</p>
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<!-- if method_list -->
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,112 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>File: simply_versioned.rb</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="fileHeader">
<h1>simply_versioned.rb</h1>
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Path:</strong></td>
<td>lib/simply_versioned.rb
</td>
</tr>
<tr class="top-aligned-row">
<td><strong>Last Update:</strong></td>
<td>Sun Dec 30 11:46:53 +0000 2007</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<p>
SimplyVersioned 0.1
</p>
<p>
Simple ActiveRecord versioning Copyright (c) 2007 Matt Mower
&lt;self@mattmower.com&gt; Released under the MIT license (see accompany
MIT-LICENSE file)
</p>
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<!-- if method_list -->
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,112 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>File: version.rb</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
<div id="fileHeader">
<h1>version.rb</h1>
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Path:</strong></td>
<td>lib/version.rb
</td>
</tr>
<tr class="top-aligned-row">
<td><strong>Last Update:</strong></td>
<td>Sun Dec 30 11:31:55 +0000 2007</td>
</tr>
</table>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<p>
SimplyVersioned 0.1
</p>
<p>
Simple ActiveRecord versioning Copyright (c) 2007 Matt Mower
&lt;self@mattmower.com&gt; Released under the MIT license (see accompany
MIT-LICENSE file)
</p>
</div>
</div>
</div>
<!-- if includes -->
<div id="section">
<!-- if method_list -->
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--
Classes
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Classes</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
<base target="docwin" />
</head>
<body>
<div id="index">
<h1 class="section-bar">Classes</h1>
<div id="index-entries">
<a href="classes/SoftwareHeretics.html">SoftwareHeretics</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord.html">SoftwareHeretics::ActiveRecord</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned.html">SoftwareHeretics::ActiveRecord::SimplyVersioned</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/ClassMethods.html">SoftwareHeretics::ActiveRecord::SimplyVersioned::ClassMethods</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/InstanceMethods.html">SoftwareHeretics::ActiveRecord::SimplyVersioned::InstanceMethods</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/VersionsProxyMethods.html">SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods</a><br />
</div>
</div>
</body>
</html>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--
Files
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Files</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
<base target="docwin" />
</head>
<body>
<div id="index">
<h1 class="section-bar">Files</h1>
<div id="index-entries">
<a href="files/README.html">README</a><br />
<a href="files/lib/simply_versioned_rb.html">lib/simply_versioned.rb</a><br />
<a href="files/lib/version_rb.html">lib/version.rb</a><br />
</div>
</div>
</body>
</html>

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--
Methods
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Methods</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
<base target="docwin" />
</head>
<body>
<div id="index">
<h1 class="section-bar">Methods</h1>
<div id="index-entries">
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/VersionsProxyMethods.html#M000005">clean (SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/VersionsProxyMethods.html#M000004">current (SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/VersionsProxyMethods.html#M000003">first (SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/VersionsProxyMethods.html#M000002">get (SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned.html#M000001">included (SoftwareHeretics::ActiveRecord::SimplyVersioned)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/VersionsProxyMethods.html#M000006">next (SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/VersionsProxyMethods.html#M000007">prev (SoftwareHeretics::ActiveRecord::SimplyVersioned::VersionsProxyMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/InstanceMethods.html#M000009">revert_to_version (SoftwareHeretics::ActiveRecord::SimplyVersioned::InstanceMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/ClassMethods.html#M000008">simply_versioned (SoftwareHeretics::ActiveRecord::SimplyVersioned::ClassMethods)</a><br />
<a href="classes/SoftwareHeretics/ActiveRecord/SimplyVersioned/InstanceMethods.html#M000010">simply_versioned_create_version (SoftwareHeretics::ActiveRecord::SimplyVersioned::InstanceMethods)</a><br />
</div>
</div>
</body>
</html>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<!--
SimplyVersioned
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>SimplyVersioned</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<frameset rows="20%, 80%">
<frameset cols="25%,35%,45%">
<frame src="fr_file_index.html" title="Files" name="Files" />
<frame src="fr_class_index.html" name="Classes" />
<frame src="fr_method_index.html" name="Methods" />
</frameset>
<frame src="files/README.html" name="docwin" />
</frameset>
</html>

View File

@ -1,208 +0,0 @@
body {
font-family: Verdana,Arial,Helvetica,sans-serif;
font-size: 90%;
margin: 0;
margin-left: 40px;
padding: 0;
background: white;
}
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
h1 { font-size: 150%; }
h2,h3,h4 { margin-top: 1em; }
a { background: #eef; color: #039; text-decoration: none; }
a:hover { background: #039; color: #eef; }
/* Override the base stylesheet's Anchor inside a table cell */
td > a {
background: transparent;
color: #039;
text-decoration: none;
}
/* and inside a section title */
.section-title > a {
background: transparent;
color: #eee;
text-decoration: none;
}
/* === Structural elements =================================== */
div#index {
margin: 0;
margin-left: -40px;
padding: 0;
font-size: 90%;
}
div#index a {
margin-left: 0.7em;
}
div#index .section-bar {
margin-left: 0px;
padding-left: 0.7em;
background: #ccc;
font-size: small;
}
div#classHeader, div#fileHeader {
width: auto;
color: white;
padding: 0.5em 1.5em 0.5em 1.5em;
margin: 0;
margin-left: -40px;
border-bottom: 3px solid #006;
}
div#classHeader a, div#fileHeader a {
background: inherit;
color: white;
}
div#classHeader td, div#fileHeader td {
background: inherit;
color: white;
}
div#fileHeader {
background: #057;
}
div#classHeader {
background: #048;
}
.class-name-in-header {
font-size: 180%;
font-weight: bold;
}
div#bodyContent {
padding: 0 1.5em 0 1.5em;
}
div#description {
padding: 0.5em 1.5em;
background: #efefef;
border: 1px dotted #999;
}
div#description h1,h2,h3,h4,h5,h6 {
color: #125;;
background: transparent;
}
div#validator-badges {
text-align: center;
}
div#validator-badges img { border: 0; }
div#copyright {
color: #333;
background: #efefef;
font: 0.75em sans-serif;
margin-top: 5em;
margin-bottom: 0;
padding: 0.5em 2em;
}
/* === Classes =================================== */
table.header-table {
color: white;
font-size: small;
}
.type-note {
font-size: small;
color: #DEDEDE;
}
.xxsection-bar {
background: #eee;
color: #333;
padding: 3px;
}
.section-bar {
color: #333;
border-bottom: 1px solid #999;
margin-left: -20px;
}
.section-title {
background: #79a;
color: #eee;
padding: 3px;
margin-top: 2em;
margin-left: -30px;
border: 1px solid #999;
}
.top-aligned-row { vertical-align: top }
.bottom-aligned-row { vertical-align: bottom }
/* --- Context section classes ----------------------- */
.context-row { }
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
.context-item-value { font-size: small; color: #448; }
.context-item-desc { color: #333; padding-left: 2em; }
/* --- Method classes -------------------------- */
.method-detail {
background: #efefef;
padding: 0;
margin-top: 0.5em;
margin-bottom: 1em;
border: 1px dotted #ccc;
}
.method-heading {
color: black;
background: #ccc;
border-bottom: 1px solid #666;
padding: 0.2em 0.5em 0 0.5em;
}
.method-signature { color: black; background: inherit; }
.method-name { font-weight: bold; }
.method-args { font-style: italic; }
.method-description { padding: 0 0.5em 0 0.5em; }
/* --- Source code sections -------------------- */
a.source-toggle { font-size: 90%; }
div.method-source-code {
background: #262626;
color: #ffdead;
margin: 1em;
padding: 0.5em;
border: 1px dashed #999;
overflow: hidden;
}
div.method-source-code pre { color: #ffdead; overflow: hidden; }
/* --- Ruby keyword styles --------------------- */
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
.ruby-constant { color: #7fffd4; background: transparent; }
.ruby-keyword { color: #00ffff; background: transparent; }
.ruby-ivar { color: #eedd82; background: transparent; }
.ruby-operator { color: #00ffee; background: transparent; }
.ruby-identifier { color: #ffdead; background: transparent; }
.ruby-node { color: #ffa07a; background: transparent; }
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
.ruby-regexp { color: #ffa07a; background: transparent; }
.ruby-value { color: #7fffd4; background: transparent; }

View File

@ -1,313 +0,0 @@
require File.join( File.dirname( __FILE__ ), 'test_helper' )
require 'mocha/api'
class Aardvark < ActiveRecord::Base
simply_versioned :keep => 3
end
class Gnu < ActiveRecord::Base
simply_versioned :keep => 4
end
class Undine < ActiveRecord::Base
end
class Heffalump < ActiveRecord::Base
simply_versioned :automatic => false
end
class Saproling < ActiveRecord::Base
simply_versioned :exclude => [:trouble]
end
class SimplyVersionedTest < FixturedTestCase
def self.suite_setup
ActiveRecord::Schema.define do
create_table :aardvarks, :force => true do |t|
t.string :name
t.integer :age
end
create_table :gnus, :force => true do |t|
t.string :name
t.text :description
end
create_table :undines, :force => true do |t|
t.string :name
t.integer :married, :default => 0
end
create_table :heffalumps, :force => true do |t|
t.string :name
end
create_table :saprolings, :force => true do |t|
t.string :name
t.string :trouble
end
create_table :versions, :force => true do |t|
t.integer :versionable_id
t.string :versionable_type
t.integer :number
t.text :yaml
t.datetime :created_at
end
end
end
def self.suite_teardown
ActiveRecord::Schema.define do
drop_table :versions
drop_table :saprolings
drop_table :heffalumps
drop_table :undines
drop_table :gnus
drop_table :aardvarks
end
end
def test_should_reject_unknown_options
assert_raises SoftwareHeretics::ActiveRecord::SimplyVersioned::BadOptions do
cls = Class.new( ActiveRecord::Base ) do
simply_versioned :bogus => true
end
end
end
def test_should_start_with_empty_versions
anthony = Aardvark.new( :name => 'Anthony', :age => 35 )
assert anthony.versions.empty?
assert anthony.unversioned?
end
def test_should_be_versioned
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 )
assert anthony.versioned?
end
def test_should_get_versions
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 )
anthony.age += 1
anthony.save!
assert_equal 35, anthony.versions.get_version(1).model.age
assert_equal 35, anthony.versions.get(1).model.age
assert_equal 36, anthony.versions.get_version(2).model.age
assert_equal 36, anthony.versions.get(2).model.age
end
def test_should_version_on_create
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 )
assert_equal 1, anthony.versions.count
assert_equal 1, anthony.versions.current_version.number
assert_equal 1, anthony.versions.current.number
end
def test_should_version_on_save
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 )
anthony.age += 1
anthony.save!
assert_equal 2, anthony.versions.count
end
def test_should_trim_versions
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
anthony.age += 1
anthony.save! #v2
anthony.age += 1
anthony.save! #v3
anthony.age += 1
anthony.save! #v4 !!
assert_equal 3, anthony.versions.count
assert_equal 36, anthony.versions.first_version.model.age
assert_equal 36, anthony.versions.first.model.age
assert_equal 38, anthony.versions.current_version.model.age
assert_equal 38, anthony.versions.current.model.age
end
def test_should_revert
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
anthony.age += 1
anthony.save! #v2
anthony.revert_to_version( 1 )
assert_equal 35, anthony.age
end
def test_should_revert_except
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
anthony.name = "Tony"
anthony.age = 45
anthony.save! # v2
anthony.revert_to_version( 1, :except => [:name,:created_at,:updated_at] )
assert_equal "Tony", anthony.name
assert_equal 35, anthony.age
end
def test_should_raise_on_reversion_to_bad_version
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
anthony.name = "Tony"
anthony.age = 45
anthony.save! # v2
assert_raise RuntimeError do
anthony.revert_to_version( -1 )
end
assert_raise RuntimeError do
anthony.revert_to_version( "a" )
end
assert_raise RuntimeError do
anthony.revert_to_version( nil )
end
end
def test_should_delete_dependent_versions
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
anthony.age += 1
anthony.save! #v2
assert_difference( 'Version.count', -2 ) do
anthony.destroy
end
end
def test_should_isolate_versioned_models
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 )
gary = Gnu.create!( :name => 'Gary', :description => 'Gary the GNU' )
assert_equal 2, Version.count
assert_equal 1, anthony.versions.first.number
assert_equal 1, gary.versions.first.number
end
def test_should_be_able_to_control_versioning
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
assert_no_difference( 'anthony.versions.count' ) do
anthony.age += 1
anthony.with_versioning( false, &:save! )
end
assert_difference( 'anthony.versions.count' ) do
anthony.age += 1
anthony.with_versioning( true, &:save! )
end
end
def test_should_not_version_in_block
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
assert_no_difference( 'anthony.versions.count' ) do
anthony.age += 1
anthony.with_versioning( false ) do
anthony.save!
end
end
end
def test_should_begin_versioning_existing_record
ulrica = Undine.create!( :name => 'Ulrica' )
# Now we begin versioning this kind of record
Undine.class_eval do
simply_versioned
end
ulrica = Undine.find_by_name( 'Ulrica' )
assert ulrica.unversioned?
ulrica.update_attributes( :married => 1 )
assert !ulrica.unversioned?
assert_equal 1, ulrica.versions.size
assert_equal 1, ulrica.versions.first.model.married
end
def test_should_follow_back_and_forth
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
anthony.age += 1
anthony.save! #v2
anthony.age += 1
anthony.save!
assert_equal anthony.versions.current_version, anthony.versions.first_version.next.next
assert_equal anthony.versions.first_version, anthony.versions.current_version.previous.previous
end
def test_should_be_trustworthy_collection
anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1
anthony.age += 1
anthony.save! #v2
# Now create another record
alan = Aardvark.create!( :name => 'Alan', :age => 35 )
assert_equal 1, alan.versions.size
end
def test_should_not_delete_old_versions_by_default
ulrica = Undine.create!( :name => 'Ulrica' )
ulrica.versions.expects( :clean_old_versions ).never
100.times do
ulrica.update_attribute( :married, 1 - ulrica.married )
end
end
def test_should_not_automatically_create_versions
henry = Heffalump.create!( :name => 'Henry' )
assert_equal 0, henry.versions.count
assert_no_difference( 'henry.versions.count' ) do
henry.name = 'Harry'
henry.save!
end
end
def test_should_create_versions_on_demand
henry = Heffalump.create!( :name => 'Henry' )
assert_difference( "henry.versions.count", 1 ) do
henry.with_versioning( true, &:save )
end
end
def test_should_exclude_columns
assert_equal ["trouble"], Saproling.simply_versioned_options[:exclude]
sylvia = Saproling.create!( :name => 'Sylvia', :trouble => "big" )
yaml = YAML::load( sylvia.versions.first.yaml )
assert_equal Set.new( [ "id", "name" ] ), Set.new( yaml.keys )
end
def test_should_exclude_column_equivalent_syntax
klass = Class.new( ActiveRecord::Base )
klass.module_eval <<-DEFN
simply_versioned :exclude => :some_column
DEFN
assert_equal ['some_column'], klass.simply_versioned_options[:exclude]
end
def test_should_report_version_number
anthony = Aardvark.new( :name => 'Anthony', :age => 35 )
assert_equal 0, anthony.version_number
anthony.save!
assert_equal 1, anthony.version_number
anthony.save!
assert_equal 2, anthony.version_number # and so on
end
end

View File

@ -1,56 +0,0 @@
ENV["RAILS_ENV"] = "test"
TEST_FOLDER = File.dirname( __FILE__ )
$:.unshift( File.join( TEST_FOLDER, '..', 'lib' ) )
HOST_APP_FOLDER = File.expand_path( ENV['HOST_APP'] || File.join( TEST_FOLDER, '..', '..', '..', '..' ) )
puts "Host application: #{HOST_APP_FOLDER}"
require 'test/unit'
require File.expand_path( File.join( HOST_APP_FOLDER, 'config', 'environment.rb' ) )
require 'test_help'
require 'turn' unless ENV['NO_TURN']
ActiveRecord::Base.logger = Logger.new( File.join( TEST_FOLDER, 'test.log' ) )
ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :dbfile => File.join( TEST_FOLDER, 'test.db' ) )
class FixturedTestSuite < Test::Unit::TestSuite
def run( result, &progress_block )
@tests.first.class.__send__( :suite_setup )
yield(STARTED, name)
@tests.each do |test|
test.run(result, &progress_block)
end
yield(FINISHED, name)
@tests.first.class.__send__( :suite_teardown )
end
end
class FixturedTestCase < Test::Unit::TestCase
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
def suite_setup
end
def suite_teardown
end
# Rolls up all of the test* methods in the fixture into
# one suite, creating a new instance of the fixture for
# each method.
def self.suite
method_names = public_instance_methods(true)
tests = method_names.delete_if {|method_name| method_name !~ /^test./}
suite = FixturedTestSuite.new(name)
tests.sort.each do
|test|
catch(:invalid_test) do
suite << new(test)
end
end
return suite
end
end

View File

@ -1 +0,0 @@
# Uninstall hook code here