Skip to content

Commit

Permalink
added tests and rdocs
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.techno-weenie.net/projects/acts_as_versioned@77 567b1171-46fb-0310-a4c9-b4bef9110e78
  • Loading branch information
technoweenie committed Sep 17, 2005
1 parent 2bd26b9 commit d27c6c6
Show file tree
Hide file tree
Showing 24 changed files with 714 additions and 80 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
@@ -1,3 +1,7 @@
*0.1.1*

* Adding tests and rdocs

*0.1*

* Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974
19 changes: 19 additions & 0 deletions README
@@ -0,0 +1,19 @@
= acts_as_versioned

This library adds simple versioning to an ActiveRecord module. ActiveRecord is required.

== Download

Gem installation:

gem install acts_as_versioned --source=http://techno-weenie.net/code

Get a gzipped tar at http://techno-weenie.net/code/pkg

== Usage

RDocs are online at http://techno-weenie.net/code/doc/acts_as_versioned/. Start with the
ActiveRecord::Acts::Versioned module.

Special thanks to Dreamer on #rubyonrails for help in early testing. His ServerSideWiki (http://serversidewiki.com/)
was the first project to use acts_as_versioned <em>in the wild</em>.
41 changes: 41 additions & 0 deletions RUNNING_UNIT_TESTS
@@ -0,0 +1,41 @@
== Creating the test database

