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.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +25 -0
- data/animator.gemspec +27 -0
- data/lib/animator.rb +7 -0
- data/lib/animator/animable.rb +117 -0
- data/lib/animator/eraminho.rb +51 -0
- data/lib/animator/fey_relation.rb +249 -0
- data/lib/animator/reanimation_error.rb +4 -0
- data/lib/generators/animator/install_generator.rb +27 -0
- data/lib/generators/animator/templates/animator.rb +3 -0
- data/lib/generators/animator/templates/create_eraminhos.rb +15 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
@@ -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
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
|
+
|
data/README.md
ADDED
@@ -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.
|
data/animator.gemspec
ADDED
@@ -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
|
data/lib/animator.rb
ADDED
@@ -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,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,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: []
|