statefully 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/statefully/diff.rb +61 -36
- data/lib/statefully/inspect.rb +14 -0
- data/lib/statefully/state.rb +9 -14
- data/lib/statefully.rb +1 -0
- data/spec/diff_spec.rb +34 -0
- data/spec/state_spec.rb +23 -9
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97acdf9e907dd51ad5227ef53828030d0943d35d
|
4
|
+
data.tar.gz: 3d9564c5fa59479e584e38c94ebdf504e1e1894d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94467d76d84d115d674c84db44022a6c4e76d81e417b1ca48eb613734802fd80c420f4a79832aa248f1622e9260c26d1bdfb8c72f9c73f078a14df230cde96b5
|
7
|
+
data.tar.gz: 732e6d9e831787099ae318d706a0c6d95280ea8ee06217e1bc0b3f9a30bd058d150b8053a972ffd631a626e3e75937cac403a5fc9e14609f0413f870e6da9894
|
data/lib/statefully/diff.rb
CHANGED
@@ -2,52 +2,55 @@ require 'set'
|
|
2
2
|
require 'singleton'
|
3
3
|
|
4
4
|
module Statefully
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module Diff
|
6
|
+
# This method reeks of :reek:FeatureEnvy (of current).
|
7
|
+
def create(current, previous)
|
8
|
+
return current.diff if current.failed? || current.finished?
|
9
9
|
changes = Builder.new(current, previous).build
|
10
|
-
changes.empty? ?
|
10
|
+
changes.empty? ? Unchanged.instance : Changed.new(**changes).freeze
|
11
11
|
end
|
12
|
+
module_function :create
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
14
|
+
class Changed
|
15
|
+
attr_reader :added, :changed
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
def empty?
|
18
|
+
false
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def inspect
|
22
|
+
"#<#{self.class.name} #{inspect_details}>"
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def added?(key)
|
26
|
+
added.key?(key)
|
27
|
+
end
|
28
28
|
|
29
|
-
|
29
|
+
def changed?(key)
|
30
|
+
changed.key?(key)
|
31
|
+
end
|
30
32
|
|
31
|
-
|
32
|
-
[inspect_added, inspect_changed].compact.join(', ')
|
33
|
-
end
|
33
|
+
private
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
def inspect_details
|
36
|
+
[inspect_added, inspect_changed].compact.join(', ')
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
def inspect_added
|
40
|
+
added.empty? ? nil : "added=#{Inspect.from_hash(added)}"
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
43
|
+
def inspect_changed
|
44
|
+
changed.empty? ? nil : "changed=#{Inspect.from_hash(changed)}"
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
47
|
+
def initialize(added:, changed:)
|
48
|
+
@added = added.freeze
|
49
|
+
@changed = changed.freeze
|
50
|
+
end
|
51
|
+
end # class Changed
|
50
52
|
|
53
|
+
module NoChanges
|
51
54
|
def empty?
|
52
55
|
true
|
53
56
|
end
|
@@ -59,11 +62,33 @@ module Statefully
|
|
59
62
|
def changed
|
60
63
|
{}
|
61
64
|
end
|
65
|
+
end # module NoChanges
|
66
|
+
private_constant :NoChanges
|
67
|
+
|
68
|
+
class Unchanged
|
69
|
+
include Singleton
|
70
|
+
include NoChanges
|
62
71
|
|
63
72
|
def inspect
|
64
|
-
"
|
73
|
+
"#<#{self.class.name}>"
|
65
74
|
end
|
66
|
-
end # class
|
75
|
+
end # class Unchanged
|
76
|
+
|
77
|
+
class Failed
|
78
|
+
include NoChanges
|
79
|
+
attr_reader :error
|
80
|
+
|
81
|
+
def initialize(error)
|
82
|
+
@error = error
|
83
|
+
end
|
84
|
+
|
85
|
+
def inspect
|
86
|
+
"#<#{self.class.name} error=#{error.inspect}>"
|
87
|
+
end
|
88
|
+
end # class Failed
|
89
|
+
|
90
|
+
class Finished < Unchanged
|
91
|
+
end # class Finished
|
67
92
|
|
68
93
|
class Change
|
69
94
|
attr_reader :current, :previous
|
@@ -127,5 +152,5 @@ module Statefully
|
|
127
152
|
end
|
128
153
|
end # class Builder
|
129
154
|
private_constant :Builder
|
130
|
-
end #
|
155
|
+
end # module Diff
|
131
156
|
end # module Statefully
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Statefully
|
2
|
+
module Inspect
|
3
|
+
def from_hash(input)
|
4
|
+
'{' + input.map { |key, val| "#{key}: #{val.inspect}" }.join(', ') + '}'
|
5
|
+
end
|
6
|
+
module_function :from_hash
|
7
|
+
|
8
|
+
def from_fields(input)
|
9
|
+
input.map { |key, val| "#{key}=#{val.inspect}" }.join(', ')
|
10
|
+
end
|
11
|
+
module_function :from_fields
|
12
|
+
end # module Inspect
|
13
|
+
private_constant :Inspect
|
14
|
+
end # module Statefully
|
data/lib/statefully/state.rb
CHANGED
@@ -21,12 +21,12 @@ module Statefully
|
|
21
21
|
([diff] + previous.history).freeze
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def successful?
|
25
25
|
true
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
!
|
28
|
+
def failed?
|
29
|
+
!successful?
|
30
30
|
end
|
31
31
|
|
32
32
|
def finished?
|
@@ -129,10 +129,10 @@ module Statefully
|
|
129
129
|
end
|
130
130
|
|
131
131
|
def diff
|
132
|
-
error
|
132
|
+
Diff::Failed.new(error).freeze
|
133
133
|
end
|
134
134
|
|
135
|
-
def
|
135
|
+
def successful?
|
136
136
|
false
|
137
137
|
end
|
138
138
|
|
@@ -146,9 +146,12 @@ module Statefully
|
|
146
146
|
end # class Failure
|
147
147
|
private_constant :Failure
|
148
148
|
|
149
|
+
# Finished state is a state which is successful, but should not be processed
|
150
|
+
# any further. This could be useful for things like early returns.
|
149
151
|
class Finished < State
|
152
|
+
# This method reeks of :reek:UtilityFunction - just implementing an API.
|
150
153
|
def diff
|
151
|
-
|
154
|
+
Diff::Finished.instance
|
152
155
|
end
|
153
156
|
|
154
157
|
def finished?
|
@@ -156,13 +159,5 @@ module Statefully
|
|
156
159
|
end
|
157
160
|
end # class Finished
|
158
161
|
private_constant :Finished
|
159
|
-
|
160
|
-
module Inspect
|
161
|
-
def from_fields(input)
|
162
|
-
input.map { |key, val| "#{key}=#{val.inspect}" }.join(', ')
|
163
|
-
end
|
164
|
-
module_function :from_fields
|
165
|
-
end # module Inspect
|
166
|
-
private_constant :Inspect
|
167
162
|
end # class State
|
168
163
|
end # module Statefully
|
data/lib/statefully.rb
CHANGED
data/spec/diff_spec.rb
CHANGED
@@ -13,6 +13,9 @@ module Statefully
|
|
13
13
|
it { expect(subject.added?(:key)).to be_truthy }
|
14
14
|
it { expect(subject.added.fetch(:key)).to eq 'val' }
|
15
15
|
it { expect(subject.changed).to be_empty }
|
16
|
+
|
17
|
+
it { expect(subject.inspect).to start_with '#<Statefully::Diff::Changed' }
|
18
|
+
it { expect(subject.inspect).to include 'added={key: "val"}>' }
|
16
19
|
end # context 'when key added'
|
17
20
|
|
18
21
|
context 'when key changed' do
|
@@ -24,6 +27,8 @@ module Statefully
|
|
24
27
|
it { expect(subject.changed).to have_key(:key) }
|
25
28
|
it { expect(subject.changed?(:key)).to be_truthy }
|
26
29
|
|
30
|
+
it { expect(subject.inspect).to include 'changed=' }
|
31
|
+
|
27
32
|
context 'with change' do
|
28
33
|
let(:change) { subject.changed.fetch(:key) }
|
29
34
|
|
@@ -37,6 +42,35 @@ module Statefully
|
|
37
42
|
let(:previous) { current }
|
38
43
|
|
39
44
|
it { expect(subject).to be_empty }
|
45
|
+
it { expect(subject.inspect).to eq '#<Statefully::Diff::Unchanged>' }
|
40
46
|
end # context 'when nothing changed'
|
47
|
+
|
48
|
+
shared_examples 'diff_is_empty' do
|
49
|
+
it { expect(subject).to be_empty }
|
50
|
+
it { expect(subject.added).to be_empty }
|
51
|
+
it { expect(subject.changed).to be_empty }
|
52
|
+
end # shared_examples 'diff_is_empty'
|
53
|
+
|
54
|
+
context 'when failed' do
|
55
|
+
let(:error) { RuntimeError.new('boo!') }
|
56
|
+
let(:previous) { State.create }
|
57
|
+
let(:current) { previous.fail(error) }
|
58
|
+
|
59
|
+
it_behaves_like 'diff_is_empty'
|
60
|
+
|
61
|
+
it { expect(subject.error).to eq error }
|
62
|
+
|
63
|
+
it { expect(subject.inspect).to start_with '#<Statefully::Diff::Failed' }
|
64
|
+
it { expect(subject.inspect).to include 'error=#<RuntimeError: boo!>' }
|
65
|
+
end # context 'when failed'
|
66
|
+
|
67
|
+
context 'when finished' do
|
68
|
+
let(:previous) { State.create }
|
69
|
+
let(:current) { previous.finish }
|
70
|
+
|
71
|
+
it_behaves_like 'diff_is_empty'
|
72
|
+
|
73
|
+
it { expect(subject.inspect).to eq '#<Statefully::Diff::Finished>' }
|
74
|
+
end # context 'when finished'
|
41
75
|
end # describe Diff
|
42
76
|
end # module Statefully
|
data/spec/state_spec.rb
CHANGED
@@ -4,7 +4,7 @@ module Statefully
|
|
4
4
|
describe State do
|
5
5
|
describe '.create' do
|
6
6
|
subject { described_class.create(key: 'val') }
|
7
|
-
it { expect(subject).to
|
7
|
+
it { expect(subject).to be_successful }
|
8
8
|
end # describe '.create'
|
9
9
|
end # describe State
|
10
10
|
|
@@ -31,13 +31,19 @@ module Statefully
|
|
31
31
|
|
32
32
|
describe 'trivial readers' do
|
33
33
|
it { expect(subject.resolve).to eq subject }
|
34
|
-
it { expect(subject).to
|
35
|
-
it { expect(subject).not_to
|
34
|
+
it { expect(subject).to be_successful }
|
35
|
+
it { expect(subject).not_to be_failed }
|
36
36
|
it { expect(subject).not_to be_finished }
|
37
37
|
end # describe 'trivial readers'
|
38
38
|
|
39
|
+
describe '#inspect' do
|
40
|
+
let(:expected) { '#<Statefully::State::Success old_key="val">' }
|
41
|
+
|
42
|
+
it { expect(subject.inspect).to eq expected }
|
43
|
+
end # describe '#inspect'
|
44
|
+
|
39
45
|
shared_examples 'successful_state' do
|
40
|
-
it { expect(next_state).to
|
46
|
+
it { expect(next_state).to be_successful }
|
41
47
|
it { expect(next_state.old_key).to eq val }
|
42
48
|
|
43
49
|
it { expect(next_state.previous).to eq subject }
|
@@ -64,11 +70,11 @@ module Statefully
|
|
64
70
|
end # describe '#succeed'
|
65
71
|
|
66
72
|
describe '#fail' do
|
67
|
-
let(:error) { RuntimeError.new('
|
73
|
+
let(:error) { RuntimeError.new('boo!') }
|
68
74
|
let(:next_state) { subject.fail(error) }
|
69
75
|
|
70
|
-
it { expect(next_state).not_to
|
71
|
-
it { expect(next_state).to
|
76
|
+
it { expect(next_state).not_to be_successful }
|
77
|
+
it { expect(next_state).to be_failed }
|
72
78
|
it { expect(next_state).not_to be_finished }
|
73
79
|
it { expect(subject).not_to be_finished }
|
74
80
|
it { expect(next_state.old_key).to eq val }
|
@@ -81,11 +87,19 @@ module Statefully
|
|
81
87
|
end
|
82
88
|
end
|
83
89
|
|
90
|
+
describe '#inspect' do
|
91
|
+
let(:inspect) { next_state.inspect }
|
92
|
+
|
93
|
+
it { expect(inspect).to start_with '#<Statefully::State::Failure' }
|
94
|
+
it { expect(inspect).to include 'old_key="val"' }
|
95
|
+
it { expect(inspect).to include 'error="#<RuntimeError: boo!>"' }
|
96
|
+
end # describe '#inspect'
|
97
|
+
|
84
98
|
context 'with history' do
|
85
99
|
let(:history) { next_state.history }
|
86
100
|
|
87
101
|
it { expect(history.size).to eq 2 }
|
88
|
-
it { expect(history.first).to eq error }
|
102
|
+
it { expect(history.first.error).to eq error }
|
89
103
|
it { expect(history.last.added).to include :old_key }
|
90
104
|
end # context 'with history'
|
91
105
|
end # describe '#fail'
|
@@ -102,7 +116,7 @@ module Statefully
|
|
102
116
|
let(:history) { next_state.history }
|
103
117
|
|
104
118
|
it { expect(history.size).to eq 2 }
|
105
|
-
it { expect(history.first).to eq
|
119
|
+
it { expect(history.first).to eq Diff::Finished.instance }
|
106
120
|
it { expect(history.last.added).to include :old_key }
|
107
121
|
end # context 'with history'
|
108
122
|
end # describe '#finish'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statefully
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcin Wyszynski
|
@@ -52,6 +52,7 @@ extra_rdoc_files: []
|
|
52
52
|
files:
|
53
53
|
- lib/statefully.rb
|
54
54
|
- lib/statefully/diff.rb
|
55
|
+
- lib/statefully/inspect.rb
|
55
56
|
- lib/statefully/state.rb
|
56
57
|
- spec/diff_spec.rb
|
57
58
|
- spec/spec_helper.rb
|