undo 0.0.3 → 0.1.0
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 +4 -4
- data/README.md +50 -16
- data/lib/undo.rb +28 -8
- data/lib/undo/version.rb +1 -1
- data/lib/undo/wrapper.rb +29 -0
- data/spec/undo/wrapper_spec.rb +31 -0
- data/spec/undo_spec.rb +49 -16
- metadata +6 -6
- data/lib/undo/model.rb +0 -38
- data/spec/undo/model_spec.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20c52711aa6a7b2718cf79b9ecc238f1a77b53e2
|
4
|
+
data.tar.gz: fd06dc16acb71cd5fde5d9bfe4b69c8f00272a1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a94e5461a9937c5141ca1bdd5cdbf3fb9d653de480ecf1a9c508580f0f1774060cb6902dc55bb4e74d4729ed3b5bc0e1b4b8873cca76cbe24ba617daee8cdf9
|
7
|
+
data.tar.gz: 11a5d31f76ddced0163edfb1d382ed03a5d7c84dfd7378a0c805f562b34eb0ed5d05659449b56f59cfdb6e119d1115bc4a69d6f233e4f57eaa766ba8a3f5f172
|
data/README.md
CHANGED
@@ -53,14 +53,35 @@ Usage
|
|
53
53
|
|
54
54
|
### Undo operation
|
55
55
|
|
56
|
-
|
56
|
+
``` ruby
|
57
|
+
uuid = Undo.store object
|
58
|
+
Undo.restore uuid
|
59
|
+
```
|
60
|
+
That is basically it :)
|
61
|
+
|
62
|
+
Additionally possible to wrap object in Undo decorator:
|
57
63
|
|
58
64
|
``` ruby
|
59
|
-
Undo.wrap object
|
65
|
+
decorated_object = Undo.wrap object
|
66
|
+
Undo.restore decorated_object.uuid
|
60
67
|
```
|
68
|
+
Use decorated_object as usual afterwards. Undo gem will store object
|
69
|
+
state on each hit to `mutator methods`. By default mutator_methods are
|
70
|
+
`update`, `delete`, `destroy`. Those methods can be changed either in
|
71
|
+
place or using global configuration (see below).
|
72
|
+
|
73
|
+
To use something more advanced rather plain memory storage and
|
74
|
+
path though serializer, configure the Undo:
|
75
|
+
|
76
|
+
``` ruby
|
77
|
+
Undo.configure do |config|
|
78
|
+
config.storage = Undo::Storage::RailsCache
|
79
|
+
config.serializer = Undo::Serializer::ActiveModel
|
80
|
+
end
|
81
|
+
```
|
82
|
+
gem `undo-storage-rails_cache` and gem `undo-serializer-active_model` are required for this.
|
83
|
+
There are a bunch of other Rails free adapters. Read about them in configuration chapter below.
|
61
84
|
|
62
|
-
And use it as usual afterwards. Undo gem will store object state on each hit to `mutator methods`.
|
63
|
-
By default mutator_methods are `update`, `delete`, `destroy`.
|
64
85
|
To append custom mutator_methods use
|
65
86
|
|
66
87
|
``` ruby
|
@@ -69,36 +90,47 @@ Undo.configure do |config|
|
|
69
90
|
end
|
70
91
|
```
|
71
92
|
|
72
|
-
To
|
93
|
+
To define custom uuid generator use `uuid_generator` option:
|
73
94
|
|
74
|
-
```
|
75
|
-
Undo.
|
95
|
+
``` ruby
|
96
|
+
Undo.configure do |config|
|
97
|
+
config.uuid_generator = ->(object) { "#{object.class.name}_#{object.id}" }
|
98
|
+
end
|
76
99
|
```
|
77
100
|
|
78
|
-
|
101
|
+
### UUID
|
79
102
|
|
80
|
-
|
81
|
-
|
103
|
+
By default uuids are generated by `SecureRandom.uuid`.
|
104
|
+
|
105
|
+
UUID can be provided to both #wrap and #store methods and it will be used instead of generated one:
|
106
|
+
|
107
|
+
``` ruby
|
108
|
+
uuid = "uniq identifier"
|
109
|
+
|
110
|
+
Undo.store object, uuid: uuid
|
111
|
+
Undo.restore uuid
|
82
112
|
```
|
83
113
|
|
84
|
-
|
85
|
-
To define custom uuid generator use `uuid_generator` option:
|
114
|
+
If object respond to #uuid method then it value will be used instead:
|
86
115
|
|
87
116
|
``` ruby
|
88
|
-
|
89
|
-
|
90
|
-
|
117
|
+
object = OpenStruct.new uuid: "uniq identifier"
|
118
|
+
Undo.store object # => uniq identifier
|
119
|
+
Undo.restore "uniq identifier"
|
91
120
|
```
|
92
121
|
|
93
122
|
### Configuration options
|
123
|
+
|
94
124
|
`storage` option responsible for putting and fetching object state to or from some storage.
|
95
125
|
Implement `put(uuid, object)` and `fetch(uuid)` methods.
|
96
126
|
Currently available storages:
|
97
127
|
* `Undo::Storage::Memory` simple runtime storage (Hash)
|
128
|
+
* `gem "undo-storage-rails_cache"` designed for Rails, but can be used with any ducktype cache store
|
98
129
|
* `gem "undo-storage-redis"` designed to be used with `gem "redis"` from v0.1 to current
|
99
130
|
|
100
131
|
See also [documentation](http://github.com/AlexParamonov/undo)
|
101
|
-
on project repository for full list of currently available storage adapters.
|
132
|
+
on project repository for full list of currently available storage adapters.
|
133
|
+
|
102
134
|
To convert objects to data that can be processed by storage adapters and backward, use `serializers`:
|
103
135
|
|
104
136
|
``` ruby
|
@@ -109,6 +141,7 @@ end
|
|
109
141
|
|
110
142
|
Currently available serializers:
|
111
143
|
* `Undo::Serializer::Null` pass though serializer. It do nothing and returns whatever passed to it.
|
144
|
+
* `gem undo-serializer-active_model`
|
112
145
|
|
113
146
|
Check [documentation](http://github.com/AlexParamonov/undo) on project
|
114
147
|
repository for currently available serializers.
|
@@ -135,6 +168,7 @@ end
|
|
135
168
|
```
|
136
169
|
|
137
170
|
### In place configuration
|
171
|
+
|
138
172
|
Any configuration option from previous chapter can be applied in
|
139
173
|
place for given operation. To restore object from another storage use
|
140
174
|
`storage` option:
|
data/lib/undo.rb
CHANGED
@@ -1,24 +1,44 @@
|
|
1
1
|
require "undo/version"
|
2
2
|
require "undo/config"
|
3
|
+
require "undo/wrapper"
|
3
4
|
|
4
5
|
module Undo
|
5
|
-
require "undo/model"
|
6
|
-
|
7
6
|
def self.configure(&block)
|
8
7
|
block_given? ? block.call(config) : config
|
9
8
|
end
|
10
9
|
|
11
|
-
def self.
|
12
|
-
|
10
|
+
def self.store(object, options = {})
|
11
|
+
config.with(options) do |config|
|
12
|
+
uuid(object, options).tap do |uuid|
|
13
|
+
config.storage.put uuid, config.serializer.serialize(object)
|
14
|
+
end
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
|
-
def self.
|
16
|
-
|
18
|
+
def self.restore(uuid, options = {})
|
19
|
+
config.with(options) do |config|
|
20
|
+
config.serializer.deserialize config.storage.fetch(uuid)
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
|
-
def self.
|
24
|
+
def self.wrap(object, options = {})
|
20
25
|
config.with(options) do |config|
|
21
|
-
|
26
|
+
Wrapper.new(
|
27
|
+
object,
|
28
|
+
uuid(object, options),
|
29
|
+
mutator_methods: config.mutator_methods
|
30
|
+
)
|
22
31
|
end
|
23
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def self.uuid(object, options = {})
|
36
|
+
options[:uuid] || config.uuid_generator.call(object)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.config
|
40
|
+
@config ||= Undo::Config.new
|
41
|
+
end
|
42
|
+
|
43
|
+
private_class_method :uuid, :config
|
24
44
|
end
|
data/lib/undo/version.rb
CHANGED
data/lib/undo/wrapper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Undo
|
4
|
+
class Wrapper < SimpleDelegator
|
5
|
+
extend Forwardable
|
6
|
+
def_delegators :object, :class, :kind_of?
|
7
|
+
attr_reader :uuid
|
8
|
+
|
9
|
+
def initialize(object, uuid, options = {})
|
10
|
+
@object = object
|
11
|
+
@mutator_methods = options.fetch :mutator_methods, []
|
12
|
+
@uuid = object.respond_to?(:uuid) ? object.uuid : uuid
|
13
|
+
|
14
|
+
super object
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
store if mutator_methods.include? method
|
19
|
+
super method, *args, &block
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
attr_reader :object, :mutator_methods
|
24
|
+
|
25
|
+
def store
|
26
|
+
Undo.store object, uuid: uuid
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper_lite"
|
2
|
+
|
3
|
+
describe Undo::Wrapper do
|
4
|
+
subject { described_class }
|
5
|
+
let(:model) { subject.new object, uuid }
|
6
|
+
let(:object) { double :object, change: true }
|
7
|
+
let(:uuid) { double :uuid }
|
8
|
+
|
9
|
+
describe "storage" do
|
10
|
+
let(:model) { subject.new object, uuid, mutator_methods: mutator_methods }
|
11
|
+
let(:mutator_methods) { [:change] }
|
12
|
+
|
13
|
+
it "stores object when mutator method is called" do
|
14
|
+
expect(model).to receive(:store)
|
15
|
+
model.change
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#uuid" do
|
20
|
+
it "uses provided uuid" do
|
21
|
+
expect(model.uuid).to eq uuid
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "when object respond_to uuid" do
|
25
|
+
it "uses object#uuid instead" do
|
26
|
+
expect(object).to receive(:uuid) { "123" }
|
27
|
+
expect(model.uuid).to eq "123"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/undo_spec.rb
CHANGED
@@ -4,6 +4,43 @@ describe Undo do
|
|
4
4
|
let(:object) { double :object, change: true }
|
5
5
|
subject { described_class }
|
6
6
|
|
7
|
+
it "stores and restores object" do
|
8
|
+
uuid = subject.store object
|
9
|
+
expect(subject.restore uuid).to eq object
|
10
|
+
end
|
11
|
+
|
12
|
+
it "stores and restores object using provided uuid" do
|
13
|
+
uuid = "uniq_identifier"
|
14
|
+
subject.store object, uuid: uuid
|
15
|
+
|
16
|
+
expect(subject.restore uuid).to eq object
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "serializing" do
|
20
|
+
let(:storage) { double :storage }
|
21
|
+
let(:serializer) { double :serializer }
|
22
|
+
|
23
|
+
it "serializes data before storing" do
|
24
|
+
expect(serializer).to receive(:serialize).with(object).ordered
|
25
|
+
expect(storage).to receive(:put).ordered
|
26
|
+
|
27
|
+
subject.store object,
|
28
|
+
storage: storage,
|
29
|
+
serializer: serializer
|
30
|
+
end
|
31
|
+
|
32
|
+
it "deserializes data before restoring" do
|
33
|
+
uuid = subject.store object
|
34
|
+
|
35
|
+
expect(storage).to receive(:fetch).and_return(foo: :bar).ordered
|
36
|
+
expect(serializer).to receive(:deserialize).with(foo: :bar).ordered
|
37
|
+
|
38
|
+
subject.restore uuid,
|
39
|
+
storage: storage,
|
40
|
+
serializer: serializer
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
7
44
|
describe "#wrap" do
|
8
45
|
before do
|
9
46
|
subject.configure do |config|
|
@@ -21,26 +58,22 @@ describe Undo do
|
|
21
58
|
expect(decorator.class).to eq Array
|
22
59
|
expect(decorator).to be_a Array
|
23
60
|
end
|
24
|
-
end
|
25
61
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
62
|
+
describe "restores" do
|
63
|
+
specify "using provided uuid" do
|
64
|
+
uuid = "uniq_identifier"
|
65
|
+
model = subject.wrap object, uuid: uuid
|
66
|
+
model.change
|
31
67
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
it "restores using provided options" do
|
36
|
-
serializer = double :serializer
|
37
|
-
expect(serializer).to receive(:deserialize) { object }
|
68
|
+
expect(subject.restore uuid).to eq object
|
69
|
+
end
|
38
70
|
|
39
|
-
|
40
|
-
|
41
|
-
|
71
|
+
specify "using gerenated uuid" do
|
72
|
+
model = subject.wrap object
|
73
|
+
model.change
|
42
74
|
|
43
|
-
|
75
|
+
expect(subject.restore model.uuid).to eq object
|
76
|
+
end
|
44
77
|
end
|
45
78
|
end
|
46
79
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: undo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Paramonov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: virtus
|
@@ -92,14 +92,14 @@ files:
|
|
92
92
|
- Rakefile
|
93
93
|
- lib/undo.rb
|
94
94
|
- lib/undo/config.rb
|
95
|
-
- lib/undo/model.rb
|
96
95
|
- lib/undo/serializer/null.rb
|
97
96
|
- lib/undo/storage/memory.rb
|
98
97
|
- lib/undo/version.rb
|
98
|
+
- lib/undo/wrapper.rb
|
99
99
|
- spec/spec_helper_lite.rb
|
100
|
-
- spec/undo/model_spec.rb
|
101
100
|
- spec/undo/serializer/null_spec.rb
|
102
101
|
- spec/undo/storage/memory_spec.rb
|
102
|
+
- spec/undo/wrapper_spec.rb
|
103
103
|
- spec/undo_spec.rb
|
104
104
|
- undo.gemspec
|
105
105
|
homepage: http://github.com/AlexParamonov/undo
|
@@ -122,14 +122,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
122
|
version: '0'
|
123
123
|
requirements: []
|
124
124
|
rubyforge_project:
|
125
|
-
rubygems_version: 2.
|
125
|
+
rubygems_version: 2.1.11
|
126
126
|
signing_key:
|
127
127
|
specification_version: 4
|
128
128
|
summary: Reverts operation made upon object
|
129
129
|
test_files:
|
130
130
|
- spec/spec_helper_lite.rb
|
131
|
-
- spec/undo/model_spec.rb
|
132
131
|
- spec/undo/serializer/null_spec.rb
|
133
132
|
- spec/undo/storage/memory_spec.rb
|
133
|
+
- spec/undo/wrapper_spec.rb
|
134
134
|
- spec/undo_spec.rb
|
135
135
|
has_rdoc:
|
data/lib/undo/model.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require "forwardable"
|
2
|
-
|
3
|
-
module Undo
|
4
|
-
class Model < SimpleDelegator
|
5
|
-
extend Forwardable
|
6
|
-
def_delegators :object, :class, :kind_of?
|
7
|
-
|
8
|
-
def initialize(object, options = {})
|
9
|
-
@object = object
|
10
|
-
@config = config.with options
|
11
|
-
super object
|
12
|
-
end
|
13
|
-
|
14
|
-
def uuid
|
15
|
-
@uuid ||= object.respond_to?(:uuid) ? object.uuid : generate_uuid
|
16
|
-
end
|
17
|
-
|
18
|
-
def method_missing(method, *args, &block)
|
19
|
-
store if config.mutator_methods.include? method
|
20
|
-
super method, *args, &block
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
attr_reader :object
|
25
|
-
|
26
|
-
def generate_uuid
|
27
|
-
config.uuid_generator.call object
|
28
|
-
end
|
29
|
-
|
30
|
-
def store
|
31
|
-
config.storage.put uuid, config.serializer.serialize(object)
|
32
|
-
end
|
33
|
-
|
34
|
-
def config
|
35
|
-
@config ||= Undo.config
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/spec/undo/model_spec.rb
DELETED
@@ -1,61 +0,0 @@
|
|
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
|
-
describe "stores object data" do
|
36
|
-
let(:object) { double :object, change: true }
|
37
|
-
let(:storage) { double :storage }
|
38
|
-
let(:serializer) { double :serializer }
|
39
|
-
|
40
|
-
specify "when called mutator method" do
|
41
|
-
expect(storage).to receive(:put)
|
42
|
-
|
43
|
-
model = subject.new object,
|
44
|
-
storage: storage,
|
45
|
-
mutator_methods: [:change]
|
46
|
-
model.change
|
47
|
-
end
|
48
|
-
|
49
|
-
it "serializes data before storing" do
|
50
|
-
expect(serializer).to receive(:serialize).with(object).ordered
|
51
|
-
expect(storage).to receive(:put).ordered
|
52
|
-
|
53
|
-
model = subject.new object,
|
54
|
-
storage: storage,
|
55
|
-
serializer: serializer,
|
56
|
-
mutator_methods: [:change]
|
57
|
-
model.change
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|