service_objects 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.metrics +5 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +2 -0
  6. data/.travis.yml +4 -0
  7. data/.yardopts +3 -0
  8. data/Gemfile +3 -0
  9. data/Guardfile +16 -0
  10. data/LICENSE +21 -0
  11. data/README.md +461 -0
  12. data/Rakefile +17 -0
  13. data/config/metrics/STYLEGUIDE +230 -0
  14. data/config/metrics/cane.yml +5 -0
  15. data/config/metrics/churn.yml +6 -0
  16. data/config/metrics/flay.yml +2 -0
  17. data/config/metrics/metric_fu.yml +14 -0
  18. data/config/metrics/pippi.yml +3 -0
  19. data/config/metrics/reek.yml +1 -0
  20. data/config/metrics/roodi.yml +24 -0
  21. data/config/metrics/rubocop.yml +75 -0
  22. data/config/metrics/saikuro.yml +3 -0
  23. data/config/metrics/simplecov.yml +6 -0
  24. data/config/metrics/yardstick.yml +37 -0
  25. data/lib/service_objects/base.rb +43 -0
  26. data/lib/service_objects/helpers/dependable.rb +63 -0
  27. data/lib/service_objects/helpers/exceptions.rb +64 -0
  28. data/lib/service_objects/helpers/messages.rb +96 -0
  29. data/lib/service_objects/helpers/parameterized.rb +85 -0
  30. data/lib/service_objects/helpers/parameters.rb +71 -0
  31. data/lib/service_objects/helpers/validations.rb +54 -0
  32. data/lib/service_objects/invalid.rb +55 -0
  33. data/lib/service_objects/listener.rb +97 -0
  34. data/lib/service_objects/message.rb +117 -0
  35. data/lib/service_objects/null.rb +26 -0
  36. data/lib/service_objects/utils/normal_hash.rb +34 -0
  37. data/lib/service_objects/version.rb +9 -0
  38. data/lib/service_objects.rb +12 -0
  39. data/service_objects.gemspec +28 -0
  40. data/spec/spec_helper.rb +15 -0
  41. data/spec/tests/base_spec.rb +43 -0
  42. data/spec/tests/helpers/dependable_spec.rb +77 -0
  43. data/spec/tests/helpers/exceptions_spec.rb +112 -0
  44. data/spec/tests/helpers/messages_spec.rb +64 -0
  45. data/spec/tests/helpers/parameterized_spec.rb +136 -0
  46. data/spec/tests/helpers/parameters_spec.rb +71 -0
  47. data/spec/tests/helpers/validations_spec.rb +60 -0
  48. data/spec/tests/invalid_spec.rb +69 -0
  49. data/spec/tests/listener_spec.rb +50 -0
  50. data/spec/tests/message_spec.rb +191 -0
  51. data/spec/tests/null_spec.rb +17 -0
  52. data/spec/tests/utils/normal_hash_spec.rb +16 -0
  53. metadata +182 -0
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::Helpers::Validations do
4
+
5
+ let(:invalid) { ServiceObjects::Invalid }
6
+ let(:message_class) { ServiceObjects::Message }
7
+ let(:messages_module) { ServiceObjects::Helpers::Messages }
8
+ let(:test_class) { Class.new }
9
+ let(:validations) { ActiveModel::Validations }
10
+
11
+ before { ServiceObjects::Test = test_class }
12
+ before { test_class.include described_class }
13
+ after { ServiceObjects.send :remove_const, :Test }
14
+
15
+ it "includes ActiveModel::Validations" do
16
+ expect(test_class).to include validations
17
+ end
18
+
19
+ it "includes ServiceObjects::Helpers::Messages" do
20
+ expect(test_class).to include messages_module
21
+ end
22
+
23
+ describe "#validate!" do
24
+
25
+ subject { test_class.new }
26
+
27
+ context "when the service is valid" do
28
+
29
+ it "passes" do
30
+ expect { subject.validate! }.not_to raise_error
31
+ end
32
+
33
+ end
34
+
35
+ context "when the service is invalid" do
36
+
37
+ before { subject.errors.add :base, :invalid }
38
+ before { allow(subject).to receive(:valid?) { false } }
39
+
40
+ it "fails" do
41
+ expect { subject.validate! }.to raise_error invalid
42
+ end
43
+
44
+ it "populates #messages from errors" do
45
+ begin
46
+ subject.validate!
47
+ rescue => err
48
+ message = subject.messages.first
49
+ end
50
+
51
+ expect(message).to be_kind_of message_class
52
+ expect(message.type).to eq "error"
53
+ expect(err.messages).to contain_exactly message
54
+ end
55
+
56
+ end
57
+
58
+ end # #validate!
59
+
60
+ end # ServiceObjects::Helpers::Validations
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::Invalid do
4
+
5
+ let(:messages) { double :messages }
6
+ let(:object) { double :object, messages: messages }
7
+
8
+ subject { described_class.new object }
9
+
10
+ describe ".new" do
11
+
12
+ context "without arguments" do
13
+
14
+ subject { described_class.new }
15
+
16
+ it "fails with ArgumentError" do
17
+ expect { subject }.to raise_error ArgumentError
18
+ end
19
+ end
20
+
21
+ context "with an object that doesn't responds to :messages" do
22
+
23
+ let(:object) { double }
24
+ subject { described_class.new object }
25
+
26
+ it "fails with TypeError" do
27
+ expect { subject }.to raise_error TypeError
28
+ end
29
+
30
+ it "returns a proper message" do
31
+ begin
32
+ subject
33
+ rescue => err
34
+ expect(err.message)
35
+ .to eq "#{ object.inspect } doesn't respond to #messages"
36
+ end
37
+ end
38
+ end
39
+
40
+ context "with an object that responds to :messages" do
41
+
42
+ it "doesn't fail" do
43
+ expect { subject }.not_to raise_error
44
+ end
45
+
46
+ it "initializes a RuntimeError" do
47
+ expect(subject).to be_kind_of RuntimeError
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "#object" do
53
+
54
+ it "is initialized" do
55
+ expect(subject.object).to eq object
56
+ end
57
+ end
58
+
59
+ describe "#messages" do
60
+
61
+ it "returns an array" do
62
+ expect(subject.messages).to be_kind_of Array
63
+ end
64
+
65
+ it "is delegated to the #object" do
66
+ expect(subject.messages).to contain_exactly object.messages
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::Listener do
4
+
5
+ subject { described_class.new double }
6
+
7
+ it "is a simple delegator" do
8
+ expect(subject).to be_kind_of SimpleDelegator
9
+ end
10
+
11
+ describe "#otherwise" do
12
+
13
+ it "is defined" do
14
+ expect(subject).to respond_to :otherwise
15
+ end
16
+
17
+ end # #otherwise
18
+
19
+ describe "#finalize" do
20
+
21
+ before do
22
+ subject.__getobj__.singleton_class.send(:define_method, :item) { nil }
23
+ subject.singleton_class.send(:define_method, :on_success) { nil }
24
+ subject.singleton_class.send(:define_method, :otherwise) { nil }
25
+ end
26
+
27
+ it "calls #otherwise when no other methods has been checked" do
28
+ expect(subject).to receive(:otherwise)
29
+ subject.finalize
30
+ end
31
+
32
+ it "calls #otherwise when undefined method has been checked" do
33
+ expect(subject).to receive(:otherwise)
34
+ subject.respond_to? :on_error
35
+ subject.finalize
36
+ end
37
+
38
+ it "doesn't call #otherwise when defined method has been checked" do
39
+ expect(subject).not_to receive(:otherwise)
40
+ subject.respond_to? :on_success
41
+ subject.finalize
42
+ end
43
+
44
+ it "returns self" do
45
+ expect(subject.finalize).to eq subject
46
+ end
47
+
48
+ end # #finalize
49
+
50
+ end # ServiceObjects::Listener
@@ -0,0 +1,191 @@
1
+ # encoding: utf-8
2
+ require "json"
3
+
4
+ describe ServiceObjects::Message do
5
+
6
+ subject { described_class.new type: :foo, text: :bar }
7
+
8
+ it "is comparable" do
9
+ expect(subject).to be_kind_of ::Comparable
10
+ end
11
+
12
+ describe ".new" do
13
+
14
+ it "requires the type" do
15
+ expect { described_class.new text: :bar }.to raise_error ArgumentError
16
+ end
17
+
18
+ it "requires the text" do
19
+ expect { described_class.new type: :foo }.to raise_error ArgumentError
20
+ end
21
+
22
+ it "freezes the object" do
23
+ expect(subject).to be_frozen
24
+ end
25
+
26
+ end # .new
27
+
28
+ describe "#type" do
29
+
30
+ it "is stringified" do
31
+ expect(subject.type).to eq "foo"
32
+ end
33
+
34
+ it "is frozen" do
35
+ expect(subject.type).to be_frozen
36
+ end
37
+
38
+ end # #type
39
+
40
+ describe "#text" do
41
+
42
+ it "is stringified" do
43
+ expect(subject.text).to eq "bar"
44
+ end
45
+
46
+ it "is frozen" do
47
+ expect(subject.text).to be_frozen
48
+ end
49
+
50
+ end # #text
51
+
52
+ describe "#priority" do
53
+
54
+ it "is float" do
55
+ expect(subject.priority).to be_kind_of Float
56
+ end
57
+
58
+ it "is customizable" do
59
+ subject = described_class.new type: "foo", text: "bar", priority: 1.5
60
+ expect(subject.priority).to eq 1.5
61
+ end
62
+
63
+ it "is set by default to 0.0 for non-errors" do
64
+ subject = described_class.new type: "foo", text: "bar"
65
+ expect(subject.priority).to eq 0.0
66
+ end
67
+
68
+ it "is set by default to -1.0 for errors" do
69
+ subject = described_class.new type: "error", text: "bar"
70
+ expect(subject.priority).to eq(-1.0)
71
+ end
72
+
73
+ end # #priority
74
+
75
+ describe "#inspect" do
76
+
77
+ it "returns text, type and priority of the message" do
78
+ expect(subject.inspect)
79
+ .to eq %W(
80
+ #<ServiceObjects::Message:#{ subject.object_id }
81
+ type=\"#{ subject.type }\"
82
+ text=\"#{ subject.text }\"
83
+ priority=#{ subject.priority }>
84
+ ).join(" ")
85
+ end
86
+
87
+ end # #inspect
88
+
89
+ describe "#==" do
90
+
91
+ it "treats messages with the same type, text and priority as equal" do
92
+ a = described_class.new type: "foo", text: "bar"
93
+ b = described_class.new type: "foo", text: "bar"
94
+ expect(a == b).to be_truthy
95
+ end
96
+
97
+ it "treats messages with different types as different" do
98
+ a = described_class.new type: "bar", text: "foo"
99
+ b = described_class.new type: "baz", text: "foo"
100
+ expect(a == b).to be_falsey
101
+ end
102
+
103
+ it "treats messages with different texts as different" do
104
+ a = described_class.new type: "foo", text: "bar"
105
+ b = described_class.new type: "foo", text: "baz"
106
+ expect(a == b).to be_falsey
107
+ end
108
+
109
+ it "treats messages with different priorities as different" do
110
+ a = described_class.new type: "foo", text: "bar", priority: 1
111
+ b = described_class.new type: "foo", text: "bar", priority: 1.1
112
+ expect(a == b).to be_falsey
113
+ end
114
+
115
+ it "treats message as different from non-message" do
116
+ a = described_class.new type: "foo", text: "bar"
117
+ b = Struct.new(:type, :text).new("foo", "bar")
118
+ expect(a == b).to be_falsey
119
+ end
120
+
121
+ end # #==
122
+
123
+ describe "#<=>" do
124
+
125
+ it "orders messages by priorities" do
126
+ a = described_class.new type: "foo", text: "bar", priority: 0
127
+ b = described_class.new type: "foo", text: "bar", priority: 0.1
128
+ expect(a <=> b).to eq(-1)
129
+ expect(b <=> a).to eq(1)
130
+ end
131
+
132
+ it "orders messages by type" do
133
+ a = described_class.new type: "bar", text: "foo"
134
+ b = described_class.new type: "baz", text: "foo"
135
+ expect(a <=> b).to eq(-1)
136
+ expect(b <=> a).to eq(1)
137
+ end
138
+
139
+ it "orders messages by text" do
140
+ a = described_class.new type: "foo", text: "bar"
141
+ b = described_class.new type: "foo", text: "baz"
142
+ expect(a <=> b).to eq(-1)
143
+ expect(b <=> a).to eq(1)
144
+ end
145
+
146
+ it "orders messages at first by priorities" do
147
+ a = described_class.new type: "bar", text: "bar", priority: 0
148
+ b = described_class.new type: "baz", text: "baz", priority: 1
149
+ expect(a <=> b).to eq(-1)
150
+ expect(b <=> a).to eq(1)
151
+ end
152
+
153
+ it "orders messages at second by types" do
154
+ a = described_class.new type: "bar", text: "bar"
155
+ b = described_class.new type: "baz", text: "baz"
156
+ expect(a <=> b).to eq(-1)
157
+ expect(b <=> a).to eq(1)
158
+ end
159
+
160
+ it "treats messages with the same type, text and priority as equal" do
161
+ a = described_class.new type: "foo", text: "bar"
162
+ b = described_class.new type: "foo", text: "bar"
163
+ expect(a <=> b).to eq 0
164
+ expect(b <=> a).to eq 0
165
+ end
166
+
167
+ it "returns nil if other value is not a message" do
168
+ expect(subject <=> 1).to be_nil
169
+ end
170
+
171
+ end # #<=>
172
+
173
+ describe "#to_h" do
174
+
175
+ it "serializes type and text" do
176
+ hash = { type: subject.type, text: subject.text }
177
+ expect(subject.to_h).to eq hash
178
+ end
179
+
180
+ end # #to_h
181
+
182
+ describe "#to_json" do
183
+
184
+ it "serializes type and text" do
185
+ hash = { type: subject.type, text: subject.text }
186
+ expect(subject.to_json).to eq hash.to_json
187
+ end
188
+
189
+ end # #to_json
190
+
191
+ end # ServiceObjects::Message
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::NULL do
4
+
5
+ it "respond to arbitrary method" do
6
+ expect(true).to eq subject.respond_to?(:arbitrary_method)
7
+ end
8
+
9
+ it "returns itself" do
10
+ expect(subject.arbitrary_method).to eq subject
11
+ end
12
+
13
+ it "is a singleton" do
14
+ expect(subject.class.instance.__id__).to eq subject.__id__
15
+ end
16
+
17
+ end # describe ServiceObjects::NULL
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::Utils::NormalHash do
4
+
5
+ describe ".from" do
6
+
7
+ it "symbolizes keys of existing hash" do
8
+ source = { "foo" => "foo", "bar" => { "bar" => "bar", "baz" => nil } }
9
+ target = { foo: "foo", bar: { bar: "bar", baz: nil } }
10
+
11
+ expect(described_class.from(source)).to eq target
12
+ end
13
+
14
+ end # .new
15
+
16
+ end # ServiceObjects::Utils::NormalHash
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: service_objects
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Kozin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: extlib
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.9'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: naught
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: wisper
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: hexx-suit
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.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.0'
83
+ description: Base class for objects, that implements both the Interactor and Observer
84
+ design patterns.
85
+ email: andrew.kozin@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files:
89
+ - README.md
90
+ - LICENSE
91
+ - config/metrics/STYLEGUIDE
92
+ files:
93
+ - ".coveralls.yml"
94
+ - ".metrics"
95
+ - ".rspec"
96
+ - ".rubocop.yml"
97
+ - ".travis.yml"
98
+ - ".yardopts"
99
+ - Gemfile
100
+ - Guardfile
101
+ - LICENSE
102
+ - README.md
103
+ - Rakefile
104
+ - config/metrics/STYLEGUIDE
105
+ - config/metrics/cane.yml
106
+ - config/metrics/churn.yml
107
+ - config/metrics/flay.yml
108
+ - config/metrics/metric_fu.yml
109
+ - config/metrics/pippi.yml
110
+ - config/metrics/reek.yml
111
+ - config/metrics/roodi.yml
112
+ - config/metrics/rubocop.yml
113
+ - config/metrics/saikuro.yml
114
+ - config/metrics/simplecov.yml
115
+ - config/metrics/yardstick.yml
116
+ - lib/service_objects.rb
117
+ - lib/service_objects/base.rb
118
+ - lib/service_objects/helpers/dependable.rb
119
+ - lib/service_objects/helpers/exceptions.rb
120
+ - lib/service_objects/helpers/messages.rb
121
+ - lib/service_objects/helpers/parameterized.rb
122
+ - lib/service_objects/helpers/parameters.rb
123
+ - lib/service_objects/helpers/validations.rb
124
+ - lib/service_objects/invalid.rb
125
+ - lib/service_objects/listener.rb
126
+ - lib/service_objects/message.rb
127
+ - lib/service_objects/null.rb
128
+ - lib/service_objects/utils/normal_hash.rb
129
+ - lib/service_objects/version.rb
130
+ - service_objects.gemspec
131
+ - spec/spec_helper.rb
132
+ - spec/tests/base_spec.rb
133
+ - spec/tests/helpers/dependable_spec.rb
134
+ - spec/tests/helpers/exceptions_spec.rb
135
+ - spec/tests/helpers/messages_spec.rb
136
+ - spec/tests/helpers/parameterized_spec.rb
137
+ - spec/tests/helpers/parameters_spec.rb
138
+ - spec/tests/helpers/validations_spec.rb
139
+ - spec/tests/invalid_spec.rb
140
+ - spec/tests/listener_spec.rb
141
+ - spec/tests/message_spec.rb
142
+ - spec/tests/null_spec.rb
143
+ - spec/tests/utils/normal_hash_spec.rb
144
+ homepage: https://github.com/nepalez/service_objects
145
+ licenses:
146
+ - MIT
147
+ metadata: {}
148
+ post_install_message:
149
+ rdoc_options: []
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: '2.1'
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ requirements: []
163
+ rubyforge_project:
164
+ rubygems_version: 2.2.2
165
+ signing_key:
166
+ specification_version: 4
167
+ summary: Service objects (interactors).
168
+ test_files:
169
+ - spec/spec_helper.rb
170
+ - spec/tests/listener_spec.rb
171
+ - spec/tests/message_spec.rb
172
+ - spec/tests/null_spec.rb
173
+ - spec/tests/base_spec.rb
174
+ - spec/tests/invalid_spec.rb
175
+ - spec/tests/helpers/parameterized_spec.rb
176
+ - spec/tests/helpers/parameters_spec.rb
177
+ - spec/tests/helpers/messages_spec.rb
178
+ - spec/tests/helpers/validations_spec.rb
179
+ - spec/tests/helpers/exceptions_spec.rb
180
+ - spec/tests/helpers/dependable_spec.rb
181
+ - spec/tests/utils/normal_hash_spec.rb
182
+ has_rdoc: