undo 0.0.1
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/.coveralls.yml +1 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +19 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +191 -0
- data/Rakefile +10 -0
- data/lib/undo.rb +23 -0
- data/lib/undo/config.rb +27 -0
- data/lib/undo/environment.rb +3 -0
- data/lib/undo/model.rb +33 -0
- data/lib/undo/serializer/simple.rb +23 -0
- data/lib/undo/storage/memory_adapter.rb +23 -0
- data/lib/undo/version.rb +3 -0
- data/spec/acceptance/it_works_spec.rb +7 -0
- data/spec/acceptance/undo_deletion_spec.rb +14 -0
- data/spec/factories.rb +6 -0
- data/spec/it_works_spec.rb +8 -0
- data/spec/rails_app/.gitignore +4 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/models/.gitkeep +0 -0
- data/spec/rails_app/app/models/user.rb +2 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +13 -0
- data/spec/rails_app/config/boot.rb +6 -0
- data/spec/rails_app/config/database.yml +22 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +23 -0
- data/spec/rails_app/config/environments/production.rb +50 -0
- data/spec/rails_app/config/environments/test.rb +34 -0
- data/spec/rails_app/config/routes.rb +2 -0
- data/spec/rails_app/db/migrate/20140214213610_create_users.rb +10 -0
- data/spec/rails_app/db/schema.rb +23 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/spec_helper_lite.rb +12 -0
- data/spec/spec_helper_rails.rb +22 -0
- data/spec/undo/model_spec.rb +36 -0
- data/spec/undo/serializer/simple_spec.rb +19 -0
- data/spec/undo_spec.rb +46 -0
- data/undo.gemspec +33 -0
- metadata +199 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: be7c69cbf8e0489d7d3ee42a63d3791ace4a85ee
|
4
|
+
data.tar.gz: 8652a478948f1e5cd1ea38e1c7943d025f755b4d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aa050823366a0684e076aa024f2b5a90078f9c6e7df8a6e3cfaf1a08134025b193bdd95383b2bdcb705d8fc376951d73eda5b367efdc4ab35b6caaafdc3fd347
|
7
|
+
data.tar.gz: 96d0ab84f7c9269d9d032b0ec55f0f6d02b0d6efaafba220696f2b3eb9730f368b974d41ef07a1f4311ef0baa0424339d383baa737fa7f0dd0aeabca73c1c03d
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
undo
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.0-p0
|
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.1
|
4
|
+
- 2.0
|
5
|
+
- 1.9.3
|
6
|
+
- ruby-head
|
7
|
+
- rbx-19mode
|
8
|
+
- jruby-19mode
|
9
|
+
- jruby-head
|
10
|
+
|
11
|
+
matrix:
|
12
|
+
allow_failures:
|
13
|
+
- rvm: ruby-head
|
14
|
+
- rvm: rbx-19mode
|
15
|
+
- rvm: jruby-19mode
|
16
|
+
- rvm: jruby-head
|
17
|
+
|
18
|
+
script:
|
19
|
+
- "bundle exec rake ci:all"
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Alexander Paramonov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
Undo
|
2
|
+
==========
|
3
|
+
[](http://travis-ci.org/AlexParamonov/undo)
|
4
|
+
[](http://gemnasium.com/AlexParamonov/undo)
|
5
|
+
[](https://coveralls.io/r/AlexParamonov/undo?branch=master)
|
6
|
+
|
7
|
+
Undo last operation on object.
|
8
|
+
Undo gem allows to use custom adapters for storage (Redis,
|
9
|
+
ActiveRecord, etc). And custom serializers when need (ActiveRecord, Virtus, etc)
|
10
|
+
|
11
|
+
Contents
|
12
|
+
---------
|
13
|
+
1. Installation
|
14
|
+
1. Requirements
|
15
|
+
1. Usage
|
16
|
+
1. Undo operation
|
17
|
+
1. Configuration options
|
18
|
+
1. In place configuration
|
19
|
+
1. Contacts
|
20
|
+
1. Compatibility
|
21
|
+
1. Contributing
|
22
|
+
1. Copyright
|
23
|
+
|
24
|
+
Installation
|
25
|
+
------------
|
26
|
+
|
27
|
+
Add this line to your application's Gemfile:
|
28
|
+
|
29
|
+
gem 'undo'
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
$ bundle
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
$ gem install undo
|
38
|
+
|
39
|
+
Requirements
|
40
|
+
------------
|
41
|
+
1. Ruby 1.9 or above
|
42
|
+
1. gem virtus ~> 1.0
|
43
|
+
|
44
|
+
Usage
|
45
|
+
-----
|
46
|
+
|
47
|
+
### Undo operation
|
48
|
+
|
49
|
+
Wrap object in Undo decorator:
|
50
|
+
|
51
|
+
``` ruby
|
52
|
+
Undo.wrap object
|
53
|
+
```
|
54
|
+
|
55
|
+
And use it as usual afterwards. Undo gem will store object state on each hit to `mutator methods`.
|
56
|
+
By default mutator_methods are `update`, `delete`, `destroy`.
|
57
|
+
To append custom mutator_methods use
|
58
|
+
|
59
|
+
``` ruby
|
60
|
+
Undo.configure do |config|
|
61
|
+
config.mutator_methods += [:put, :push, :pop]
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
To restore previous version
|
66
|
+
|
67
|
+
```
|
68
|
+
Undo.restore uuid
|
69
|
+
```
|
70
|
+
|
71
|
+
`uuid` is provided by wrapped object:
|
72
|
+
|
73
|
+
```
|
74
|
+
Undo.wrap(object).uuid
|
75
|
+
```
|
76
|
+
|
77
|
+
By default it is using `SecureRandom.uuid`.
|
78
|
+
To define custom uuid generator use `uuid_generator` option:
|
79
|
+
|
80
|
+
``` ruby
|
81
|
+
Undo.configure do |config|
|
82
|
+
config.uuid_generator = ->(object) { "#{object.class.name}_#{object.id}" }
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
### Configuration options
|
87
|
+
`storage` option responsible for putting and fetching object state to or from some storage.
|
88
|
+
Implement `put(uuid, object)` and `fetch(uuid)` methods. See MemoryAdapter for example.
|
89
|
+
See also [documentation](http://github.com/AlexParamonov/undo)
|
90
|
+
on project repository for currently available storage adapters.
|
91
|
+
If provided storage cant handle objects (most of the storage works with own formats as json for example),
|
92
|
+
pass `serializer` to it:
|
93
|
+
|
94
|
+
``` ruby
|
95
|
+
Undo.configure do |config|
|
96
|
+
config.storage = AnotherStorage.new(serializer: config.serializer)
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
By default here is very basic `Serializer::Simple`.
|
101
|
+
There are no more serializers available now, but check
|
102
|
+
[documentation](http://github.com/AlexParamonov/undo) on project
|
103
|
+
repository for currently available serializers.
|
104
|
+
|
105
|
+
Serializer is not used by `Undo` gem directly. It mean to be used in
|
106
|
+
storage adopters to serialize and deserialize data to required format.
|
107
|
+
Storage adapter may use serializer this way:
|
108
|
+
|
109
|
+
``` ruby
|
110
|
+
json = serializer.to_json object # in put method
|
111
|
+
return serializer.load_from_json json # in fetch method
|
112
|
+
|
113
|
+
xml = serializer.to_xml object
|
114
|
+
object = serializer.load_from_xml xml
|
115
|
+
```
|
116
|
+
|
117
|
+
Usage of serializer is optional, some storages does not need them.
|
118
|
+
Serializer has the responsibility to write object to persistence
|
119
|
+
(load_from\_\* methods) This seems a good candinate to extraction to own
|
120
|
+
class (Deserializer or Loader) but due to to\_\* and load_from\_\*
|
121
|
+
method are tightly coupled with data format it is in one class now.
|
122
|
+
Let me know using the Github feedback (create an issue) if you have
|
123
|
+
any idea on this topic.
|
124
|
+
|
125
|
+
`uuid_generator` option allows to setup custom uuid generator.
|
126
|
+
|
127
|
+
By default it is using `SecureRandom.uuid`.
|
128
|
+
To define custom uuid generator use `uuid_generator` option:
|
129
|
+
|
130
|
+
``` ruby
|
131
|
+
Undo.configure do |config|
|
132
|
+
config.uuid_generator = ->(object) { "#{object.class.name}_#{object.id}" }
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
`mutator methods` option defines a list of methods that will trigger storage#put
|
137
|
+
By default mutator_methods are `update`, `delete`, `destroy`.
|
138
|
+
To set custom mutator_methods use
|
139
|
+
|
140
|
+
``` ruby
|
141
|
+
Undo.configure do |config|
|
142
|
+
config.mutator_methods = [:put, :push, :pop]
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
### In place configuration
|
147
|
+
Any configuration option from previous chapter can be applied in place
|
148
|
+
only for given operation.
|
149
|
+
To restore object from another storage use `storage` option:
|
150
|
+
|
151
|
+
``` ruby
|
152
|
+
Undo.restore uuid, storage: AnotherStorage.new
|
153
|
+
```
|
154
|
+
|
155
|
+
To wrap an object using custom serializer use `serializer` option:
|
156
|
+
|
157
|
+
``` ruby
|
158
|
+
Undo.wrap object, serializer: AnotherSerializer.new
|
159
|
+
```
|
160
|
+
|
161
|
+
Contacts
|
162
|
+
-------------
|
163
|
+
Have questions or recommendations? Contact me via `alexander.n.paramonov@gmail.com`
|
164
|
+
Found a bug or have enhancement request? You are welcome at [Github bugtracker](https://github.com/AlexParamonov/undo/issues)
|
165
|
+
|
166
|
+
|
167
|
+
Compatibility
|
168
|
+
-------------
|
169
|
+
tested with Ruby
|
170
|
+
|
171
|
+
* 2.1
|
172
|
+
* 2.0
|
173
|
+
* 1.9.3
|
174
|
+
* rbx-19mode
|
175
|
+
* ruby-head
|
176
|
+
|
177
|
+
See [build history](http://travis-ci.org/#!/AlexParamonov/undo/builds)
|
178
|
+
|
179
|
+
|
180
|
+
## Contributing
|
181
|
+
|
182
|
+
1. Fork repository ( http://github.com/AlexParamonov/undo/fork )
|
183
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
184
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
185
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
186
|
+
5. Create new Pull Request
|
187
|
+
|
188
|
+
Copyright
|
189
|
+
---------
|
190
|
+
Copyright © 2014 Alexander Paramonov.
|
191
|
+
Released under the MIT License. See the LICENSE file for further details.
|
data/Rakefile
ADDED
data/lib/undo.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "undo/version"
|
2
|
+
require "undo/config"
|
3
|
+
|
4
|
+
module Undo
|
5
|
+
require "undo/model"
|
6
|
+
|
7
|
+
def self.configure(&block)
|
8
|
+
yield(config) if block_given?
|
9
|
+
config
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.config
|
13
|
+
@config ||= Undo::Config.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.wrap(object, *args)
|
17
|
+
Model.new object, *args
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.restore(uuid, options = {})
|
21
|
+
config.with(options).storage.fetch uuid
|
22
|
+
end
|
23
|
+
end
|
data/lib/undo/config.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "virtus"
|
2
|
+
|
3
|
+
module Undo
|
4
|
+
class Config
|
5
|
+
include Virtus.model
|
6
|
+
|
7
|
+
attribute :mutator_methods, Array[Symbol], default: [:update, :delete, :destroy]
|
8
|
+
|
9
|
+
attribute :uuid_generator, Proc, default: ->(config, _) {
|
10
|
+
require "securerandom"
|
11
|
+
->(object) { SecureRandom.uuid }
|
12
|
+
}
|
13
|
+
attribute :storage, Object, default: ->(config, _) {
|
14
|
+
require "undo/storage/memory_adapter"
|
15
|
+
Undo::Storage::MemoryAdapter.new
|
16
|
+
}
|
17
|
+
attribute :serializer, Object, default: ->(config, _) {
|
18
|
+
require "undo/serializer/simple"
|
19
|
+
Undo::Serializer::Simple.new
|
20
|
+
}
|
21
|
+
|
22
|
+
def with(attribute_updates = {}, &block)
|
23
|
+
return self if attribute_updates.empty?
|
24
|
+
self.class.new attribute_set.get(self).merge(attribute_updates)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/undo/model.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Undo
|
2
|
+
class Model < SimpleDelegator
|
3
|
+
def initialize(object, options = {})
|
4
|
+
@object = object
|
5
|
+
@config = config.with options
|
6
|
+
super object
|
7
|
+
end
|
8
|
+
|
9
|
+
def uuid
|
10
|
+
@uuid ||= object.respond_to?(:uuid) ? object.uuid : generate_uuid
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(method, *args, &block)
|
14
|
+
store if config.mutator_methods.include? method
|
15
|
+
super method, *args, &block
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
attr_reader :object
|
20
|
+
|
21
|
+
def generate_uuid
|
22
|
+
config.uuid_generator.call object
|
23
|
+
end
|
24
|
+
|
25
|
+
def store
|
26
|
+
config.storage.put uuid, object
|
27
|
+
end
|
28
|
+
|
29
|
+
def config
|
30
|
+
@config ||= Undo.config
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Undo
|
4
|
+
module Serializer
|
5
|
+
class Simple
|
6
|
+
def to_json(object)
|
7
|
+
object.to_json
|
8
|
+
end
|
9
|
+
|
10
|
+
def load_from_json(json)
|
11
|
+
JSON.parse json
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_xml(object)
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_from_xml(xml)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Undo
|
2
|
+
module Storage
|
3
|
+
class MemoryAdapter
|
4
|
+
def initialize(options = {})
|
5
|
+
end
|
6
|
+
|
7
|
+
def put(uuid, object)
|
8
|
+
storage[uuid] = object
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch(uuid)
|
12
|
+
storage.fetch uuid
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
attr_writer :storage
|
17
|
+
|
18
|
+
def storage
|
19
|
+
@storage ||= {}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/undo/version.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "spec_helper_rails"
|
2
|
+
|
3
|
+
describe "Undo deletion" do
|
4
|
+
subject { Undo }
|
5
|
+
|
6
|
+
it "reverts user deletion" do
|
7
|
+
user = create :user
|
8
|
+
undoable_model = subject.wrap user
|
9
|
+
undoable_model.destroy
|
10
|
+
restored_user = subject.restore undoable_model.uuid
|
11
|
+
|
12
|
+
expect(restored_user).to eq user
|
13
|
+
end
|
14
|
+
end
|
data/spec/factories.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
require File.expand_path('../config/application', __FILE__)
|
5
|
+
require 'rake'
|
6
|
+
|
7
|
+
RailsApp::Application.load_tasks
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
require "rails/all"
|
4
|
+
|
5
|
+
# If you have a Gemfile, require the gems listed there, including any gems
|
6
|
+
# you've limited to :test, :development, or :production.
|
7
|
+
Bundler.require(:default, Rails.env) if defined?(Bundler)
|
8
|
+
|
9
|
+
module RailsApp
|
10
|
+
class Application < Rails::Application
|
11
|
+
I18n.enforce_available_locales = false
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# SQLite version 3.x
|
2
|
+
# gem install sqlite3
|
3
|
+
development:
|
4
|
+
adapter: sqlite3
|
5
|
+
database: db/development.sqlite3
|
6
|
+
pool: 5
|
7
|
+
timeout: 5000
|
8
|
+
|
9
|
+
# Warning: The database defined as "test" will be erased and
|
10
|
+
# re-generated from your development database when you run "rake".
|
11
|
+
# Do not set this db to the same as development or production.
|
12
|
+
test:
|
13
|
+
adapter: sqlite3
|
14
|
+
database: db/test.sqlite3
|
15
|
+
pool: 5
|
16
|
+
timeout: 5000
|
17
|
+
|
18
|
+
production:
|
19
|
+
adapter: sqlite3
|
20
|
+
database: db/production.sqlite3
|
21
|
+
pool: 5
|
22
|
+
timeout: 5000
|
@@ -0,0 +1,23 @@
|
|
1
|
+
RailsApp::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# In the development environment your application's code is reloaded on
|
5
|
+
# every request. This slows down response time but is perfect for development
|
6
|
+
# since you don't have to restart the webserver when you make code changes.
|
7
|
+
config.cache_classes = false
|
8
|
+
config.eager_load = false
|
9
|
+
|
10
|
+
# Show full error reports and disable caching
|
11
|
+
config.consider_all_requests_local = true
|
12
|
+
config.action_controller.perform_caching = false
|
13
|
+
|
14
|
+
# Don't care if the mailer can't send
|
15
|
+
config.action_mailer.raise_delivery_errors = false
|
16
|
+
|
17
|
+
# Print deprecation notices to the Rails logger
|
18
|
+
config.active_support.deprecation = :log
|
19
|
+
|
20
|
+
# Only use best-standards-support built into browsers
|
21
|
+
config.action_dispatch.best_standards_support = :builtin
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
RailsApp::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# The production environment is meant for finished, "live" apps.
|
5
|
+
# Code is not reloaded between requests
|
6
|
+
config.cache_classes = true
|
7
|
+
config.eager_load = true
|
8
|
+
|
9
|
+
# Full error reports are disabled and caching is turned on
|
10
|
+
config.consider_all_requests_local = false
|
11
|
+
config.action_controller.perform_caching = true
|
12
|
+
|
13
|
+
# Specifies the header that your server uses for sending files
|
14
|
+
config.action_dispatch.x_sendfile_header = "X-Sendfile"
|
15
|
+
|
16
|
+
# For nginx:
|
17
|
+
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
|
18
|
+
|
19
|
+
# If you have no front-end server that supports something like X-Sendfile,
|
20
|
+
# just comment this out and Rails will serve the files
|
21
|
+
|
22
|
+
# See everything in the log (default is :info)
|
23
|
+
# config.log_level = :debug
|
24
|
+
|
25
|
+
# Use a different logger for distributed setups
|
26
|
+
# config.logger = SyslogLogger.new
|
27
|
+
|
28
|
+
# Use a different cache store in production
|
29
|
+
# config.cache_store = :mem_cache_store
|
30
|
+
|
31
|
+
# Disable Rails's static asset server
|
32
|
+
# In production, Apache or nginx will already do this
|
33
|
+
config.serve_static_assets = false
|
34
|
+
|
35
|
+
# Enable serving of images, stylesheets, and javascripts from an asset server
|
36
|
+
# config.action_controller.asset_host = "http://assets.example.com"
|
37
|
+
|
38
|
+
# Disable delivery errors, bad email addresses will be ignored
|
39
|
+
# config.action_mailer.raise_delivery_errors = false
|
40
|
+
|
41
|
+
# Enable threaded mode
|
42
|
+
# config.threadsafe!
|
43
|
+
|
44
|
+
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
45
|
+
# the I18n.default_locale when a translation can not be found)
|
46
|
+
config.i18n.fallbacks = true
|
47
|
+
|
48
|
+
# Send deprecation notices to registered listeners
|
49
|
+
config.active_support.deprecation = :notify
|
50
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
RailsApp::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# The test environment is used exclusively to run your application's
|
5
|
+
# test suite. You never need to work with it otherwise. Remember that
|
6
|
+
# your test database is "scratch space" for the test suite and is wiped
|
7
|
+
# and recreated between test runs. Don't rely on the data there!
|
8
|
+
config.cache_classes = true
|
9
|
+
config.eager_load = false
|
10
|
+
|
11
|
+
# Show full error reports and disable caching
|
12
|
+
config.consider_all_requests_local = true
|
13
|
+
config.action_controller.perform_caching = false
|
14
|
+
|
15
|
+
# Raise exceptions instead of rendering exception templates
|
16
|
+
config.action_dispatch.show_exceptions = false
|
17
|
+
|
18
|
+
# Disable request forgery protection in test environment
|
19
|
+
config.action_controller.allow_forgery_protection = false
|
20
|
+
|
21
|
+
# Tell Action Mailer not to deliver emails to the real world.
|
22
|
+
# The :test delivery method accumulates sent emails in the
|
23
|
+
# ActionMailer::Base.deliveries array.
|
24
|
+
config.action_mailer.delivery_method = :test
|
25
|
+
config.action_mailer.default_url_options = { :host => 'www.example.com' }
|
26
|
+
|
27
|
+
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
28
|
+
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
29
|
+
# like if you have constraints or database-specific column types
|
30
|
+
# config.active_record.schema_format = :sql
|
31
|
+
|
32
|
+
# Print deprecation notices to the stderr
|
33
|
+
config.active_support.deprecation = :stderr
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# This file is auto-generated from the current state of the database. Instead
|
3
|
+
# of editing this file, please use the migrations feature of Active Record to
|
4
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
5
|
+
#
|
6
|
+
# Note that this schema.rb definition is the authoritative source for your
|
7
|
+
# database schema. If you need to create the application database on another
|
8
|
+
# system, you should be using db:schema:load, not running all the migrations
|
9
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
10
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
11
|
+
#
|
12
|
+
# It's strongly recommended that you check this file into your version control system.
|
13
|
+
|
14
|
+
ActiveRecord::Schema.define(version: 20140214213610) do
|
15
|
+
|
16
|
+
create_table "users", force: true do |t|
|
17
|
+
t.string "name"
|
18
|
+
t.string "email"
|
19
|
+
t.datetime "created_at"
|
20
|
+
t.datetime "updated_at"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# This file should contain all the record creation needed to seed the database with its default values.
|
2
|
+
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
|
3
|
+
#
|
4
|
+
# Examples:
|
5
|
+
#
|
6
|
+
# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
|
7
|
+
# Mayor.create(:name => 'Daley', :city => cities.first)
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
if Undo::RUNNING_ON_CI
|
2
|
+
require 'coveralls'
|
3
|
+
Coveralls.wear!
|
4
|
+
else
|
5
|
+
require 'pry'
|
6
|
+
end
|
7
|
+
|
8
|
+
ENV['RAILS_ENV'] ||= 'test'
|
9
|
+
|
10
|
+
require File.expand_path('../rails_app/config/environment', __FILE__)
|
11
|
+
require 'rspec'
|
12
|
+
require_relative 'factories'
|
13
|
+
|
14
|
+
ActiveRecord::Migration.verbose = false
|
15
|
+
ActiveRecord::Migrator.migrate(Rails.root.join('db', 'migrate').to_s)
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.mock_with :rspec do |config|
|
19
|
+
config.syntax = [:expect, :should]
|
20
|
+
end
|
21
|
+
config.include FactoryGirl::Syntax::Methods
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper_lite"
|
2
|
+
|
3
|
+
describe Undo::Model do
|
4
|
+
subject { described_class }
|
5
|
+
let(:model) { subject.new object }
|
6
|
+
let(:object) { double :object }
|
7
|
+
|
8
|
+
describe "#uuid" do
|
9
|
+
it "using object#uuid" do
|
10
|
+
expect(object).to receive(:uuid) { "123" }
|
11
|
+
expect(model.uuid).to eq "123"
|
12
|
+
end
|
13
|
+
|
14
|
+
context "object do not respond to #uuid" do
|
15
|
+
it "using configured uuid gerenator" do
|
16
|
+
model = subject.new object, uuid_generator: proc { "123" }
|
17
|
+
expect(model.uuid).to eq "123"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "using SecureRandom uuid gerenator by default" do
|
21
|
+
expect(SecureRandom).to receive(:uuid) { "123" }
|
22
|
+
expect(model.uuid).to eq "123"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "passes object to custom uuid gerenator" do
|
26
|
+
uuid_generator = double :uuid_generator
|
27
|
+
expect(uuid_generator).to receive(:call).with(object)
|
28
|
+
|
29
|
+
model = subject.new object, uuid_generator: uuid_generator
|
30
|
+
model.uuid
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "spec_helper_lite"
|
2
|
+
require "undo/serializer/simple"
|
3
|
+
|
4
|
+
describe Undo::Serializer::Simple do
|
5
|
+
subject { described_class }
|
6
|
+
let(:serializer) { described_class.new }
|
7
|
+
|
8
|
+
it "serializes to json" do
|
9
|
+
object = { "hello" => "world" }
|
10
|
+
result = serializer.to_json object
|
11
|
+
expect(result).to eq '{"hello":"world"}'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "deserializes from json" do
|
15
|
+
serialized_object = '{"hello":"world"}'
|
16
|
+
result = serializer.load_from_json serialized_object
|
17
|
+
expect(result).to eq "hello" => "world"
|
18
|
+
end
|
19
|
+
end
|
data/spec/undo_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper_lite"
|
2
|
+
|
3
|
+
describe Undo do
|
4
|
+
subject { described_class }
|
5
|
+
|
6
|
+
describe "#wrap" do
|
7
|
+
let(:object) { double :object, change: true }
|
8
|
+
|
9
|
+
before do
|
10
|
+
subject.configure do |config|
|
11
|
+
config.mutator_methods = [:change]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "is a decorator" do
|
16
|
+
object = [:a, :b]
|
17
|
+
decorator = subject.wrap object
|
18
|
+
expect(object).to receive(:some_method)
|
19
|
+
|
20
|
+
decorator.some_method
|
21
|
+
expect(object.class).to eq Array
|
22
|
+
end
|
23
|
+
|
24
|
+
it "restores object" do
|
25
|
+
undoable_model = subject.wrap object
|
26
|
+
undoable_model.change
|
27
|
+
restored_object = subject.restore undoable_model.uuid
|
28
|
+
|
29
|
+
expect(restored_object).to eq object
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "with options" do
|
33
|
+
it "restores using provided options" do
|
34
|
+
storage = double
|
35
|
+
expect(storage).to receive(:put)
|
36
|
+
expect(storage).to receive(:fetch) { object }
|
37
|
+
|
38
|
+
undoable_model = subject.wrap object, storage: storage
|
39
|
+
undoable_model.change
|
40
|
+
restored_object = subject.restore undoable_model.uuid, storage: storage
|
41
|
+
|
42
|
+
expect(restored_object).to eq object
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/undo.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'undo/version'
|
5
|
+
require 'undo/environment'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "undo"
|
9
|
+
spec.version = Undo::VERSION
|
10
|
+
spec.authors = ["Alexander Paramonov"]
|
11
|
+
spec.email = ["alexander.n.paramonov@gmail.com"]
|
12
|
+
spec.summary = %q{Undo operations on object}
|
13
|
+
spec.description = %q{Undo allows to reverl last operation on object}
|
14
|
+
spec.homepage = "http://github.com/AlexParamonov/undo"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "virtus", "~> 1.0"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec", ">= 3.0.0.beta1"
|
26
|
+
|
27
|
+
if Undo::RUNNING_ON_CI
|
28
|
+
spec.add_development_dependency "coveralls"
|
29
|
+
else
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency "pry-plus" if "ruby" == RUBY_ENGINE
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: undo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Paramonov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: virtus
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
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
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.0.0.beta1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.0.0.beta1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
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: pry-plus
|
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
|
+
description: Undo allows to reverl last operation on object
|
98
|
+
email:
|
99
|
+
- alexander.n.paramonov@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".coveralls.yml"
|
105
|
+
- ".gitignore"
|
106
|
+
- ".rspec"
|
107
|
+
- ".ruby-gemset"
|
108
|
+
- ".ruby-version"
|
109
|
+
- ".travis.yml"
|
110
|
+
- Gemfile
|
111
|
+
- LICENSE.txt
|
112
|
+
- README.md
|
113
|
+
- Rakefile
|
114
|
+
- lib/undo.rb
|
115
|
+
- lib/undo/config.rb
|
116
|
+
- lib/undo/environment.rb
|
117
|
+
- lib/undo/model.rb
|
118
|
+
- lib/undo/serializer/simple.rb
|
119
|
+
- lib/undo/storage/memory_adapter.rb
|
120
|
+
- lib/undo/version.rb
|
121
|
+
- spec/acceptance/it_works_spec.rb
|
122
|
+
- spec/acceptance/undo_deletion_spec.rb
|
123
|
+
- spec/factories.rb
|
124
|
+
- spec/it_works_spec.rb
|
125
|
+
- spec/rails_app/.gitignore
|
126
|
+
- spec/rails_app/Rakefile
|
127
|
+
- spec/rails_app/app/models/.gitkeep
|
128
|
+
- spec/rails_app/app/models/user.rb
|
129
|
+
- spec/rails_app/config.ru
|
130
|
+
- spec/rails_app/config/application.rb
|
131
|
+
- spec/rails_app/config/boot.rb
|
132
|
+
- spec/rails_app/config/database.yml
|
133
|
+
- spec/rails_app/config/environment.rb
|
134
|
+
- spec/rails_app/config/environments/development.rb
|
135
|
+
- spec/rails_app/config/environments/production.rb
|
136
|
+
- spec/rails_app/config/environments/test.rb
|
137
|
+
- spec/rails_app/config/routes.rb
|
138
|
+
- spec/rails_app/db/migrate/20140214213610_create_users.rb
|
139
|
+
- spec/rails_app/db/schema.rb
|
140
|
+
- spec/rails_app/db/seeds.rb
|
141
|
+
- spec/rails_app/script/rails
|
142
|
+
- spec/spec_helper_lite.rb
|
143
|
+
- spec/spec_helper_rails.rb
|
144
|
+
- spec/undo/model_spec.rb
|
145
|
+
- spec/undo/serializer/simple_spec.rb
|
146
|
+
- spec/undo_spec.rb
|
147
|
+
- undo.gemspec
|
148
|
+
homepage: http://github.com/AlexParamonov/undo
|
149
|
+
licenses:
|
150
|
+
- MIT
|
151
|
+
metadata: {}
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
requirements: []
|
167
|
+
rubyforge_project:
|
168
|
+
rubygems_version: 2.2.2
|
169
|
+
signing_key:
|
170
|
+
specification_version: 4
|
171
|
+
summary: Undo operations on object
|
172
|
+
test_files:
|
173
|
+
- spec/acceptance/it_works_spec.rb
|
174
|
+
- spec/acceptance/undo_deletion_spec.rb
|
175
|
+
- spec/factories.rb
|
176
|
+
- spec/it_works_spec.rb
|
177
|
+
- spec/rails_app/.gitignore
|
178
|
+
- spec/rails_app/Rakefile
|
179
|
+
- spec/rails_app/app/models/.gitkeep
|
180
|
+
- spec/rails_app/app/models/user.rb
|
181
|
+
- spec/rails_app/config.ru
|
182
|
+
- spec/rails_app/config/application.rb
|
183
|
+
- spec/rails_app/config/boot.rb
|
184
|
+
- spec/rails_app/config/database.yml
|
185
|
+
- spec/rails_app/config/environment.rb
|
186
|
+
- spec/rails_app/config/environments/development.rb
|
187
|
+
- spec/rails_app/config/environments/production.rb
|
188
|
+
- spec/rails_app/config/environments/test.rb
|
189
|
+
- spec/rails_app/config/routes.rb
|
190
|
+
- spec/rails_app/db/migrate/20140214213610_create_users.rb
|
191
|
+
- spec/rails_app/db/schema.rb
|
192
|
+
- spec/rails_app/db/seeds.rb
|
193
|
+
- spec/rails_app/script/rails
|
194
|
+
- spec/spec_helper_lite.rb
|
195
|
+
- spec/spec_helper_rails.rb
|
196
|
+
- spec/undo/model_spec.rb
|
197
|
+
- spec/undo/serializer/simple_spec.rb
|
198
|
+
- spec/undo_spec.rb
|
199
|
+
has_rdoc:
|