service_objects 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.
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: