auditrail 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: "1"
@@ -0,0 +1,3 @@
1
+ **/*.swp
2
+ **/*.DS_Store
3
+ spec/tmp
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2@auditrail --create
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in auditrail.gemspec
4
+ gemspec
@@ -0,0 +1,73 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ auditrail (0.0.1)
5
+ activerecord (~> 3.0.1)
6
+ railties (~> 3.0.1)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ abstract (1.0.0)
12
+ actionpack (3.0.3)
13
+ activemodel (= 3.0.3)
14
+ activesupport (= 3.0.3)
15
+ builder (~> 2.1.2)
16
+ erubis (~> 2.6.6)
17
+ i18n (~> 0.4)
18
+ rack (~> 1.2.1)
19
+ rack-mount (~> 0.6.13)
20
+ rack-test (~> 0.5.6)
21
+ tzinfo (~> 0.3.23)
22
+ activemodel (3.0.3)
23
+ activesupport (= 3.0.3)
24
+ builder (~> 2.1.2)
25
+ i18n (~> 0.4)
26
+ activerecord (3.0.3)
27
+ activemodel (= 3.0.3)
28
+ activesupport (= 3.0.3)
29
+ arel (~> 2.0.2)
30
+ tzinfo (~> 0.3.23)
31
+ activesupport (3.0.3)
32
+ arel (2.0.6)
33
+ builder (2.1.2)
34
+ diff-lcs (1.1.2)
35
+ erubis (2.6.6)
36
+ abstract (>= 1.0.0)
37
+ i18n (0.5.0)
38
+ rack (1.2.1)
39
+ rack-mount (0.6.13)
40
+ rack (>= 1.0.0)
41
+ rack-test (0.5.6)
42
+ rack (>= 1.0)
43
+ railties (3.0.3)
44
+ actionpack (= 3.0.3)
45
+ activesupport (= 3.0.3)
46
+ rake (>= 0.8.7)
47
+ thor (~> 0.14.4)
48
+ rake (0.8.7)
49
+ rspec (2.0.1)
50
+ rspec-core (~> 2.0.1)
51
+ rspec-expectations (~> 2.0.1)
52
+ rspec-mocks (~> 2.0.1)
53
+ rspec-core (2.0.1)
54
+ rspec-expectations (2.0.1)
55
+ diff-lcs (>= 1.1.2)
56
+ rspec-mocks (2.0.1)
57
+ rspec-core (~> 2.0.1)
58
+ rspec-expectations (~> 2.0.1)
59
+ rspec-rails (2.0.1)
60
+ rspec (~> 2.0.0)
61
+ sqlite3-ruby (1.3.2)
62
+ thor (0.14.6)
63
+ tzinfo (0.3.23)
64
+
65
+ PLATFORMS
66
+ ruby
67
+
68
+ DEPENDENCIES
69
+ activerecord (~> 3.0.1)
70
+ auditrail!
71
+ railties (~> 3.0.1)
72
+ rspec-rails (~> 2.0.1)
73
+ sqlite3-ruby
@@ -0,0 +1,93 @@
1
+ # auditrail
2
+ An easy and unobtrusive way to track changes on Active Record models.
3
+
4
+
5
+ ## How it works
6
+ This will generate a table named **audits**. **auditrail** will save an *audit entry* each time
7
+ an *audited model* changes.
8
+
9
+ You can find an example application that shows how to use **auditrail**
10
+ [here](https://github.com/MGalv/auditrails_test_app).
11
+
12
+
13
+ ## Installing
14
+ It has only been tested on rails3, in order to install it do:
15
+
16
+ gem install auditrail
17
+
18
+
19
+ ## Usage
20
+ First run the generator to create the *audits* table:
21
+
22
+ rails g auditrail:create
23
+
24
+ That will create a migration. Now Simply add *auditable* to your models like this:
25
+
26
+ class User < ActiveRecord::Base
27
+ auditable
28
+ end
29
+
30
+
31
+ ### Options
32
+ You can define parameter options with a block.
33
+
34
+ #### for_attributes
35
+ Using *for_attributes* you select the fields that you want to be audited. For example:
36
+
37
+ auditable do
38
+ for_attributes "name", "email"
39
+ end
40
+
41
+ This will create an *audit entry* by each time that the fields *name* or *email* change.
42
+
43
+ #### by_user
44
+ Using *by_user* you control who was the *action invoker* or *fields modifier*:
45
+
46
+ auditable do
47
+ by_user "user"
48
+ end
49
+
50
+ Also, you can call the method *by_user* with a block as parameter. For example:
51
+
52
+ auditable do
53
+ by_user do
54
+ "user"
55
+ end
56
+ end
57
+
58
+ This way you may dynamically control what will be saved as the *action invoker* or
59
+ *fields modifier*.
60
+
61
+
62
+ # Development
63
+ If you want to make changes to the gem, then fork it, and first install bundler:
64
+
65
+ gem install bundler
66
+
67
+ Afterwards, install the bundle:
68
+
69
+ bundle install
70
+
71
+
72
+ ## Running the test suite
73
+ Simply run:
74
+
75
+ rake
76
+
77
+
78
+ # Changelog
79
+ Nothing yet.
80
+
81
+
82
+ # To Do
83
+ * Refactor auditrail.rb and its tests.
84
+ * Let the implementor configure where to store the audits.
85
+ * What the audit table name will be.
86
+
87
+ # About the Author
88
+ [Crowd Interactive](http://www.crowdint.com) is an American web design and development
89
+ company that happens to work in Colima, Mexico. We specialize in building and growing
90
+ online retail stores. We don’t work with everyone – just companies we believe in. Call
91
+ us today to see if there’s a fit.
92
+
93
+ Find more info [here](http://www.crowdint.com)!
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc "Run all examples"
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.rspec_path = 'rspec'
9
+ t.rspec_opts = %w[--color]
10
+ end
11
+
12
+ task :default => :spec
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "auditrail/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "auditrail"
7
+ s.version = Auditrail::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Luis Galaviz", "Emmanuel Delgado"]
10
+ s.email = ["emmanuel@crowdint.com", "luis.galaviz@crowdint.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Audits models using serialization}
13
+ s.description = %q{Audits models using serialization}
14
+
15
+ s.rubyforge_project = "auditrail"
16
+ s.add_dependency("activerecord", "~> 3.0.1")
17
+ s.add_dependency("railties", "~> 3.0.1")
18
+ s.add_development_dependency("rspec-rails", "~> 2.0.1")
19
+ s.add_development_dependency("sqlite3-ruby")
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,85 @@
1
+ require 'active_record'
2
+ require 'active_support/concern'
3
+ require 'yaml'
4
+ require 'generators/migrations'
5
+ require 'generators/model'
6
+
7
+ module Auditrail
8
+
9
+ extend ActiveSupport::Concern
10
+
11
+ module ClassMethods
12
+
13
+ class AuditOptions
14
+
15
+ def initialize(&block)
16
+ instance_eval &block if block
17
+ end
18
+
19
+ def user
20
+ @user
21
+ end
22
+
23
+ def attributes
24
+ @attributes
25
+ end
26
+
27
+ private
28
+ def by_user(user = nil, &block)
29
+ @user = block ? block.call : user
30
+ end
31
+
32
+ def for_attributes(*attributes)
33
+ @attributes = attributes
34
+ end
35
+
36
+ end
37
+
38
+ def auditable(&block)
39
+ audit_options = block ? AuditOptions.new(&block) : AuditOptions.new
40
+
41
+ class_eval do
42
+ before_create do
43
+ track_changes(:creating, audit_options.user) if attributes_changed?(*audit_options.attributes)
44
+ end
45
+
46
+ before_update do
47
+ track_changes(:updating, audit_options.user) if attributes_changed?(*audit_options.attributes)
48
+ end
49
+
50
+ after_save do
51
+ save_tracked_changes if attributes_changed?(*audit_options.attributes)
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ module InstanceMethods
60
+
61
+ private
62
+ def attributes_changed?(*options)
63
+ (options - changes.keys) != options || options.empty?
64
+ end
65
+
66
+
67
+ def track_changes(*options)
68
+ action = options[0]
69
+ @audit = Audit.new
70
+ @audit.dumped_changes = YAML.dump(changes)
71
+ @audit.model_changed = self.class
72
+ @audit.action = action
73
+ @audit.invoker = YAML.dump(options[1])
74
+ end
75
+
76
+ def save_tracked_changes
77
+ @audit.element_id = id
78
+ @audit.save
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ ActiveRecord::Base.send(:include, Auditrail)
@@ -0,0 +1,3 @@
1
+ module Auditrail
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,16 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/active_record'
3
+
4
+ module Auditrail
5
+ module Generators
6
+ class MigrationsGenerator < Rails::Generators::Base
7
+ source_root File.expand_path("templates", File.dirname(__FILE__))
8
+
9
+ def prepare
10
+ migrations_dir = File.join("db", "migrate")
11
+ file_name = ::ActiveRecord::Generators::Base.next_migration_number(migrations_dir)
12
+ copy_file("audits_table.rb", File.join(migrations_dir, "#{file_name.to_s}_create_audits.rb"))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/active_record'
3
+
4
+ module Auditrail
5
+ module Generators
6
+ class ModelGenerator < Rails::Generators::Base
7
+ source_root File.expand_path("templates", File.dirname(__FILE__))
8
+
9
+ def prepare
10
+ copy_file("audit_model.rb", File.join("app", "models", "audit.rb"))
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ require 'yaml'
2
+
3
+ class Audit < ActiveRecord::Base
4
+ def action_invoker
5
+ YAML.load(invoker)
6
+ end
7
+
8
+ def self.model_filter(model_changed)
9
+ where("model_changed = ?", model_changed.to_s.camelize)
10
+ end
11
+
12
+ def self.action_filter(action)
13
+ where("action = ?", action.to_s)
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ class CreateAudits < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :audits do |t|
4
+ t.string :dumped_changes
5
+ t.string :action
6
+ t.string :model_changed
7
+ t.integer :element_id
8
+ t.string :invoker
9
+
10
+ t.timestamps
11
+ end
12
+ end
13
+
14
+ def self.down
15
+ drop_table :audits
16
+ end
17
+ end
@@ -0,0 +1,155 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'support/active_record'
4
+
5
+ describe 'A test class' do
6
+ include Auditrail::Test::ActiveRecord
7
+
8
+ before do
9
+ connection_open
10
+ generate_migration
11
+ migrate
12
+
13
+ # the blocked passed to auditable will determine the action invoker
14
+ # that will be serialized
15
+ @test_class.class_eval do
16
+ auditable do
17
+ # When using the options by_user you can also pass the parameters as a block.
18
+ # by_user 465
19
+ # or
20
+ # by_user do
21
+ # 465
22
+ # end
23
+
24
+ by_user 465
25
+ end
26
+ end
27
+ end
28
+
29
+ after do
30
+ clean_tmp_path
31
+ connection_close
32
+ end
33
+
34
+ context 'its class should be auditable' do
35
+ it 'contains an auditable method' do
36
+ @test_class.should respond_to(:auditable)
37
+ end
38
+ end
39
+
40
+ context 'basic Audit behavior' do
41
+
42
+ before do
43
+ @test_class.create(:name => "Text")
44
+ end
45
+
46
+ context 'creates a new object' do
47
+
48
+ it "should track the changes in the Test object" do
49
+ audit_changes = @audit_class.first.dumped_changes
50
+ changes_hash = YAML.load(audit_changes)
51
+ changes_hash["name"][0].should eq(nil)
52
+ changes_hash["name"][1].should eq("Text")
53
+ end
54
+
55
+ it "should receive a creating status" do
56
+ @audit_class.first.action.should eq("creating")
57
+ end
58
+
59
+ it "should save the model name of the audited object" do
60
+ @audit_class.first.model_changed.should eq("Test")
61
+ end
62
+
63
+ it 'should save the id of the original affected object' do
64
+ instance = @test_class.first
65
+ @audit_class.first.element_id.should eq(instance.id)
66
+ end
67
+
68
+ it 'should return the action invoker' do
69
+ @audit_class.first.action_invoker.should eq(465)
70
+ end
71
+
72
+ end
73
+
74
+ context 'updates an existing object' do
75
+ it "should receive a creating status" do
76
+ instance = @test_class.first
77
+ instance.name = "Text change"
78
+ instance.save
79
+ @audit_class.last.action.should eq("updating")
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ context "basic query content behavior" do
86
+
87
+ before do
88
+ @user_class.class_eval do
89
+ auditable
90
+ end
91
+ 10.times do
92
+ @test_class.create(:name => "Text")
93
+ end
94
+
95
+ 5.times do |item_number|
96
+ @user_class.create(:name => "User #{item_number}", :age => 15 + item_number, :email => "abc#{item_number}@abc.com")
97
+ end
98
+ end
99
+
100
+ it "should find the audits by model" do
101
+ @audit_class.model_filter(:user).should have_exactly(5).items
102
+ @audit_class.model_filter(:test).should have_exactly(10).items
103
+ @audit_class.model_filter(:admin).should have_exactly(0).items
104
+ end
105
+
106
+ it "should find the audits by action" do
107
+ 5.times do |item_number|
108
+ test = @test_class.first
109
+ test.name = "Text changed #{item_number}"
110
+ test.save
111
+ end
112
+
113
+ 3.times do |item_number|
114
+ user = @user_class.first
115
+ user.name = "User 1 name changed #{item_number}"
116
+ user.save
117
+ end
118
+
119
+ @audit_class.action_filter(:creating).should have_exactly(15).items
120
+ @audit_class.action_filter(:updating).should have_exactly(8).items
121
+ @audit_class.action_filter(:other).should have_exactly(0).items
122
+ end
123
+ end
124
+
125
+ context "track changes only for selected attributes" do
126
+ before do
127
+ @user_class.class_eval do
128
+ auditable do
129
+ for_attributes "name", "email"
130
+ end
131
+ end
132
+ @user_class.create(:name => "Marco", :age => 15, :email => "marco@abc.com")
133
+ end
134
+
135
+ it "should track only for name and email" do
136
+ user = @user_class.first
137
+ user.name = "Polo"
138
+ user.save
139
+
140
+ user = @user_class.first
141
+ user.email = "polo@abc.com"
142
+ user.save
143
+
144
+ @audit_class.all.should have_exactly(3).items
145
+ end
146
+
147
+ it "should not track changes for age" do
148
+ user = @user_class.first
149
+ user.age = 16
150
+ user.save
151
+
152
+ @audit_class.all.should have_exactly(1).items
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'support/active_record'
3
+
4
+ describe Auditrail::Generators::MigrationsGenerator do
5
+ include Auditrail::Test::ActiveRecord
6
+
7
+ before {generate_migration}
8
+
9
+ after {clean_tmp_path}
10
+
11
+ it "should generate the migration for the audits tabble into the db/migrate folder" do
12
+ Dir.glob(File.join(File.expand_path(File.join(DESTINATION, "db", "migrate")), "*_create_audits.rb")).should have_exactly(1).items
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'support/active_record'
3
+
4
+ describe Auditrail::Generators::ModelGenerator do
5
+ include Auditrail::Test::ActiveRecord
6
+
7
+ before { generate_model }
8
+
9
+ after {clean_tmp_path}
10
+
11
+ it "should generate the Audit model" do
12
+ file = File.expand_path(File.join(DESTINATION, "app", "models", "audit.rb"))
13
+ File.exist?(file).should be(true)
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ $:.unshift File.join(File.dirname(__FILE__))
2
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'auditrail'
5
+ require 'generators/migrations'
6
+ require 'generators/model'
7
+ require 'rails'
8
+ require 'fileutils'
9
+ require 'rake'
10
+
11
+ ENV["RAILS_ENV"] = "test"
12
+ ENV["RAILS_ROOT"] = "tmp"
13
+ DESTINATION = File.expand_path(File.join("spec","tmp"))
14
+ ENV['SCHEMA'] = File.join(DESTINATION, "db", "schema.rb")
15
+
16
+ module Auditrail
17
+ class Application < Rails::Application; end
18
+ end
@@ -0,0 +1,62 @@
1
+ require 'active_record'
2
+
3
+ module Auditrail
4
+ module Test
5
+ module ActiveRecord
6
+
7
+ def migrate
8
+ rake_app = Rake::Application.new
9
+ Rake.application = rake_app
10
+ Rake.application.rake_require File.join("active_record", "railties", "databases")
11
+ Rake::Task.define_task(:environment)
12
+
13
+ ::ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
14
+ ::ActiveRecord::Migrator.migrate(File.join(DESTINATION, "db", "migrate"), ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
15
+ rake_app["db:migrate"].invoke if ::ActiveRecord::Base.schema_format == :ruby
16
+ generate_model
17
+ load File.join(DESTINATION, 'app', 'models', 'audit.rb')
18
+ @audit_class = ::Audit
19
+ end
20
+
21
+ def connection_open
22
+ #::ActiveRecord::Base.logger = Logger.new(STDOUT)
23
+ ::ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
24
+ ::ActiveRecord::Schema.define(:version => 1) do
25
+ create_table :tests do |t|
26
+ t.string :name
27
+ end
28
+
29
+ create_table :users do |t|
30
+ t.string :name
31
+ t.string :email
32
+ t.integer :age
33
+ end
34
+ end
35
+
36
+ @test_class = Object.const_set(:Test, Class.new(::ActiveRecord::Base))
37
+ @user_class = Object.const_set(:User, Class.new(::ActiveRecord::Base))
38
+ end
39
+
40
+ def connection_close
41
+ Object.send(:remove_const, :Test)
42
+ Object.send(:remove_const, :User)
43
+ ::ActiveRecord::Base.connection.tables.each do |table|
44
+ ::ActiveRecord::Base.connection.drop_table(table)
45
+ end
46
+ end
47
+
48
+ def clean_tmp_path
49
+ FileUtils.rm_rf(DESTINATION)
50
+ end
51
+
52
+ def generate_migration
53
+ Auditrail::Generators::MigrationsGenerator.start([] , :destination_root => DESTINATION)
54
+ end
55
+
56
+ def generate_model
57
+ Auditrail::Generators::ModelGenerator.start([] , :destination_root => DESTINATION)
58
+ end
59
+
60
+ end
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: auditrail
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Luis Galaviz
13
+ - Emmanuel Delgado
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-22 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 3
31
+ - 0
32
+ - 1
33
+ version: 3.0.1
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: railties
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ segments:
45
+ - 3
46
+ - 0
47
+ - 1
48
+ version: 3.0.1
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: rspec-rails
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 2
61
+ - 0
62
+ - 1
63
+ version: 2.0.1
64
+ type: :development
65
+ version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ name: sqlite3-ruby
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ type: :development
78
+ version_requirements: *id004
79
+ description: Audits models using serialization
80
+ email:
81
+ - emmanuel@crowdint.com
82
+ - luis.galaviz@crowdint.com
83
+ executables: []
84
+
85
+ extensions: []
86
+
87
+ extra_rdoc_files: []
88
+
89
+ files:
90
+ - .bundle/config
91
+ - .gitignore
92
+ - .rvmrc
93
+ - Gemfile
94
+ - Gemfile.lock
95
+ - README.md
96
+ - Rakefile
97
+ - auditrail.gemspec
98
+ - lib/auditrail.rb
99
+ - lib/auditrail/version.rb
100
+ - lib/generators/migrations.rb
101
+ - lib/generators/model.rb
102
+ - lib/generators/templates/audit_model.rb
103
+ - lib/generators/templates/audits_table.rb
104
+ - spec/auditrail_spec.rb
105
+ - spec/migrations_spec.rb
106
+ - spec/model_generator_spec.rb
107
+ - spec/spec_helper.rb
108
+ - spec/support/active_record.rb
109
+ has_rdoc: true
110
+ homepage: ""
111
+ licenses: []
112
+
113
+ post_install_message:
114
+ rdoc_options: []
115
+
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ requirements: []
135
+
136
+ rubyforge_project: auditrail
137
+ rubygems_version: 1.3.7
138
+ signing_key:
139
+ specification_version: 3
140
+ summary: Audits models using serialization
141
+ test_files: []
142
+