controlled_versioning 0.6

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 006bad30ccaea1ec63957fcf41c9987bf2ba5027
4
+ data.tar.gz: 75b870f39473c849265c9d8baa990be953c52b2d
5
+ SHA512:
6
+ metadata.gz: 8978fffbb883fddfb408d0c27f634935e97be9fef9a573c83c2462acb4f12146064fd46d45ddaf8280646195adc24bd3404a5c9487fa489317411ee3a31201ba
7
+ data.tar.gz: 13f85a9d20a79641716580c601d801fc110f89b1dab9f60f59566c36b349dd19af898031818fc2aac4e2e6d03d06adadb80b4cb7fea0e888f7cbedc01128fb7f
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Timothy Baron
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.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = ControlledVersioning
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ControlledVersioning'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
@@ -0,0 +1,4 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ no_revisions_made: "You must edit at least one attribute"
@@ -0,0 +1,110 @@
1
+ # Core
2
+ require "controlled_versioning/revision"
3
+ require "controlled_versioning/revision_auditor"
4
+ require "controlled_versioning/revision_builder"
5
+ require "controlled_versioning/revision_accepter"
6
+ require "controlled_versioning/initial_version_builder"
7
+
8
+ # Add utility classes
9
+ require "support/array_converter"
10
+ require "support/attribute_encapsulator"
11
+
12
+ module ControlledVersioning
13
+ module ActsAsVersionable
14
+ extend ActiveSupport::Concern
15
+
16
+ included do
17
+ end
18
+
19
+ module ClassMethods
20
+ def acts_as_versionable(options = {})
21
+
22
+ send :include, InstanceMethods
23
+
24
+ def set_versionable_attribute_names(nonversionables)
25
+ nonversionables = [] unless nonversionables.present?
26
+ ArrayConverter.to_s!(nonversionables)
27
+ nonversionables += ["id", "updated_at", "created_at"]
28
+ attribute_names - nonversionables
29
+ end
30
+
31
+ def nested_associations
32
+ nested_attributes_options.keys
33
+ end
34
+
35
+ def has_nested_associations?
36
+ nested_associations.present?
37
+ end
38
+
39
+ attr_accessor :user
40
+
41
+ after_create :create_initial_version
42
+
43
+ cattr_accessor :nested_within
44
+ self.nested_within = options[:nested_within]
45
+
46
+ def is_a_nested_association?
47
+ nested_within.present?
48
+ end
49
+
50
+ if is_a_nested_association?
51
+ has_many :version_children,
52
+ class_name: 'ControlledVersioning::VersionChild',
53
+ as: :versionable
54
+ else
55
+ has_many :versions,
56
+ lambda { order("created_at ASC")},
57
+ class_name: 'ControlledVersioning::Version',
58
+ as: :versionable
59
+ end
60
+
61
+ cattr_accessor :versionable_attribute_names
62
+ self.versionable_attribute_names = options[:versionable_attributes] ||
63
+ set_versionable_attribute_names(
64
+ options[:nonversionable_attributes])
65
+ end
66
+ end
67
+
68
+ module InstanceMethods
69
+ def is_a_nested_association?
70
+ self.class.is_a_nested_association?
71
+ end
72
+
73
+ def versionable_attributes
74
+ versionable_attributes = self.versionable_attribute_names
75
+ ArrayConverter.to_s!(versionable_attributes)
76
+ self.attributes.slice(*versionable_attributes)
77
+ end
78
+
79
+ def initial_version
80
+ if is_a_nested_association?
81
+ version_children.first
82
+ else
83
+ versions.find_by(initial: true)
84
+ end
85
+ end
86
+
87
+ def submit_revision(suggested_attributes)
88
+ assign_attributes(suggested_attributes)
89
+ if invalid?
90
+ errors
91
+ elsif !RevisionAuditor.new(self).changes_original?
92
+ errors[:base] << I18n.t("errors.messages.no_revisions_made")
93
+ errors
94
+ else
95
+ version = versions.build
96
+ RevisionBuilder.new(versionable: self, version: version).version
97
+ version.save
98
+ version
99
+ end
100
+ end
101
+
102
+ private
103
+ def create_initial_version
104
+ InitialVersionBuilder.new(self)
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ ActiveRecord::Base.send :include, ControlledVersioning::ActsAsVersionable
@@ -0,0 +1,49 @@
1
+ class InitialVersionBuilder < Revision
2
+
3
+ attr_reader :versionable, :version
4
+ def initialize(versionable)
5
+ @versionable = versionable
6
+ @version = build_version_type
7
+ build_initial_version
8
+ end
9
+
10
+ private
11
+ def build_version_type
12
+ if is_a_nested_association?
13
+ parent.initial_version.version_children.build(versionable: versionable)
14
+ else
15
+ versionable.versions.build(initial: true)
16
+ end
17
+ end
18
+
19
+ def build_initial_version
20
+ build_version_attributes
21
+ version.save
22
+ end
23
+
24
+ def build_version_attributes
25
+ versionable_attributes.each do |attr|
26
+ attr = AttributeEncapsulator.new(attr)
27
+ build_attribute(attr)
28
+ end
29
+ end
30
+
31
+ def build_attribute(attr)
32
+ version_attributes.build(
33
+ name: attr.key,
34
+ new_value: attr.value)
35
+ end
36
+
37
+ def is_a_nested_association?
38
+ versionable.is_a_nested_association?
39
+ end
40
+
41
+ def nested_within
42
+ versionable.nested_within
43
+ end
44
+
45
+ def parent
46
+ versionable.public_send(nested_within)
47
+ end
48
+
49
+ end
@@ -0,0 +1,34 @@
1
+ class Revision
2
+
3
+ private
4
+ def versionable_attributes
5
+ versionable.versionable_attributes
6
+ end
7
+
8
+ def changed_attributes
9
+ versionable.changed_attributes
10
+ end
11
+
12
+ def nested_associations
13
+ versionable.class.nested_associations
14
+ end
15
+
16
+ def version_attributes
17
+ version.version_attributes
18
+ end
19
+
20
+ def version_children
21
+ version.version_children
22
+ end
23
+
24
+ def versionable_changes(key)
25
+ values = versionable.changes[key]
26
+ ValueChange.new(values[0], values[1])
27
+ end
28
+
29
+ def previous_value(key)
30
+ versionable_changes(key).previous_value
31
+ end
32
+
33
+ ValueChange = Struct.new(:previous_value, :new_value)
34
+ end
@@ -0,0 +1,51 @@
1
+ class RevisionAccepter < Revision
2
+
3
+ attr_reader :version, :versionable
4
+ def initialize(version)
5
+ @version = version
6
+ @versionable = version.versionable
7
+ accept_revision
8
+ end
9
+
10
+ private
11
+ def accept_revision
12
+ create_or_update_versionable
13
+ update_version_children
14
+ end
15
+
16
+ def create_or_update_versionable
17
+ versionable.present? ? update_versionable : create_versionable
18
+ end
19
+
20
+ def new_attributes
21
+ version_attributes.each_with_object({}) {|v, h| h[v.name] = v.new_value }
22
+ end
23
+
24
+ def create_versionable
25
+ version.versionable = version.versionable_type.constantize.
26
+ create(new_attributes)
27
+ end
28
+
29
+ def update_versionable
30
+ versionable.update_attributes(new_attributes)
31
+ end
32
+
33
+ def update_version_children
34
+ version_children.each do |child|
35
+ update_or_destroy_child(child)
36
+ end
37
+ end
38
+
39
+ def update_or_destroy_child(child)
40
+ if child.marked_for_removal?
41
+ destroy_child(child)
42
+ else
43
+ RevisionAccepter.new(child)
44
+ end
45
+ end
46
+
47
+ def destroy_child(child)
48
+ child.versionable.destroy
49
+ end
50
+
51
+ end
@@ -0,0 +1,42 @@
1
+ class RevisionAuditor < Revision
2
+
3
+ attr_reader :versionable
4
+ def initialize(versionable)
5
+ @versionable = versionable
6
+ end
7
+
8
+ def changes_original?
9
+ return true if versionable.marked_for_destruction?
10
+ return true if changes_at_least_one_attribute?
11
+ return true if changes_at_least_one_nested_association?
12
+ return false
13
+ end
14
+
15
+ private
16
+ def changes_at_least_one_attribute?
17
+ versionable_attributes.each do |attr|
18
+ attr = AttributeEncapsulator.new(attr)
19
+ return true if changed_attributes.include?(attr.key)
20
+ end
21
+ return false
22
+ end
23
+
24
+ def changes_at_least_one_nested_association?
25
+ nested_associations.each do |association|
26
+ return true if association_changed?(association)
27
+ end
28
+ return false
29
+ end
30
+
31
+ def association_changed?(association)
32
+ versionable.public_send(association).each do |child|
33
+ return true if child_changed?(child)
34
+ end
35
+ return false
36
+ end
37
+
38
+ def child_changed?(child)
39
+ child.new_record? || child.marked_for_destruction? ||
40
+ RevisionAuditor.new(child).changes_original?
41
+ end
42
+ end
@@ -0,0 +1,60 @@
1
+ class RevisionBuilder < Revision
2
+
3
+ attr_reader :versionable, :version
4
+ def initialize(args)
5
+ @versionable = args[:versionable]
6
+ @version = args[:version]
7
+ build_revision
8
+ end
9
+
10
+ private
11
+ def build_revision
12
+ mark_for_removal
13
+ build_attributes
14
+ build_children
15
+ end
16
+
17
+ def mark_for_removal
18
+ version.marked_for_removal = true if versionable.marked_for_destruction?
19
+ end
20
+
21
+ def build_attributes
22
+ versionable_attributes.each do |attr|
23
+ attr = AttributeEncapsulator.new(attr)
24
+ if changed_attributes.include?(attr.key)
25
+ build_attribute(attr)
26
+ end
27
+ end
28
+ end
29
+
30
+ def build_attribute(attr)
31
+ version_attributes.build(
32
+ name: attr.key,
33
+ new_value: attr.value,
34
+ old_value: previous_value(attr.key))
35
+ end
36
+
37
+ def build_children
38
+ nested_associations.each do |association|
39
+ versionable.public_send(association).each do |child|
40
+ build_child(child)
41
+ end
42
+ end
43
+ end
44
+
45
+ def build_child(child)
46
+ if RevisionAuditor.new(child).changes_original?
47
+ version_child = build_version_child(child)
48
+ RevisionBuilder.new(versionable: child, version: version_child)
49
+ end
50
+ end
51
+
52
+ def build_version_child(child)
53
+ if child.new_record?
54
+ version_children.build(versionable_type: child.class.name)
55
+ else
56
+ version_children.build(versionable: child)
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,3 @@
1
+ module ControlledVersioning
2
+ VERSION = "0.6"
3
+ end
@@ -0,0 +1,30 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record'
4
+
5
+ module ControlledVersioning
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include ::Rails::Generators::Migration
8
+
9
+ source_root File.expand_path('../../templates', __FILE__)
10
+
11
+ desc 'Generates (but does not run) a migration to add a versions table.'
12
+
13
+ def create_model_file
14
+ template "version.rb", "app/models/controlled_versioning/version.rb"
15
+ template "version_attribute.rb",
16
+ "app/models/controlled_versioning/version_attribute.rb"
17
+ template "version_child.rb",
18
+ "app/models/controlled_versioning/version_child.rb"
19
+ migration_template "create_versions.rb", "db/migrate/create_versions.rb"
20
+ migration_template "create_version_attributes.rb",
21
+ "db/migrate/create_version_attributes.rb"
22
+ migration_template "create_version_children.rb",
23
+ "db/migrate/create_version_children.rb"
24
+ end
25
+
26
+ def self.next_migration_number(dirname)
27
+ ::ActiveRecord::Generators::Base.next_migration_number(dirname)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ class CreateVersionAttributes < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :version_attributes do |t|
4
+ t.string :version_type, null: false
5
+ t.integer :version_id, null: false
6
+ t.string :name, null: false
7
+ t.text :old_value
8
+ t.text :new_value
9
+ end
10
+ add_index :version_attributes, [:version_type, :version_id]
11
+ end
12
+
13
+ def self.down
14
+ remove_index :version_attributes, [:version_type, :version_id]
15
+ drop_table :version_attributes
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ class CreateVersionChildren < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :version_children do |t|
4
+ t.string :version_type, null: false
5
+ t.integer :version_id, null: false
6
+ t.string :versionable_type
7
+ t.integer :versionable_id
8
+
9
+ t.boolean :marked_for_removal, null: false, default: false
10
+ end
11
+ add_index :version_children, [:version_type, :version_id]
12
+ add_index :version_children, [:versionable_type, :versionable_id]
13
+ end
14
+
15
+ def self.down
16
+ remove_index :version_children, [:version_type, :version_id]
17
+ remove_index :version_children, [:versionable_type, :versionable_id]
18
+ drop_table :version_children
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ class CreateVersions < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :versions do |t|
4
+ t.string :versionable_type, null: false
5
+ t.integer :versionable_id, null: false
6
+
7
+ t.integer :user_id
8
+
9
+ t.text :notes
10
+
11
+ t.boolean :initial, null: false, default: false
12
+
13
+ t.boolean :marked_for_removal, null: false, default: false
14
+
15
+ t.boolean :approved, null: false, default: false
16
+ t.boolean :declined, null: false, default: false
17
+ t.boolean :pending, null: false, default: true
18
+
19
+ t.datetime :created_at
20
+ end
21
+ add_index :versions, :initial
22
+ add_index :versions, [:versionable_type, :versionable_id]
23
+ end
24
+
25
+ def self.down
26
+ remove_index :versions, :initial
27
+ remove_index :versions, [:verstionable_type, :versionable_id]
28
+ drop_table :versions
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ class ControlledVersioning::Version < ActiveRecord::Base
2
+
3
+ belongs_to :versionable, polymorphic: true
4
+ belongs_to :user
5
+ has_many :version_attributes, as: :version
6
+ has_many :version_children, as: :version
7
+
8
+ validates :versionable, presence: true
9
+
10
+ def accept
11
+ RevisionAccepter.new(self)
12
+ update_attributes(pending: false, approved: true)
13
+ end
14
+
15
+ def decline
16
+ update_attributes(pending: false, declined: true)
17
+ end
18
+
19
+ end
@@ -0,0 +1,7 @@
1
+ class ControlledVersioning::VersionAttribute < ActiveRecord::Base
2
+
3
+ belongs_to :version, polymorphic: true
4
+
5
+ validates :name, presence: true
6
+
7
+ end
@@ -0,0 +1,8 @@
1
+ class ControlledVersioning::VersionChild < ActiveRecord::Base
2
+
3
+ belongs_to :versionable, polymorphic: true
4
+ belongs_to :version, polymorphic: true
5
+ has_many :version_attributes, as: :version
6
+ has_many :version_children, as: :version
7
+
8
+ end
@@ -0,0 +1,6 @@
1
+ class ArrayConverter
2
+
3
+ def self.to_s!(array)
4
+ array.map! { |s| s.to_s } if array.present?
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ class AttributeEncapsulator
2
+
3
+ attr_reader :attr
4
+ def initialize(attr)
5
+ @attr = AttrStruct.new(attr[0], attr[1])
6
+ end
7
+
8
+ def key
9
+ attr.key
10
+ end
11
+
12
+ def value
13
+ attr.value
14
+ end
15
+
16
+ private
17
+ AttrStruct = Struct.new(:key, :value)
18
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :controlled_versioning do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: controlled_versioning
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.6'
5
+ platform: ruby
6
+ authors:
7
+ - timothythehuman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: debugger
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-spork
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: factory_girl_rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: With Controlled Versioning, you can make any model versionable. This
112
+ will record suggested changes to the model, which can then be approved or declined
113
+ according to your application's design.
114
+ email:
115
+ - timothythehuman@gmail.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - config/locales/en.yml
121
+ - lib/tasks/controlled_versioning_tasks.rake
122
+ - lib/support/attribute_encapsulator.rb
123
+ - lib/support/array_converter.rb
124
+ - lib/generators/templates/create_version_children.rb
125
+ - lib/generators/templates/create_versions.rb
126
+ - lib/generators/templates/version_attribute.rb
127
+ - lib/generators/templates/version_child.rb
128
+ - lib/generators/templates/version.rb
129
+ - lib/generators/templates/create_version_attributes.rb
130
+ - lib/generators/controlled_versioning/install_generator.rb
131
+ - lib/controlled_versioning/revision_accepter.rb
132
+ - lib/controlled_versioning/revision_builder.rb
133
+ - lib/controlled_versioning/revision.rb
134
+ - lib/controlled_versioning/revision_auditor.rb
135
+ - lib/controlled_versioning/initial_version_builder.rb
136
+ - lib/controlled_versioning/version.rb
137
+ - lib/controlled_versioning.rb
138
+ - MIT-LICENSE
139
+ - Rakefile
140
+ - README.rdoc
141
+ homepage: https://github.com/timothythehuman/controlled_versioning
142
+ licenses: []
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.0.5
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: Adds model versioning to a Rails app, with the ability to approve and declined
164
+ revisions.
165
+ test_files: []