acts_as_versioned 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ *0.1.2*
2
+
3
+ * check if module is already included when acts_as_versioned is called
4
+
5
+ *0.1.1*
6
+
7
+ * Adding tests and rdocs
8
+
9
+ *0.1*
10
+
11
+ * Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2005 Rick Olson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,19 @@
1
+ = acts_as_versioned
2
+
3
+ This library adds simple versioning to an ActiveRecord module. ActiveRecord is required.
4
+
5
+ == Download
6
+
7
+ Gem installation:
8
+
9
+ gem install acts_as_versioned --source=http://techno-weenie.net/code
10
+
11
+ Get a gzipped tar at http://techno-weenie.net/code/pkg
12
+
13
+ == Usage
14
+
15
+ RDocs are online at http://techno-weenie.net/code/doc/acts_as_versioned/. Start with the
16
+ ActiveRecord::Acts::Versioned module.
17
+
18
+ Special thanks to Dreamer on ##rubyonrails for help in early testing. His ServerSideWiki (http://serversidewiki.com)
19
+ was the first project to use acts_as_versioned <em>in the wild</em>.
@@ -0,0 +1,41 @@
1
+ == Creating the test database
2
+
3
+ The default name for the test databases is "activerecord_versioned". If you
4
+ want to use another database name then be sure to update the connection
5
+ adapter setups you want to test with in test/connections/<your database>/connection.rb.
6
+ When you have the database online, you can import the fixture tables with
7
+ the test/fixtures/db_definitions/*.sql files.
8
+
9
+ Make sure that you create database objects with the same user that you specified in i
10
+ connection.rb otherwise (on Postgres, at least) tests for default values will fail.
11
+
12
+ == Running with Rake
13
+
14
+ The easiest way to run the unit tests is through Rake. The default task runs
15
+ the entire test suite for all the adapters. You can also run the suite on just
16
+ one adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite,
17
+ or test_postresql. For more information, checkout the full array of rake tasks with "rake -T"
18
+
19
+ Rake can be found at http://rake.rubyforge.org
20
+
21
+ == Running by hand
22
+
23
+ Unit tests are located in test directory. If you only want to run a single test suite,
24
+ or don't want to bother with Rake, you can do so with something like:
25
+
26
+ cd test; ruby -I "connections/native_mysql" base_test.rb
27
+
28
+ That'll run the base suite using the MySQL-Ruby adapter. Change the adapter
29
+ and test suite name as needed.
30
+
31
+ == Faster tests
32
+
33
+ If you are using a database that supports transactions, you can set the
34
+ "AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures.
35
+ This gives a very large speed boost. With rake:
36
+
37
+ rake AR_TX_FIXTURES=yes
38
+
39
+ Or, by hand:
40
+
41
+ AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb
@@ -0,0 +1,373 @@
1
+ # Copyright (c) 2005 Rick Olson
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ module ActiveRecord #:nodoc:
23
+ module Acts #:nodoc:
24
+ # Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a
25
+ # versioned table ready and that your model has a version field. This works with optimisic locking if the lock_version
26
+ # column is present as well.
27
+ #
28
+ # class Page < ActiveRecord::Base
29
+ # # assumes pages_versions table
30
+ # acts_as_versioned
31
+ # end
32
+ #
33
+ # Example:
34
+ #
35
+ # page = Page.create(:title => 'hello world!')
36
+ # page.version # => 1
37
+ #
38
+ # page.title = 'hello world'
39
+ # page.save
40
+ # page.version # => 2
41
+ # page.versions.size # => 2
42
+ #
43
+ # page.revert_to(1) # using version number
44
+ # page.title # => 'hello world!'
45
+ #
46
+ # page.revert_to(page.versions.last) # using versioned instance
47
+ # page.title # => 'hello world'
48
+ #
49
+ # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options
50
+ module Versioned
51
+ def self.included(base) # :nodoc:
52
+ base.extend ClassMethods
53
+ end
54
+
55
+ module ClassMethods
56
+ # == Configuration options
57
+ #
58
+ # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)
59
+ # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)
60
+ # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example)
61
+ # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type)
62
+ # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)
63
+ # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited
64
+ # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved.
65
+ # For finer control, pass either a Proc or modify Model#version_condition_met?
66
+ #
67
+ # acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
68
+ #
69
+ # or...
70
+ #
71
+ # class Auction
72
+ # def version_condition_met? # totally bypasses the <tt>:if</tt> option
73
+ # !expired?
74
+ # end
75
+ # end
76
+ #
77
+ # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes
78
+ # either a symbol or array of symbols.
79
+ #
80
+ # == Database Schema
81
+ #
82
+ # The model that you're versioning needs to have a 'version' attribute. The model is versioned
83
+ # into a table called #{model}_versions where the model name is singlular. The _versions table should
84
+ # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
85
+ #
86
+ # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance,
87
+ # then that field is reflected in the versioned model as 'versioned_type' by default.
88
+ #
89
+ # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table
90
+ # method, perfect for a migration. It will also create the version column if the main model does not already have it.
91
+ #
92
+ # class AddVersions < ActiveRecord::Migration
93
+ # def self.up
94
+ # # create_versioned_table takes the same options hash
95
+ # # that create_table does
96
+ # Post.create_versioned_table
97
+ # end
98
+ #
99
+ # def self.down
100
+ # Post.drop_versioned_table
101
+ # end
102
+ # end
103
+ def acts_as_versioned(options = {})
104
+ # don't allow multiple calls
105
+ return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods)
106
+
107
+ class_eval do
108
+ include ActiveRecord::Acts::Versioned::ActMethods
109
+ cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,
110
+ :version_column, :max_version_limit, :track_changed_attributes, :version_condition
111
+ attr_accessor :changed_attributes
112
+ end
113
+
114
+ self.versioned_class_name = options[:class_name] || "#{self.to_s.demodulize}Version"
115
+ self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key
116
+ self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{Inflector.underscore(Inflector.demodulize(class_name_of_active_record_descendant(self)))}_versions#{table_name_suffix}"
117
+ self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
118
+ self.version_column = options[:version_column] || 'version'
119
+ self.max_version_limit = options[:limit].to_i
120
+ self.version_condition = options[:if] || true
121
+
122
+ class_eval do
123
+ has_many :versions,
124
+ :class_name => "ActiveRecord::Acts::Versioned::#{versioned_class_name}",
125
+ :foreign_key => "#{versioned_foreign_key}",
126
+ :order => 'version'
127
+ before_save :set_new_version
128
+ after_create :save_version_on_create
129
+ after_update :save_version
130
+ after_save :clear_old_versions
131
+ after_save :clear_changed_attributes
132
+
133
+ unless options[:if_changed].nil?
134
+ self.track_changed_attributes = true
135
+ options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)
136
+ options[:if_changed].each do |attr_name|
137
+ define_method("#{attr_name}=") do |value|
138
+ (self.changed_attributes ||= []) << attr_name.to_s unless self.dirty?(attr_name) or self.send(attr_name) == value
139
+ write_attribute(attr_name.to_s, value)
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ # create the dynamic versioned model
146
+ eval <<-EOV
147
+ class ActiveRecord::Acts::Versioned::#{versioned_class_name} < ActiveRecord::Base
148
+ set_table_name "#{versioned_table_name}"
149
+ belongs_to :#{self.to_s.demodulize.underscore}, :class_name => "#{self.to_s}"
150
+ end
151
+ EOV
152
+ end
153
+ end
154
+
155
+ module ActMethods
156
+ def self.included(base) # :nodoc:
157
+ base.extend ClassMethods
158
+ end
159
+
160
+ # Saves a version of the model if applicable
161
+ def save_version
162
+ save_version_on_create if save_version?
163
+ end
164
+
165
+ # Saves a version of the model in the versioned table. This is called in the after_save callback by default
166
+ def save_version_on_create
167
+ rev = self.class.versioned_class.new
168
+ self.clone_versioned_model(self, rev)
169
+ rev.version = send(self.class.version_column)
170
+ rev.send("#{self.class.versioned_foreign_key}=", self.id)
171
+ rev.save
172
+ end
173
+
174
+ # Clears old revisions if a limit is set with the :limit option in <tt>acts_as_versioned</tt>.
175
+ # Override this method to set your own criteria for clearing old versions.
176
+ def clear_old_versions
177
+ return if self.class.max_version_limit.blank?
178
+ excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit
179
+ if excess_baggage > 0
180
+ sql = "DELETE FROM #{self.class.versioned_table_name} WHERE version <= #{excess_baggage} AND #{self.class.versioned_foreign_key} = #{self.id}"
181
+ self.class.versioned_class.connection.execute sql
182
+ end
183
+ end
184
+
185
+ # Finds a specific version of this model.
186
+ def find_version(version)
187
+ return version if version.is_a?(self.class.versioned_class)
188
+ return nil if version.is_a?(ActiveRecord::Base)
189
+ find_versions(:conditions => ['version = ?', version], :limit => 1).first
190
+ end
191
+
192
+ # Finds versions of this model. Takes an options hash like <tt>find</tt>
193
+ def find_versions(options = {})
194
+ versions.find(:all, {:order => 'version'}.merge(options))
195
+ end
196
+
197
+ # Reverts a model to a given version. Takes either a version number or an instance of the versioned model
198
+ def revert_to(version)
199
+ if version.is_a?(self.class.versioned_class)
200
+ return false unless version.send(self.class.versioned_foreign_key) == self.id and !version.new_record?
201
+ else
202
+ return false unless version = find_version(version)
203
+ end
204
+ self.clone_versioned_model(version, self)
205
+ self.send("#{self.class.version_column}=", version.version)
206
+ true
207
+ end
208
+
209
+ # Reverts a model to a given version and saves the model.
210
+ # Takes either a version number or an instance of the versioned model
211
+ def revert_to!(version)
212
+ revert_to(version) ? save_without_revision : false
213
+ end
214
+
215
+ # Temporarily turns off Optimistic Locking while saving. Used when reverting so that a new version is not created.
216
+ def save_without_revision
217
+ old_lock_value = ActiveRecord::Base.lock_optimistically
218
+ ActiveRecord::Base.lock_optimistically = false if old_lock_value
219
+ disable_acts_as_versioned_callbacks
220
+ save_result = self.save
221
+ enable_acts_as_versioned_callbacks
222
+ ActiveRecord::Base.lock_optimistically = true if old_lock_value
223
+ save_result
224
+ end
225
+
226
+ # Returns an array of attribute keys that are versioned. See non_versioned_fields
227
+ def versioned_attributes
228
+ self.attributes.keys.select { |k| !self.class.non_versioned_fields.include?(k) }
229
+ end
230
+
231
+ # If called with no parameters, gets whether the current model is dirty and needs to be versioned.
232
+ # If called with a single parameter, gets whether the parameter is currently dirty.
233
+ def dirty?(attr_name = nil)
234
+ attr_name.nil? ?
235
+ (!self.class.track_changed_attributes or (changed_attributes and changed_attributes.length > 0)) :
236
+ (changed_attributes and changed_attributes.include?(attr_name.to_s))
237
+ end
238
+
239
+ # Clones a model. Used when saving a new version or reverting a model's version.
240
+ def clone_versioned_model(orig_model, new_model)
241
+ self.versioned_attributes.each do |key|
242
+ new_model.send("#{key}=", orig_model.attributes[key]) if orig_model.attribute_present?(key)
243
+ end
244
+
245
+ if orig_model.is_a?(self.class.versioned_class)
246
+ new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]
247
+ elsif new_model.is_a?(self.class.versioned_class)
248
+ new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column]
249
+ end
250
+ end
251
+
252
+ # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>dirty?</tt>.
253
+ def save_version?
254
+ version_condition_met? and dirty?
255
+ end
256
+
257
+ # Checks condition set in the :if option to check whether a revision should be created or not. Override this for
258
+ # custom version condition checking.
259
+ def version_condition_met?
260
+ case
261
+ when version_condition.is_a?(Symbol)
262
+ send(version_condition)
263
+ when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)
264
+ version_condition.call(self)
265
+ else
266
+ version_condition
267
+ end
268
+ end
269
+
270
+ protected
271
+ # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.
272
+ def set_new_version
273
+ self.send("#{self.class.version_column}=", self.next_version) if new_record? or (!locking_enabled? and save_version?)
274
+ end
275
+
276
+ # Gets the next available version for the current record, or 1 for a new record
277
+ def next_version
278
+ return 1 if new_record?
279
+ connection.select_one("SELECT MAX(version)+1 AS next_version FROM #{self.class.versioned_table_name} WHERE #{self.class.versioned_foreign_key} = #{self.id}")['next_version'] || 1
280
+ end
281
+
282
+ # clears current dirty attributes. Called after save.
283
+ def clear_changed_attributes
284
+ self.changed_attributes = []
285
+ end
286
+
287
+ private
288
+ unless defined?(ACTS_AS_VERSIONED_CALLBACKS)
289
+ ACTS_AS_VERSIONED_CALLBACKS = [:set_new_version, :save_version_on_create, :save_version, :clear_changed_attributes]
290
+ end
291
+
292
+ ACTS_AS_VERSIONED_CALLBACKS.each do |attr_name|
293
+ alias_method "orig_#{attr_name}".to_sym, attr_name
294
+ end
295
+
296
+ def empty_callback() end #:nodoc:
297
+
298
+ def enable_acts_as_versioned_callbacks
299
+ self.class.class_eval do
300
+ ACTS_AS_VERSIONED_CALLBACKS.each do |attr_name|
301
+ alias_method attr_name, "orig_#{attr_name}".to_sym
302
+ end
303
+ end
304
+ end
305
+
306
+ def disable_acts_as_versioned_callbacks
307
+ self.class.class_eval do
308
+ ACTS_AS_VERSIONED_CALLBACKS.each do |attr_name|
309
+ alias_method attr_name, :empty_callback
310
+ end
311
+ end
312
+ end
313
+
314
+ module ClassMethods
315
+ # Returns an array of columns that are versioned. See non_versioned_fields
316
+ def versioned_columns
317
+ self.columns.select { |c| !non_versioned_fields.include?(c.name) }
318
+ end
319
+
320
+ # Returns an instance of the dynamic versioned model
321
+ def versioned_class
322
+ "ActiveRecord::Acts::Versioned::#{versioned_class_name}".constantize
323
+ end
324
+
325
+ # An array of fields that are not saved in the versioned table
326
+ def non_versioned_fields
327
+ [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
328
+ end
329
+
330
+ # Rake migration task to create the versioned table using options passed to acts_as_versioned
331
+ def create_versioned_table(create_table_options = {})
332
+ self.transaction do
333
+ # create version column in main table if it does not exist
334
+ if !self.content_columns.find { |c| %w(version lock_version).include? c.name }
335
+ self.connection.add_column table_name, :version, :integer
336
+ end
337
+
338
+ self.connection.create_table(versioned_table_name, create_table_options) do |t|
339
+ t.column versioned_foreign_key, :integer
340
+ t.column :version, :integer
341
+ end
342
+
343
+ updated_col = nil
344
+ self.versioned_columns.each do |col|
345
+ updated_col = col if !updated_col and %(updated_at updated_on).include?(col.name)
346
+ self.connection.add_column versioned_table_name, col.name, col.type,
347
+ :limit => col.limit,
348
+ :default => col.default
349
+ end
350
+
351
+ if type_col = self.columns_hash[inheritance_column]
352
+ self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type,
353
+ :limit => type_col.limit,
354
+ :default => type_col.default
355
+ end
356
+
357
+ if updated_col.nil?
358
+ self.connection.add_column versioned_table_name, :updated_at, :timestamp
359
+ end
360
+ end
361
+ end
362
+
363
+ # Rake migration task to drop the versioned table
364
+ def drop_versioned_table
365
+ self.connection.drop_table versioned_table_name
366
+ end
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end
372
+
373
+ ActiveRecord::Base.class_eval { include ActiveRecord::Acts::Versioned }
@@ -0,0 +1,25 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'active_record'
6
+ require 'active_record/fixtures'
7
+ require 'active_support/binding_of_caller'
8
+ require 'active_support/breakpoint'
9
+ require 'connection'
10
+ require 'acts_as_versioned'
11
+
12
+ class Test::Unit::TestCase #:nodoc:
13
+ def create_fixtures(*table_names)
14
+ if block_given?
15
+ Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names) { yield }
16
+ else
17
+ Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names)
18
+ end
19
+ end
20
+ end
21
+
22
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
23
+ Test::Unit::TestCase.use_instantiated_fixtures = false
24
+ Test::Unit::TestCase.use_transactional_fixtures = (ENV['AR_TX_FIXTURES'] == "yes")
25
+
@@ -0,0 +1,14 @@
1
+ print "Using native DB2\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'arversioned'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "db2",
10
+ :host => "localhost",
11
+ :username => "arunit",
12
+ :password => "arunit",
13
+ :database => db1
14
+ )
@@ -0,0 +1,14 @@
1
+ print "Using native MySQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'activerecord_versioned'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "mysql",
10
+ :host => "localhost",
11
+ :username => "rails",
12
+ :password => "",
13
+ :database => db1
14
+ )
@@ -0,0 +1,15 @@
1
+ print "Using OCI Oracle\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new STDOUT
5
+ ActiveRecord::Base.logger.level = Logger::WARN
6
+
7
+ db1 = 'activerecord_versioned'
8
+
9
+ ActiveRecord::Base.establish_connection(
10
+ :adapter => 'oci',
11
+ :host => '', # can use an oracle SID
12
+ :username => 'arunit',
13
+ :password => 'arunit',
14
+ :database => db1
15
+ )
@@ -0,0 +1,14 @@
1
+ print "Using native PostgreSQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'activerecord_versioned'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "postgresql",
10
+ :host => nil,
11
+ :username => "postgres",
12
+ :password => "postgres",
13
+ :database => db1
14
+ )
@@ -0,0 +1,34 @@
1
+ print "Using native SQlite\n"
2
+ require 'logger'
3
+ ActiveRecord::Base.logger = Logger.new("debug.log")
4
+
5
+ class SqliteError < StandardError
6
+ end
7
+
8
+ BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures')
9
+ sqlite_test_db = "#{BASE_DIR}/activerecord_versioned.sqlite"
10
+
11
+ def make_connection(clazz, db_file, db_definitions_file)
12
+ unless File.exist?(db_file)
13
+ puts "SQLite database not found at #{db_file}. Rebuilding it."
14
+ sqlite_command = %Q{sqlite #{db_file} "create table a (a integer); drop table a;"}
15
+ puts "Executing '#{sqlite_command}'"
16
+ raise SqliteError.new("Seems that there is no sqlite executable available") unless system(sqlite_command)
17
+ clazz.establish_connection(
18
+ :adapter => "sqlite",
19
+ :dbfile => db_file)
20
+ script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}")
21
+ # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time
22
+ script.split(';').each do
23
+ |command|
24
+ clazz.connection.execute(command) unless command.strip.empty?
25
+ end
26
+ else
27
+ clazz.establish_connection(
28
+ :adapter => "sqlite",
29
+ :dbfile => db_file)
30
+ end
31
+ end
32
+
33
+ make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql')
34
+
@@ -0,0 +1,33 @@
1
+ print "Using native SQLite3\n"
2
+ require 'logger'
3
+ ActiveRecord::Base.logger = Logger.new("debug.log")
4
+
5
+ class SqliteError < StandardError
6
+ end
7
+
8
+ BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures')
9
+ sqlite_test_db = "#{BASE_DIR}/activerecord_versioned.sqlite3"
10
+
11
+ def make_connection(clazz, db_file, db_definitions_file)
12
+ unless File.exist?(db_file)
13
+ puts "SQLite3 database not found at #{db_file}. Rebuilding it."
14
+ sqlite_command = %Q{sqlite3 #{db_file} "create table a (a integer); drop table a;"}
15
+ puts "Executing '#{sqlite_command}'"
16
+ raise SqliteError.new("Seems that there is no sqlite3 executable available") unless system(sqlite_command)
17
+ clazz.establish_connection(
18
+ :adapter => "sqlite3",
19
+ :dbfile => db_file)
20
+ script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}")
21
+ # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time
22
+ script.split(';').each do
23
+ |command|
24
+ clazz.connection.execute(command) unless command.strip.empty?
25
+ end
26
+ else
27
+ clazz.establish_connection(
28
+ :adapter => "sqlite3",
29
+ :dbfile => db_file)
30
+ end
31
+ end
32
+
33
+ make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql')
@@ -0,0 +1,14 @@
1
+ print "Using native SQLServer\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'activerecord_versioned'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "sqlserver",
10
+ :host => "localhost",
11
+ :username => "sa",
12
+ :password => "",
13
+ :database => db1
14
+ )
@@ -0,0 +1,15 @@
1
+ print "Using native SQLServer via ODBC\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ dsn1 = 'activerecord_versioned'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "sqlserver",
10
+ :mode => "ODBC",
11
+ :host => "localhost",
12
+ :username => "sa",
13
+ :password => "",
14
+ :dsn => dsn1
15
+ )
@@ -0,0 +1,4 @@
1
+ DROP TABLE pages;
2
+ DROP TABLE page_versions;
3
+ DROP TABLE locked_pages;
4
+ DROP TABLE locked_pages_revisions;
@@ -0,0 +1,36 @@
1
+ CREATE TABLE `pages` (
2
+ `id` int(11) NOT NULL auto_increment,
3
+ `version` int(11) default NULL,
4
+ `title` varchar(255) default NULL,
5
+ `body` TEXT NOT NULL,
6
+ `updated_on` datetime default NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) TYPE=InnoDB;
9
+
10
+ CREATE TABLE `page_versions` (
11
+ `id` int(11) NOT NULL auto_increment,
12
+ `page_id` int(11) default NULL,
13
+ `version` int(11) default NULL,
14
+ `title` varchar(255) default NULL,
15
+ `body` TEXT NOT NULL,
16
+ `updated_on` datetime default NULL,
17
+ PRIMARY KEY (`id`)
18
+ ) TYPE=InnoDB;
19
+
20
+ CREATE TABLE `locked_pages` (
21
+ `id` int(11) NOT NULL auto_increment,
22
+ `lock_version` int(11) default NULL,
23
+ `title` varchar(255) default NULL,
24
+ `type` varchar(255) default NULL,
25
+ PRIMARY KEY (`id`)
26
+ ) TYPE=InnoDB;
27
+
28
+ CREATE TABLE `locked_pages_revisions` (
29
+ `id` int(11) NOT NULL auto_increment,
30
+ `page_id` int(11) default NULL,
31
+ `version` int(11) default NULL,
32
+ `title` varchar(255) default NULL,
33
+ `version_type` varchar(255) default NULL,
34
+ `updated_at` datetime default NULL,
35
+ PRIMARY KEY (`id`)
36
+ ) TYPE=InnoDB;
@@ -0,0 +1,4 @@
1
+ DROP TABLE pages;
2
+ DROP TABLE page_versions;
3
+ DROP TABLE locked_pages;
4
+ DROP TABLE locked_pages_revisions;
@@ -0,0 +1,34 @@
1
+ CREATE TABLE pages (
2
+ id SERIAL,
3
+ version INTEGER,
4
+ title VARCHAR(255),
5
+ body TEXT,
6
+ updated_on TIMESTAMP
7
+ );
8
+ SELECT setval('pages_id_seq', 100);
9
+
10
+ CREATE TABLE page_versions (
11
+ id SERIAL,
12
+ page_id INTEGER,
13
+ version INTEGER,
14
+ title VARCHAR(255),
15
+ body TEXT,
16
+ updated_on TIMESTAMP
17
+ );
18
+
19
+ CREATE TABLE locked_pages (
20
+ id SERIAL,
21
+ lock_version INTEGER,
22
+ title VARCHAR(255),
23
+ type VARCHAR(255)
24
+ );
25
+ SELECT setval('pages_id_seq', 100);
26
+
27
+ CREATE TABLE locked_pages_revisions (
28
+ id SERIAL,
29
+ page_id INTEGER,
30
+ version INTEGER,
31
+ title VARCHAR(255),
32
+ version_type VARCHAR(255),
33
+ updated_at TIMESTAMP
34
+ );
@@ -0,0 +1,4 @@
1
+ DROP TABLE pages;
2
+ DROP TABLE page_versions;
3
+ DROP TABLE locked_pages;
4
+ DROP TABLE locked_pages_revisions;
@@ -0,0 +1,32 @@
1
+ CREATE TABLE 'pages' (
2
+ 'id' INTEGER NOT NULL PRIMARY KEY,
3
+ 'version' INTEGER,
4
+ 'title' VARCHAR(255),
5
+ 'body' TEXT,
6
+ 'updated_on' DATETIME DEFAULT NULL
7
+ );
8
+
9
+ CREATE TABLE 'page_versions' (
10
+ 'id' INTEGER NOT NULL PRIMARY KEY,
11
+ 'page_id' INTEGER NOT NULL,
12
+ 'version' INTEGER NOT NULL,
13
+ 'title' VARCHAR(255),
14
+ 'body' TEXT DEFAULT NULL,
15
+ 'updated_on' DATETIME DEFAULT NULL
16
+ );
17
+
18
+ CREATE TABLE 'locked_pages' (
19
+ 'id' INTEGER NOT NULL PRIMARY KEY,
20
+ 'lock_version' INTEGER NOT NULL,
21
+ 'title' VARCHAR(255),
22
+ 'type' VARCHAR(255)
23
+ );
24
+
25
+ CREATE TABLE 'locked_pages_revisions' (
26
+ 'id' INTEGER NOT NULL PRIMARY KEY,
27
+ 'page_id' INTEGER NOT NULL,
28
+ 'version' INTEGER NOT NULL,
29
+ 'title' VARCHAR(255),
30
+ 'version_type' VARCHAR(255),
31
+ 'updated_at' DATETIME DEFAULT NULL
32
+ );
@@ -0,0 +1,10 @@
1
+ welcome:
2
+ id: 1
3
+ title: Welcome to the weblog
4
+ lock_version: 24
5
+ type: LockedPage
6
+ thinking:
7
+ id: 2
8
+ title: So I was thinking
9
+ lock_version: 24
10
+ type: SpecialLockedPage
@@ -0,0 +1,27 @@
1
+ welcome_1:
2
+ id: 1
3
+ page_id: 1
4
+ title: Welcome to the weblg
5
+ version: 23
6
+ version_type: LockedPage
7
+
8
+ welcome_2:
9
+ id: 2
10
+ page_id: 1
11
+ title: Welcome to the weblog
12
+ version: 24
13
+ version_type: LockedPage
14
+
15
+ thinking_1:
16
+ id: 3
17
+ page_id: 2
18
+ title: So I was thinking!!!
19
+ version: 23
20
+ version_type: SpecialLockedPage
21
+
22
+ thinking_2:
23
+ id: 4
24
+ page_id: 2
25
+ title: So I was thinking
26
+ version: 24
27
+ version_type: SpecialLockedPage
@@ -0,0 +1,13 @@
1
+ class AddVersionedTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table("things") do |t|
4
+ t.column :title, :text
5
+ end
6
+ Thing.create_versioned_table
7
+ end
8
+
9
+ def self.down
10
+ Thing.drop_versioned_table
11
+ drop_table "things" rescue nil
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ class Page < ActiveRecord::Base
2
+ cattr_accessor :feeling_good
3
+ @@feeling_good = true
4
+
5
+ acts_as_versioned :if => :feeling_good?
6
+
7
+ def feeling_good?
8
+ @@feeling_good == true
9
+ end
10
+ end
11
+
12
+ class LockedPage < ActiveRecord::Base
13
+ acts_as_versioned \
14
+ :inheritance_column => :version_type,
15
+ :foreign_key => :page_id,
16
+ :table_name => :locked_pages_revisions,
17
+ :class_name => 'LockedPageRevision',
18
+ :version_column => :lock_version,
19
+ :limit => 2,
20
+ :if_changed => :title
21
+ end
22
+
23
+ class SpecialLockedPage < LockedPage
24
+ end
@@ -0,0 +1,12 @@
1
+ welcome_2:
2
+ id: 1
3
+ page_id: 1
4
+ title: Welcome to the weblog
5
+ body: Such a lovely day
6
+ version: 24
7
+ welcome_1:
8
+ id: 2
9
+ page_id: 1
10
+ title: Welcome to the weblg
11
+ body: Such a lovely day
12
+ version: 23
@@ -0,0 +1,5 @@
1
+ welcome:
2
+ id: 1
3
+ title: Welcome to the weblog
4
+ body: Such a lovely day
5
+ version: 24
@@ -0,0 +1,29 @@
1
+ require 'abstract_unit'
2
+
3
+ if ActiveRecord::Base.connection.supports_migrations?
4
+ class Thing < ActiveRecord::Base
5
+ attr_accessor :version
6
+ acts_as_versioned
7
+ end
8
+
9
+ class MigrationTest < Test::Unit::TestCase
10
+ def setup
11
+ end
12
+
13
+ def teardown
14
+ ActiveRecord::Base.connection.initialize_schema_information
15
+ ActiveRecord::Base.connection.update "UPDATE schema_info SET version = 0"
16
+
17
+ Thing.connection.drop_table "things" rescue nil
18
+ Thing.connection.drop_table "thing_versions" rescue nil
19
+ Thing.reset_column_information
20
+ end
21
+
22
+ def test_versioned_migration
23
+ assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }
24
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
25
+ t = Thing.create :title => 'blah blah'
26
+ assert_equal 1, t.versions.size
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,2 @@
1
+ $:.unshift "../lib"
2
+ Dir["**/*_test.rb"].each { |f| load f }
@@ -0,0 +1,228 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/page'
3
+
4
+ class VersionedTest < Test::Unit::TestCase
5
+ fixtures :pages, :page_versions, :locked_pages, :locked_pages_revisions
6
+
7
+ def test_saves_versioned_copy
8
+ p = Page.create :title => 'first title', :body => 'first body'
9
+ assert !p.new_record?
10
+ assert_equal 1, p.versions.size
11
+ assert_equal 1, p.version
12
+ assert_instance_of Page.versioned_class, p.versions.first
13
+ end
14
+
15
+ def test_rollback_with_version_number
16
+ p = pages(:welcome)
17
+ assert_equal 24, p.version
18
+ assert_equal 'Welcome to the weblog', p.title
19
+
20
+ assert p.revert_to!(p.versions.first.version), "Couldn't revert to 23"
21
+ assert_equal 23, p.version
22
+ assert_equal 'Welcome to the weblg', p.title
23
+ end
24
+
25
+ def test_versioned_class_name
26
+ assert_equal 'PageVersion', Page.versioned_class_name
27
+ assert_equal 'LockedPageRevision', LockedPage.versioned_class_name
28
+ end
29
+
30
+ def test_rollback_with_version_class
31
+ p = pages(:welcome)
32
+ assert_equal 24, p.version
33
+ assert_equal 'Welcome to the weblog', p.title
34
+
35
+ assert p.revert_to!(p.versions.first), "Couldn't revert to 23"
36
+ assert_equal 23, p.version
37
+ assert_equal 'Welcome to the weblg', p.title
38
+ end
39
+
40
+ def test_rollback_fails_with_invalid_revision
41
+ p = locked_pages(:welcome)
42
+ assert !p.revert_to!(locked_pages(:thinking))
43
+ end
44
+
45
+ def test_saves_versioned_copy_with_options
46
+ p = LockedPage.create :title => 'first title'
47
+ assert !p.new_record?
48
+ assert_equal 1, p.versions.size
49
+ assert_instance_of LockedPage.versioned_class, p.versions.first
50
+ end
51
+
52
+ def test_rollback_with_version_number_with_options
53
+ p = locked_pages(:welcome)
54
+ assert_equal 'Welcome to the weblog', p.title
55
+ assert_equal 'LockedPage', p.versions.first.version_type
56
+
57
+ assert p.revert_to!(p.versions.first.version), "Couldn't revert to 23"
58
+ assert_equal 'Welcome to the weblg', p.title
59
+ assert_equal 'LockedPage', p.versions.first.version_type
60
+ end
61
+
62
+ def test_rollback_with_version_class_with_options
63
+ p = locked_pages(:welcome)
64
+ assert_equal 'Welcome to the weblog', p.title
65
+ assert_equal 'LockedPage', p.versions.first.version_type
66
+
67
+ assert p.revert_to!(p.versions.first), "Couldn't revert to 1"
68
+ assert_equal 'Welcome to the weblg', p.title
69
+ assert_equal 'LockedPage', p.versions.first.version_type
70
+ end
71
+
72
+ def test_saves_versioned_copy_with_sti
73
+ p = SpecialLockedPage.create :title => 'first title'
74
+ assert !p.new_record?
75
+ assert_equal 1, p.versions.size
76
+ assert_instance_of LockedPage.versioned_class, p.versions.first
77
+ assert_equal 'SpecialLockedPage', p.versions.first.version_type
78
+ end
79
+
80
+ def test_rollback_with_version_number_with_sti
81
+ p = locked_pages(:thinking)
82
+ assert_equal 'So I was thinking', p.title
83
+
84
+ assert p.revert_to!(p.versions.first.version), "Couldn't revert to 1"
85
+ assert_equal 'So I was thinking!!!', p.title
86
+ assert_equal 'SpecialLockedPage', p.versions.first.version_type
87
+ end
88
+
89
+ def test_lock_version_works_with_versioning
90
+ p = locked_pages(:thinking)
91
+ p2 = LockedPage.find(p.id)
92
+
93
+ p.title = 'fresh title'
94
+ p.save
95
+ assert_equal 2, p.versions.size # limit!
96
+
97
+ assert_raises(ActiveRecord::StaleObjectError) do
98
+ p2.title = 'stale title'
99
+ p2.save
100
+ end
101
+ end
102
+
103
+ def test_version_if_condition
104
+ p = Page.create :title => "title"
105
+ assert_equal 1, p.version
106
+
107
+ Page.feeling_good = false
108
+ p.save
109
+ assert_equal 1, p.version
110
+ Page.feeling_good = true
111
+ end
112
+
113
+ def test_version_if_condition2
114
+ # set new if condition
115
+ Page.class_eval do
116
+ def new_feeling_good() title[0..0] == 'a'; end
117
+ alias_method :old_feeling_good, :feeling_good?
118
+ alias_method :feeling_good?, :new_feeling_good
119
+ end
120
+
121
+ p = Page.create :title => "title"
122
+ assert_equal 1, p.version # version does not increment
123
+ assert_equal 1, p.versions(true).size
124
+
125
+ p.update_attributes(:title => 'new title')
126
+ assert_equal 1, p.version # version does not increment
127
+ assert_equal 1, p.versions(true).size
128
+
129
+ p.update_attributes(:title => 'a title')
130
+ assert_equal 2, p.version
131
+ assert_equal 2, p.versions(true).size
132
+
133
+ # reset original if condition
134
+ Page.class_eval { alias_method :feeling_good?, :old_feeling_good }
135
+ end
136
+
137
+ def test_version_if_condition_with_block
138
+ # set new if condition
139
+ old_condition = Page.version_condition
140
+ Page.version_condition = Proc.new { |page| page.title[0..0] == 'b' }
141
+
142
+ p = Page.create :title => "title"
143
+ assert_equal 1, p.version # version does not increment
144
+ assert_equal 1, p.versions(true).size
145
+
146
+ p.update_attributes(:title => 'a title')
147
+ assert_equal 1, p.version # version does not increment
148
+ assert_equal 1, p.versions(true).size
149
+
150
+ p.update_attributes(:title => 'b title')
151
+ assert_equal 2, p.version
152
+ assert_equal 2, p.versions(true).size
153
+
154
+ # reset original if condition
155
+ Page.version_condition = old_condition
156
+ end
157
+
158
+ def test_version_no_limit
159
+ p = Page.create :title => "title", :body => 'first body'
160
+ p.save
161
+ p.save
162
+ 5.times do |i|
163
+ assert_page_title p, i
164
+ end
165
+ end
166
+
167
+ def test_version_max_limit
168
+ p = LockedPage.create :title => "title"
169
+ p.update_attributes(:title => "title1")
170
+ p.update_attributes(:title => "title2")
171
+ 5.times do |i|
172
+ assert_page_title p, i, :lock_version
173
+ assert p.versions(true).size <= 2, "locked version can only store 2 versions"
174
+ end
175
+ end
176
+
177
+ def test_track_changed_attributes_default_value
178
+ assert !Page.track_changed_attributes
179
+ assert LockedPage.track_changed_attributes
180
+ assert SpecialLockedPage.track_changed_attributes
181
+ end
182
+
183
+ def test_version_order
184
+ assert_equal 23, pages(:welcome).versions.first.version
185
+ assert_equal 24, pages(:welcome).versions.last.version
186
+ assert_equal 23, pages(:welcome).find_versions.first.version
187
+ assert_equal 24, pages(:welcome).find_versions.last.version
188
+ end
189
+
190
+ def test_track_changed_attributes
191
+ p = LockedPage.create :title => "title"
192
+ assert_equal 1, p.lock_version
193
+ assert_equal 1, p.versions(true).size
194
+
195
+ p.title = 'title'
196
+ assert !p.save_version?
197
+ p.save
198
+ assert_equal 2, p.lock_version # still increments version because of optimistic locking
199
+ assert_equal 1, p.versions(true).size
200
+
201
+ p.title = 'updated title'
202
+ assert p.save_version?
203
+ p.save
204
+ assert_equal 3, p.lock_version
205
+ assert_equal 1, p.versions(true).size # version 1 deleted
206
+
207
+ p.title = 'updated title!'
208
+ assert p.save_version?
209
+ p.save
210
+ assert_equal 4, p.lock_version
211
+ assert_equal 2, p.versions(true).size # version 1 deleted
212
+ end
213
+
214
+ def assert_page_title(p, i, version_field = :version)
215
+ p.title = "title#{i}"
216
+ p.save
217
+ assert_equal "title#{i}", p.title
218
+ assert_equal (i+4), p.send(version_field)
219
+ end
220
+
221
+ def test_find_versions
222
+ assert_equal 2, locked_pages(:welcome).versions.size
223
+ assert_equal 1, locked_pages(:welcome).find_versions(:conditions => ['title LIKE ?', '%weblog%']).length
224
+ assert_equal 2, locked_pages(:welcome).find_versions(:conditions => ['title LIKE ?', '%web%']).length
225
+ assert_equal 0, locked_pages(:thinking).find_versions(:conditions => ['title LIKE ?', '%web%']).length
226
+ assert_equal 2, locked_pages(:welcome).find_versions.length
227
+ end
228
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.10
3
+ specification_version: 1
4
+ name: acts_as_versioned
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.2
7
+ date: 2005-09-18
8
+ summary: Simple versioning with active record models
9
+ require_paths:
10
+ - lib
11
+ email: technoweenie@gmail.com
12
+ homepage: http://techno-weenie.net
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: acts_as_versioned
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ authors:
28
+ - Rick Olson
29
+ files:
30
+ - lib/acts_as_versioned.rb
31
+ - test/abstract_unit.rb
32
+ - test/connections
33
+ - test/fixtures
34
+ - test/migration_test.rb
35
+ - test/tests.rb
36
+ - test/versioned_test.rb
37
+ - test/connections/native_db2
38
+ - test/connections/native_mysql
39
+ - test/connections/native_oci
40
+ - test/connections/native_postgresql
41
+ - test/connections/native_sqlite
42
+ - test/connections/native_sqlite3
43
+ - test/connections/native_sqlserver
44
+ - test/connections/native_sqlserver_odbc
45
+ - test/connections/native_db2/connection.rb
46
+ - test/connections/native_mysql/connection.rb
47
+ - test/connections/native_oci/connection.rb
48
+ - test/connections/native_postgresql/connection.rb
49
+ - test/connections/native_sqlite/connection.rb
50
+ - test/connections/native_sqlite3/connection.rb
51
+ - test/connections/native_sqlserver/connection.rb
52
+ - test/connections/native_sqlserver_odbc/connection.rb
53
+ - test/fixtures/activerecord_versioned.sqlite3
54
+ - test/fixtures/db_definitions
55
+ - test/fixtures/locked_pages.yml
56
+ - test/fixtures/locked_pages_revisions.yml
57
+ - test/fixtures/migrations
58
+ - test/fixtures/page.rb
59
+ - test/fixtures/page_versions.yml
60
+ - test/fixtures/pages.yml
61
+ - test/fixtures/db_definitions/mysql.drop.sql
62
+ - test/fixtures/db_definitions/mysql.sql
63
+ - test/fixtures/db_definitions/postgresql.drop.sql
64
+ - test/fixtures/db_definitions/postgresql.sql
65
+ - test/fixtures/db_definitions/sqlite.drop.sql
66
+ - test/fixtures/db_definitions/sqlite.sql
67
+ - test/fixtures/migrations/1_add_versioned_tables.rb
68
+ - README
69
+ - MIT-LICENSE
70
+ - CHANGELOG
71
+ - RUNNING_UNIT_TESTS
72
+ test_files:
73
+ - test/tests.rb
74
+ rdoc_options: []
75
+ extra_rdoc_files: []
76
+ executables: []
77
+ extensions: []
78
+ requirements: []
79
+ dependencies:
80
+ - !ruby/object:Gem::Dependency
81
+ name: activerecord
82
+ version_requirement:
83
+ version_requirements: !ruby/object:Gem::Version::Requirement
84
+ requirements:
85
+ -
86
+ - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.10.1
89
+ version:
90
+ - !ruby/object:Gem::Dependency
91
+ name: activesupport
92
+ version_requirement:
93
+ version_requirements: !ruby/object:Gem::Version::Requirement
94
+ requirements:
95
+ -
96
+ - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 1.1.1
99
+ version: