undo 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4a5040011eba1d15fba3685916c6b860e1c27bcb
4
- data.tar.gz: 13ac49e306629143828ceb2c8b9485fc331b6f13
3
+ metadata.gz: 20c52711aa6a7b2718cf79b9ecc238f1a77b53e2
4
+ data.tar.gz: fd06dc16acb71cd5fde5d9bfe4b69c8f00272a1c
5
5
  SHA512:
6
- metadata.gz: 0c7b26509df4c556ff01122e53af31069be2b3ebb5b64bcd3cab7a2cc7f471130a4c11fb1fe850ca317cc1daddfecbdf4d6ed52642ef7b8dd6de34499c72c03f
7
- data.tar.gz: 30eef3cf3133a1515ef46e1ada8baf4e517c92d3155ef8970514075e088bf6817ecf89761edd8ceed6ae9f46051b465ab0244d1d3eca66a5713a8f0eae89bb46
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
- Wrap object in Undo decorator:
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 restore previous version
93
+ To define custom uuid generator use `uuid_generator` option:
73
94
 
74
- ```
75
- Undo.restore uuid
95
+ ``` ruby
96
+ Undo.configure do |config|
97
+ config.uuid_generator = ->(object) { "#{object.class.name}_#{object.id}" }
98
+ end
76
99
  ```
77
100
 
78
- `uuid` is provided by wrapped object:
101
+ ### UUID
79
102
 
80
- ```
81
- Undo.wrap(object).uuid
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
- By default it is using `SecureRandom.uuid`.
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
- Undo.configure do |config|
89
- config.uuid_generator = ->(object) { "#{object.class.name}_#{object.id}" }
90
- end
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:
@@ -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.config
12
- @config ||= Undo::Config.new
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.wrap(object, *args)
16
- Model.new object, *args
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.restore(uuid, options = {})
24
+ def self.wrap(object, options = {})
20
25
  config.with(options) do |config|
21
- config.serializer.deserialize config.storage.fetch uuid
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
@@ -1,3 +1,3 @@
1
1
  module Undo
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -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
@@ -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
- describe "restores object by uuid" do
27
- it "restores object" do
28
- model = subject.wrap object
29
- model.change
30
- restored_object = subject.restore model.uuid
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
- expect(restored_object).to eq object
33
- end
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
- model = subject.wrap object
40
- model.change
41
- restored_object = subject.restore model.uuid, serializer: serializer
71
+ specify "using gerenated uuid" do
72
+ model = subject.wrap object
73
+ model.change
42
74
 
43
- expect(restored_object).to eq object
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.3
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-02-16 00:00:00.000000000 Z
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.2.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:
@@ -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
@@ -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