The default name for the test databases is "activerecord_versioned". If you
want to use another database name then be sure to update the connection
adapter setups you want to test with in test/connections/<your database>/connection.rb.
When you have the database online, you can import the fixture tables with
the test/fixtures/db_definitions/*.sql files.

Make sure that you create database objects with the same user that you specified in i
connection.rb otherwise (on Postgres, at least) tests for default values will fail.

== Running with Rake

The easiest way to run the unit tests is through Rake. The default task runs
the entire test suite for all the adapters. You can also run the suite on just
one adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite,
or test_postresql. For more information, checkout the full array of rake tasks with "rake -T"

Rake can be found at http://rake.rubyforge.org

== Running by hand

Unit tests are located in test directory. If you only want to run a single test suite,
or don't want to bother with Rake, you can do so with something like:

cd test; ruby -I "connections/native_mysql" base_test.rb

That'll run the base suite using the MySQL-Ruby adapter. Change the adapter
and test suite name as needed.

== Faster tests

If you are using a database that supports transactions, you can set the
"AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures.
This gives a very large speed boost. With rake:

rake AR_TX_FIXTURES=yes

Or, by hand:

AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb
66 changes: 66 additions & 0 deletions Rakefile
@@ -0,0 +1,66 @@
require 'rubygems'

Gem::manage_gems

require 'rake/rdoctask'
require 'rake/packagetask'
require 'rake/gempackagetask'
require 'rake/testtask'
require 'rake/contrib/rubyforgepublisher'

PKG_NAME = 'acts_as_versioned'
PKG_VERSION = '0.1.1'
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
PROD_HOST = "technoweenie@bidwell.textdrive.com"

for adapter in %w( mysql postgresql sqlite sqlite3 sqlserver sqlserver_odbc db2 oci )
Rake::TestTask.new("test_#{adapter}") do |t|
t.libs << "test" << "test/connections/native_#{adapter}"
t.pattern = "test/*_test{,_#{adapter}}.rb"
t.verbose = true
end
end

Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = 'doc'
rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models"
rdoc.options << '--line-numbers --inline-source --accessor cattr_accessor=object'
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
rdoc.rdoc_files.include('RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
end

spec = Gem::Specification.new do |s|
s.name = PKG_NAME
s.version = PKG_VERSION
s.platform = Gem::Platform::RUBY
s.summary = "Simple versioning with active record models"
s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS)
s.files.delete "test/fixtures/activerecord_versioned.sqlite"
s.files.delete "test/fixtures/activerecord_versioned.sqlite3"
s.require_path = 'lib'
s.autorequire = 'acts_as_versioned'
s.has_rdoc = true
s.test_file = 'test/tests.rb'
s.add_dependency 'activerecord', '>= 1.10.1'
s.add_dependency 'activesupport', '>= 1.1.1'
s.author = "Rick Olson"
s.email = "technoweenie@gmail.com"
s.homepage = "http://techno-weenie.net"
end

Rake::GemPackageTask.new(spec) do |pkg|
pkg.need_tar = true
end

desc "Publish the beta gem"
task :pgem => [:package] do
Rake::SshFilePublisher.new(PROD_HOST, "public_html/code/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
Rake::SshFilePublisher.new(PROD_HOST, "public_html/code/pkg", "pkg", "#{PKG_FILE_NAME}.tgz").upload
%x{ssh #{PROD_HOST} 'update_gems'}
end

desc "Publish the API documentation"
task :pdoc => [:rdoc] do
Rake::SshDirPublisher.new(PROD_HOST, "public_html/code/doc/acts_as_versioned", "doc").upload
end
19 changes: 0 additions & 19 deletions acts_as_versioned.gemspec

This file was deleted.

155 changes: 95 additions & 60 deletions lib/acts_as_versioned.rb
@@ -1,57 +1,59 @@
#Copyright (c) 2005 Rick Olson
#
#Permission is hereby granted, free of charge, to any person obtaining
#a copy of this software and associated documentation files (the
#"Software"), to deal in the Software without restriction, including
#without limitation the rights to use, copy, modify, merge, publish,
#distribute, sublicense, and/or sell copies of the Software, and to
#permit persons to whom the Software is furnished to do so, subject to
#the following conditions:
#
#The above copyright notice and this permission notice shall be
#included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
#LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
#OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
#WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Copyright (c) 2005 Rick Olson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

module ActiveRecord
module ActiveRecord #:nodoc:
module Acts #:nodoc:
module Versioned #:nodoc:
# Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a
# versioned table ready and that your model has a version field. This works with optimisic locking if the lock_version
# column is present as well.
#
# class Page < ActiveRecord::Base
# # assumes pages_versions table
# acts_as_versioned
# end
#
# Example:
#
# page = Page.create(:title => 'hello world!')
# page.version # => 1
#
# page.title = 'hello world'
# page.save
# page.version # => 2
# page.versions.size # => 2
#
# page.revert_to(1) # using version number
# page.title # => 'hello world!'
#
# page.revert_to(page.versions.last) # using versioned instance
# page.title # => 'hello world'
#
# See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options
module Versioned
def self.included(base) # :nodoc:
base.extend ClassMethods
end

# Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a
# versioned table ready and that your model has a version field. This works with optimisic locking if the lock_version
# column is present as well.
#
# class Page < ActiveRecord::Base
# # assumes pages_versions table
# acts_as_versioned
# end
#
# Example:
#
# page = Page.create(:title => 'hello world!')
# page.version # => 1
#
# page.title = 'hello world'
# page.save
# page.version # => 2
# page.versions.size # => 2
#
# page.revert_to(1) # using version number
# page.title # => 'hello world!'
#
# page.revert_to(page.versions.last) # using versioned instance
# page.title # => 'hello world'
module ClassMethods
# Configuration options are:
# == Configuration options
#
# * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)
# * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)
Expand All @@ -60,20 +62,44 @@ module ClassMethods
# * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)
# * <tt>limit</tt> - number of revisions to keep, defaults to unlimited
# * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved.
# For finer control, pass either a Proc or modify Model#version_condition_met?
# For finer control, pass either a Proc or modify Model#version_condition_met?
#
# acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
# acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
#
# or...
# or...
#
# class Auction
# def version_condition_met? # totally bypasses the <tt>:if</tt> option
# !expired?
# end
# end
# class Auction
# def version_condition_met? # totally bypasses the <tt>:if</tt> option
# !expired?
# end
# end
#
# * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes
# either a symbol or array of symbols.
# either a symbol or array of symbols.
#
# == Database Schema
#
# The model that you're versioning needs to have a 'version' attribute. The model is versioned
# into a table called #{model}_versions where the model name is singlular. The _versions table should
# contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
#
# A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance,
# then that field is reflected in the versioned model as 'versioned_type' by default.
#
# Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table
# method, perfect for a migration. It will also create the version column if the main model does not already have it.
#
# class AddVersions < ActiveRecord::Migration
# def self.up
# # create_versioned_table takes the same options hash
# # that create_table does
# Post.create_versioned_table
# end
#
# def self.down
# Post.drop_versioned_table
# end
# end
def acts_as_versioned(options = {})
# don't allow multiple calls
return if defined?(self.versioned_class_name)
Expand Down Expand Up @@ -262,17 +288,26 @@ def clear_changed_attributes
unless defined?(ACTS_AS_VERSIONED_CALLBACKS)
ACTS_AS_VERSIONED_CALLBACKS = [:set_new_version, :save_version_on_create, :save_version, :clear_changed_attributes]
end

ACTS_AS_VERSIONED_CALLBACKS.each do |attr_name|
alias_method "orig_#{attr_name}".to_sym, attr_name
end

ACTS_AS_VERSIONED_CALLBACKS.each { |attr_name| alias_method "orig_#{attr_name}".to_sym, attr_name }
def empty_callback() end
def empty_callback() end #:nodoc:

def enable_acts_as_versioned_callbacks
self.class.class_eval do
ACTS_AS_VERSIONED_CALLBACKS.each { |attr_name| alias_method attr_name, "orig_#{attr_name}".to_sym }
ACTS_AS_VERSIONED_CALLBACKS.each do |attr_name|
alias_method attr_name, "orig_#{attr_name}".to_sym
end
end
end

def disable_acts_as_versioned_callbacks
self.class.class_eval do
ACTS_AS_VERSIONED_CALLBACKS.each { |attr_name| alias_method attr_name, :empty_callback }
ACTS_AS_VERSIONED_CALLBACKS.each do |attr_name|
alias_method attr_name, :empty_callback
end
end
end

Expand Down
25 changes: 25 additions & 0 deletions test/abstract_unit.rb
@@ -0,0 +1,25 @@
$:.unshift(File.dirname(__FILE__) + '/../lib')

require 'rubygems'
require 'test/unit'
require 'active_record'
require 'active_record/fixtures'
require 'active_support/binding_of_caller'
require 'active_support/breakpoint'
require 'connection'
require 'acts_as_versioned'

class Test::Unit::TestCase #:nodoc:
def create_fixtures(*table_names)
if block_given?
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names) { yield }
else
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names)
end
end
end

Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
Test::Unit::TestCase.use_instantiated_fixtures = false
Test::Unit::TestCase.use_transactional_fixtures = (ENV['AR_TX_FIXTURES'] == "yes")

Binary file added test/fixtures/activerecord_versioned.sqlite
Binary file not shown.
Binary file added test/fixtures/activerecord_versioned.sqlite3
Binary file not shown.
4 changes: 4 additions & 0 deletions test/fixtures/db_definitions/mysql.drop.sql
@@ -0,0 +1,4 @@
DROP TABLE pages;
DROP TABLE page_versions;
DROP TABLE locked_pages;
DROP TABLE locked_pages_revisions;

0 comments on commit d27c6c6

Please sign in to comment.