animator 0.0.4

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7144168dc13c07de16022b09f83439081574c8fb
4
+ data.tar.gz: 6af7fba48b1b1eecce204e61d68f153958134301
5
+ SHA512:
6
+ metadata.gz: 0b6a06284fb6e0642531b53b2f2cca59fd1360241f58c28340624181e20731284e57a3d5297a5059e3a5f34b52e242ce512f58e2189b2a32e08f48a545563771
7
+ data.tar.gz: 1f34b0ef28dfb97a39bb5d0d3379f91d941ba31d1c14183ff1c0d50197fd45450db395d3b4af2d4059bda7bfb02264056f05e3fc0334e4e2adf286b4debf2b58
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Alec Larsen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,25 @@
1
+ Animator
2
+ ========
3
+ Inspired by the elegance of [PaperTrail](https://github.com/airblade/paper_trail), Animator is a cleanly namespaced ActiveRecord plugin that hooks into the existing model life-cycle allowing you to to restore (`Animable#reanimate`), query (`Animable.inanimate`), and inspect (`Animable#divine`) destroyed objects including associations without the tedium and ugliness of default scopes, monkey-patched methods, and complex callbacks.
4
+
5
+ ## Getting Started
6
+ Animator is opinionated software that protects every model in the application right out of the box.
7
+
8
+ Add it to your `Gemfile` and run the `bundle` command.
9
+ ```ruby
10
+ gem 'animator'
11
+ ```
12
+
13
+ Once the gem is installed, run the `animator:install` generator to create the necessary migration and default initializer.
14
+ ```console
15
+ rails g animator:install
16
+ ```
17
+
18
+ > **Note:** To selectively enable Animator, delete the initializer in `config/initializers/animator.rb` and include `Animator::Animable` on the desired models manually.
19
+
20
+ Finally, the database must be migrated to create the `eraminhos` table before Animator will work properly.
21
+ ```console
22
+ rake db:migrate
23
+ ```
24
+
25
+ > **Note:** In the very unlikely event that `eraminhos` needs to be preserved for use in the application, Animator may be configured to use an alternative table name by editing the migration and appending `Animator::Eraminho.table_name = 'alternative_table_name_for_eraminhos'` to the initializer.
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'animator'
3
+ s.version = '0.0.4'
4
+ s.platform = Gem::Platform::RUBY
5
+ s.summary = 'Animator is a cleanly namespaced ActiveRecord plugin that hooks into the existing model life-cycle allowing you to to restore (Animable#reanimate), query (Animable.inanimate), and inspect (Animable#divine) destroyed objects including associations without the tedium and ugliness of default scopes, monkey-patched methods, and complex callbacks.'
6
+ s.description = s.summary
7
+ s.homepage = 'https://github.com/AlecLarsen/animator'
8
+ s.authors = ['Alec Larsen']
9
+ s.email = 'aleclarsen42@gmail.com'
10
+ s.license = 'MIT'
11
+
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ s.require_paths = ['lib']
16
+
17
+ s.required_rubygems_version = '>= 1.3.6'
18
+
19
+ s.add_dependency 'activerecord', ['>= 3.0', '< 5.0']
20
+ s.add_dependency 'activesupport', ['>= 3.0', '< 5.0']
21
+
22
+ s.post_install_message = <<-eos
23
+
24
+ Animator will not work properly until the eraminhos table has been created. You can generate the proper migration by running `rails g animator:install`.
25
+
26
+ eos
27
+ end
@@ -0,0 +1,7 @@
1
+ require 'animator/eraminho'
2
+ require 'animator/animable'
3
+ require 'animator/fey_relation'
4
+ require 'animator/reanimation_error'
5
+
6
+ module Animator
7
+ end
@@ -0,0 +1,117 @@
1
+ module Animator
2
+ module Animable
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def reanimate!(id, options = {})
7
+ Eraminho.find_by!(animable_class: name, animable_id: id).animable!.reanimate!(options)
8
+ end
9
+
10
+ def reanimate(id, options = {})
11
+ reanimate!(id, options) rescue nil
12
+ end
13
+
14
+ def divine(id, options = {}, &block)
15
+ options = { validate: false }.merge(options)
16
+
17
+ result = nil
18
+
19
+ transaction do
20
+ instance = reanimate!(id, options)
21
+ result = instance.instance_exec(&block)
22
+ raise ActiveRecord::Rollback
23
+ end
24
+
25
+ result
26
+ end
27
+
28
+ def inanimate(transaction_uuid = nil, relation = all)
29
+ FeyRelation.new(relation.klass, transaction_uuid).merge(relation)
30
+ end
31
+ end
32
+
33
+ def divine(options = {}, &block)
34
+ options = { validate: false }.merge(options)
35
+
36
+ result = nil
37
+ eraminho = @eraminho
38
+ destroyed = @destroyed
39
+
40
+ transaction do
41
+ reanimate!(options)
42
+ result = instance_exec(&block)
43
+ raise ActiveRecord::Rollback
44
+ end
45
+
46
+ @eraminho = eraminho
47
+ @destroyed = destroyed
48
+ result
49
+ end
50
+
51
+ def animable?
52
+ destroyed? && !@eraminho.nil?
53
+ end
54
+
55
+ def reanimate!(options = {}, validation_queue = nil)
56
+ klass = self.class
57
+ options = { force: false, transactional: true, validate: true }.merge(options)
58
+
59
+ raise(ReanimationError, "#{inspect} is not animable.") unless animable?
60
+
61
+ transaction do
62
+ if validation_queue
63
+ run_callbacks(:reanimate) do
64
+ if options[:transactional]
65
+ Eraminho.with_transaction_uuid(@eraminho.transaction_uuid).find_each do |eraminho|
66
+ if options[:force]
67
+ eraminho.animable!.reanimate(options.merge(transactional: false, force: false), validation_queue)
68
+ else
69
+ eraminho.animable!.reanimate!(options.merge(transactional: false, force: false), validation_queue)
70
+ end
71
+ end
72
+ else
73
+ klass.unscoped.insert arel_attributes_with_values_for_create attribute_names
74
+ validation_queue << self if options[:validate]
75
+ @eraminho.delete
76
+ end
77
+ end
78
+
79
+ @eraminho = nil
80
+ @destroyed = false
81
+ else
82
+ validation_queue = []
83
+
84
+ reanimate!(options, validation_queue)
85
+
86
+ validation_queue.each do |animable|
87
+ unless animable.valid?(:reanimate)
88
+ raise(ActiveRecord::RecordInvalid.new(animable))
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ self
95
+ end
96
+
97
+ def reanimate(options = {}, validation_queue = nil)
98
+ reanimate!(options, validation_queue) rescue self
99
+ end
100
+
101
+ def eraminho
102
+ @eraminho
103
+ end
104
+
105
+ included do
106
+ define_callbacks :reanimate
107
+
108
+ around_destroy do |animable, &block|
109
+ block.call
110
+
111
+ unless animable?
112
+ @eraminho = Eraminho.create!(animable: animable)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,51 @@
1
+ require 'securerandom'
2
+ require 'yaml'
3
+
4
+ module Animator
5
+ class Eraminho < ActiveRecord::Base
6
+ scope :with_animable_id, ->(animable_id) { where(animable_id: animable_id) }
7
+ scope :with_animable_class, ->(animable_class) { where(animable_class: animable_class) }
8
+
9
+ scope :with_animable_attribute, ->(attribute_name, value) { where(arel_table[:anima].matches("% #{YAML.dump(attribute_name.to_s => value).gsub(/^---\n/, '')}%")) }
10
+ scope :with_animable_attributes, ->(attributes) { attributes.to_a.reduce(all) { |relation, key_value_pair| relation.with_animable_attribute(*key_value_pair) } }
11
+
12
+ scope :with_transaction_uuid, ->(transaction_uuid) { where(transaction_uuid: transaction_uuid) }
13
+
14
+ def animable=(animable)
15
+ if animable
16
+ raise(TypeError, "Attempted to set #{animable.inspect} as the animable of an Eraminho, but #{animable.class.name} has not included Animator::Animable") unless animable.is_a?(Animable)
17
+
18
+ self.animable_class = animable.class.name
19
+ self.animable_id = animable[animable.class.primary_key] if animable.class.primary_key
20
+ self.transaction_uuid = get_current_transaction_uuid(animable.class.connection)
21
+ self.anima = YAML.dump(animable)
22
+ end
23
+
24
+ @animable = animable
25
+ end
26
+
27
+ def animable
28
+ animable! rescue nil
29
+ end
30
+
31
+ def animable!
32
+ unless @animable
33
+ animable_class.constantize rescue nil # This is required because of ActiveSupport's lazy loading
34
+ @animable = YAML.load(anima)
35
+
36
+ raise(ReanimationError, "#{@animable.class.name} has not included Animator::Animable") unless @animable.is_a?(Animable)
37
+
38
+ @animable.instance_variable_set(:@destroyed, true)
39
+ @animable.instance_variable_set(:@eraminho, self)
40
+ end
41
+
42
+ @animable
43
+ end
44
+
45
+ private
46
+
47
+ def get_current_transaction_uuid(connection)
48
+ connection.current_transaction.instance_eval { @__animator_transaction_uuid__ ||= SecureRandom.uuid }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,249 @@
1
+ module Animator
2
+ class FeyRelation
3
+ attr_reader :transaction_uuid
4
+ attr_reader :where_values_hash
5
+ attr_reader :klass
6
+
7
+ def initialize(klass, transaction_uuid = nil, where_values_hash = {}, &block)
8
+ @transaction_uuid = transaction_uuid
9
+ @where_values_hash = where_values_hash
10
+ @klass = klass
11
+
12
+ instance_exec(&block) if block
13
+ end
14
+
15
+ def spawn(&block)
16
+ self.class.new(@klass, @transaction_uuid, @where_values_hash, &block)
17
+ end
18
+
19
+ def where(where_values_hash, &block)
20
+ self.class.new(@klass, @transaction_uuid, @where_values_hash.merge(where_values_hash), &block)
21
+ end
22
+
23
+ def merge(relation)
24
+ if relation.is_a?(ActiveRecord::Relation)
25
+ raise(NotImplementedError, "#{self.class.name} does not support joins.") if relation.joins_values.any? || relation.includes_values.any? || relation.joined_includes_values.any?
26
+ raise(NotImplementedError, "#{self.class.name} does not support custom select.") if relation.select_values.any?
27
+ raise(NotImplementedError, "#{self.class.name} does not support aggragation.") if relation.group_values.any? || relation.having_values.any?
28
+ end
29
+
30
+ if relation.respond_to?(:klass, false)
31
+ raise('Class mismatch while attempting to merge into #{self.class.name}') unless relation.klass == @klass
32
+ end
33
+
34
+ where(relation.where_values_hash) do
35
+ @limit_value = relation.limit_value if relation.respond_to?(:limit_value, false)
36
+ @offset_value = relation.offset_value if relation.respond_to?(:offset_value, false)
37
+ end
38
+ end
39
+
40
+ def all
41
+ spawn
42
+ end
43
+
44
+ def to_a
45
+ eraminho_relation.map(&:animable)
46
+ end
47
+
48
+ def take
49
+ eraminho_relation.take.try(:animable)
50
+ end
51
+
52
+ def take!
53
+ take || raise(ActiveRecord::RecordNotFound)
54
+ end
55
+
56
+ def find_by(where_values_hash)
57
+ where(where_values_hash).take
58
+ end
59
+
60
+ def find_by!(where_values_hash)
61
+ where(where_values_hash).take!
62
+ end
63
+
64
+ def find(id)
65
+ find_by!(@klass.primary_key => id)
66
+ end
67
+
68
+ def first(limit = nil)
69
+ if limit
70
+ eraminho_relation.first(limit).map(&:animable)
71
+ else
72
+ eraminho_relation.first.try(:animable)
73
+ end
74
+ end
75
+
76
+ def first!
77
+ first || raise(ActiveRecord::RecordNotFound)
78
+ end
79
+
80
+ def last(limit = nil)
81
+ if limit
82
+ eraminho_relation.last(limit).map(&:animable)
83
+ else
84
+ eraminho_relation.last.try(:animable)
85
+ end
86
+ end
87
+
88
+ def last!
89
+ last || raise(ActiveRecord::RecordNotFound)
90
+ end
91
+
92
+ def exists?(where_values_hash = nil)
93
+ if where_values_hash
94
+ where(where_values_hash).exists?
95
+ else
96
+ eraminho_relation.exists?
97
+ end
98
+ end
99
+
100
+ def count
101
+ eraminho_relation.count
102
+ end
103
+
104
+ def pluck(*columns)
105
+ if columns.count > 1
106
+ eraminho_relation.map { |eraminho| columns.map { |column| eraminho.animable!.public_send(column) } }
107
+ else
108
+ eraminho_relation.map { |eraminho| eraminho.animable!.public_send(columns.first) }
109
+ end
110
+ end
111
+
112
+ def limit(limit_value)
113
+ spawn do
114
+ @limit_value = limit_value
115
+ end
116
+ end
117
+
118
+ def offset(offset_value)
119
+ spawn do
120
+ @offset_value = offset_value
121
+ end
122
+ end
123
+
124
+ def ids
125
+ eraminho_relation.pluck(:animable_id)
126
+ end
127
+
128
+ def find_each(options = {}, &block)
129
+ eraminho_relation.find_each(options) { |eraminho| block.call(eraminho.animable!) }
130
+ end
131
+
132
+ def reset
133
+ eraminho_relation.reset
134
+ end
135
+
136
+ def loaded?
137
+ eraminho_relation.loaded?
138
+ end
139
+
140
+ def inspect
141
+ entries = to_a.take(11).map!(&:inspect)
142
+ entries[10] = '...' if entries.size == 11
143
+
144
+ "#<#{self.class.name} [#{entries.join(', ')}]>"
145
+ end
146
+
147
+ def ==(other)
148
+ case other
149
+ when FeyRelation
150
+ eraminho_relation.to_sql == other.eraminho_relation.to_sql
151
+ when Array
152
+ to_a == other
153
+ end
154
+ end
155
+
156
+ def reanimate_all!(options = {})
157
+ options = { force: false, transactional: true, validate: true }.merge(options)
158
+
159
+ validation_queue = []
160
+
161
+ Eraminho.transaction do
162
+ if options[:transactional]
163
+ Eraminho.with_transaction_uuid(eraminho_relation.pluck(:transaction_uuid))
164
+ else
165
+ eraminho_relation
166
+ end.find_each do |eraminho|
167
+ if options[:force]
168
+ eraminho.animable!.reanimate(options.merge(transactional: false, force: false), validation_queue)
169
+ else
170
+ eraminho.animable!.reanimate!(options.merge(transactional: false, force: false), validation_queue)
171
+ end
172
+ end
173
+
174
+ validation_queue.each do |animable|
175
+ unless animable.valid?(:reanimate)
176
+ raise(ActiveRecord::RecordInvalid.new(animable))
177
+ end
178
+ end
179
+
180
+ reset
181
+ end
182
+
183
+ true
184
+ end
185
+
186
+ def reanimate_all(options = {})
187
+ reanimate_all! rescue false
188
+ end
189
+
190
+ def to_active_record_relation
191
+ @_active_record_relation ||= @klass.where(@where_values_hash)
192
+ end
193
+
194
+ def divine(options = {}, &block)
195
+ options = { validate: false }.merge(options)
196
+
197
+ result = nil
198
+
199
+ @klass.transaction do
200
+ reanimate_all!(options)
201
+ result = to_active_record_relation.instance_exec(&block)
202
+ raise ActiveRecord::Rollback
203
+ end
204
+
205
+ result
206
+ end
207
+
208
+ def respond_to_missing?(method_name, include_private = false)
209
+ @klass.respond_to?(method_name, false) || [].respond_to?(method_name, false) || super
210
+ end
211
+
212
+ def method_missing(method_name, *args, &block)
213
+ if @klass.respond_to?(method_name, false)
214
+ result = to_active_record_relation.public_send(method_name, *args, &block)
215
+
216
+ if result.respond_to?(:where_values_hash)
217
+ result = merge(result)
218
+ else
219
+ result
220
+ end
221
+ elsif [].respond_to?(method_name, false)
222
+ to_a.public_send(method_name, *args, &block)
223
+ else
224
+ super
225
+ end
226
+ end
227
+
228
+ protected
229
+
230
+ def eraminho_relation
231
+ unless @eraminho_relation
232
+ @eraminho_relation = Eraminho.with_animable_class(@klass.name)
233
+
234
+ @eraminho_relation = @eraminho_relation.with_transaction_uuid(@transaction_uuid) if @transaction_uuid
235
+
236
+ animable_id = @where_values_hash[@klass.primary_key] || @where_values_hash[@klass.primary_key.to_sym]
237
+ animable_attributes = @where_values_hash.reject { |key| key == @klass.primary_key || key == @klass.primary_key.to_sym }
238
+
239
+ @eraminho_relation = @eraminho_relation.with_animable_id(animable_id) if animable_id
240
+ @eraminho_relation = @eraminho_relation.with_animable_attributes(animable_attributes)
241
+
242
+ @eraminho_relation = @eraminho_relation.limit(@limit_value) if @limit_value
243
+ @eraminho_relation = @eraminho_relation.offset(@offset_value) if @offset_value
244
+ end
245
+
246
+ @eraminho_relation
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,4 @@
1
+ module Animator
2
+ class ReanimationError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,27 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/active_record'
3
+
4
+ module Animator
5
+ class InstallGenerator < ::Rails::Generators::Base
6
+ include ::Rails::Generators::Migration
7
+
8
+ def self.next_migration_number(dirname)
9
+ ::ActiveRecord::Generators::Base.next_migration_number(dirname)
10
+ end
11
+
12
+ source_root File.expand_path('../templates', __FILE__)
13
+
14
+ def create_migration_file
15
+ migration_template 'create_eraminhos.rb', 'db/migrate/create_eraminhos.rb'
16
+ create_file_template 'animator.rb', 'config/initializers/animator.rb'
17
+ end
18
+
19
+ private
20
+
21
+ def create_file_template(source, destination)
22
+ source = File.expand_path(find_in_source_paths(source.to_s))
23
+ context = instance_eval('binding')
24
+ create_file(destination, ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context))
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ class ActiveRecord::Base
2
+ include Animator::Animable
3
+ end
@@ -0,0 +1,15 @@
1
+ class CreateEraminhos < ActiveRecord::Migration
2
+ def change
3
+ create_table :eraminhos do |t|
4
+ t.string :transaction_uuid, null: false
5
+ t.string :animable_class, null: false
6
+ t.integer :animable_id, null: true # Support for tables without a primary key
7
+ t.text :anima, null: false
8
+ t.datetime :created_at, null: false
9
+ end
10
+
11
+ add_index :eraminhos, [:animable_class, :animable_id]
12
+ add_index :eraminhos, [:animable_class, :transaction_uuid]
13
+ add_index :eraminhos, [:transaction_uuid]
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: animator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Alec Larsen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '5.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '3.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '5.0'
53
+ description: Animator is a cleanly namespaced ActiveRecord plugin that hooks into
54
+ the existing model life-cycle allowing you to to restore (Animable#reanimate), query
55
+ (Animable.inanimate), and inspect (Animable#divine) destroyed objects including
56
+ associations without the tedium and ugliness of default scopes, monkey-patched methods,
57
+ and complex callbacks.
58
+ email: aleclarsen42@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE
66
+ - README.md
67
+ - animator.gemspec
68
+ - lib/animator.rb
69
+ - lib/animator/animable.rb
70
+ - lib/animator/eraminho.rb
71
+ - lib/animator/fey_relation.rb
72
+ - lib/animator/reanimation_error.rb
73
+ - lib/generators/animator/install_generator.rb
74
+ - lib/generators/animator/templates/animator.rb
75
+ - lib/generators/animator/templates/create_eraminhos.rb
76
+ homepage: https://github.com/AlecLarsen/animator
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message: |2+
81
+
82
+ Animator will not work properly until the eraminhos table has been created. You can generate the proper migration by running `rails g animator:install`.
83
+
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.3.6
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.4.5
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Animator is a cleanly namespaced ActiveRecord plugin that hooks into the
103
+ existing model life-cycle allowing you to to restore (Animable#reanimate), query
104
+ (Animable.inanimate), and inspect (Animable#divine) destroyed objects including
105
+ associations without the tedium and ugliness of default scopes, monkey-patched methods,
106
+ and complex callbacks.
107
+ test_files: []