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:
parent
a9d5a905c0
commit
6736b69401
|
@ -0,0 +1,8 @@
|
|||
Version.class_eval do
|
||||
include PolymorphicTypeOverride
|
||||
|
||||
override_polymorphic_types versionable_type: {
|
||||
'Quiz' => 'Quizzes::Quiz',
|
||||
'QuizSubmission' => 'Quizzes::QuizSubmission'
|
||||
}
|
||||
end
|
|
@ -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
|
|
@ -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 )
|
|
@ -0,0 +1,3 @@
|
|||
module SimplyVersioned
|
||||
VERSION = "1.0.0"
|
||||
end
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
require 'simply_versioned'
|
|
@ -1 +0,0 @@
|
|||
# Install hook code here
|
|
@ -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 )
|
|
@ -1,4 +0,0 @@
|
|||
# desc "Explaining what the task does"
|
||||
# task :simply_versioned do
|
||||
# # Task goes here
|
||||
# end
|
|
@ -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 <self@mattmower.com>
|
||||
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>
|
|
@ -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>
|
|
@ -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>
|
||||
</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>
|
|
@ -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>
|
||||
</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">></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">></span> <span class="ruby-value str">'number DESC'</span>, <span class="ruby-identifier">:as</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">:versionable</span>, <span class="ruby-identifier">:dependent</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">:destroy</span>, <span class="ruby-identifier">:extend</span> =<span class="ruby-operator">></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>
|
|
@ -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>
|
||||
<a href="#M000010">simply_versioned_create_version</a>
|
||||
</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">></span> { <span class="ruby-identifier">:number</span> =<span class="ruby-operator">></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">></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>
|
|
@ -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>
|
||||
<a href="#M000004">current</a>
|
||||
<a href="#M000003">first</a>
|
||||
<a href="#M000002">get</a>
|
||||
<a href="#M000006">next</a>
|
||||
<a href="#M000007">prev</a>
|
||||
</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">></span> [ <span class="ruby-value str">'number <= ?'</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">></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">></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">></span> <span class="ruby-value str">'number ASC'</span>, <span class="ruby-identifier">:conditions</span> =<span class="ruby-operator">></span> [ <span class="ruby-value str">"number > ?"</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">></span> <span class="ruby-value str">'number DESC'</span>, <span class="ruby-identifier">:conditions</span> =<span class="ruby-operator">></span> [ <span class="ruby-value str">"number < ?"</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>
|
|
@ -1 +0,0 @@
|
|||
Sun, 30 Dec 2007 11:52:57 +0000
|
|
@ -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 <self@mattmower.com>
|
||||
</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 ‘Version’ 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‘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 < ActiveRecord::Base
|
||||
simply_versioned :keep => 10
|
||||
end
|
||||
</pre>
|
||||
</li>
|
||||
<li>Create versions
|
||||
|
||||
<pre>
|
||||
thing = Thing.create!( :foo => bar ) # creates v1
|
||||
thing.foo = baz
|
||||
thing.save! # creates v2
|
||||
</pre>
|
||||
</li>
|
||||
<li>Find versions
|
||||
|
||||
<pre>
|
||||
thing.versions.each do |version| ... end
|
||||
render :partial => 'thing_version', :collection => 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 # => Instantiated Thing with versioned values
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
Copyright (c) 2007 Matt Mower <self@mattmower.com> 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>
|
|
@ -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
|
||||
<self@mattmower.com> 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>
|
|
@ -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
|
||||
<self@mattmower.com> 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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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; }
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
# Uninstall hook code here
|
Loading…
Reference in New Issue