service_objects 0.1.0 → 1.0.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.metrics +1 -0
  4. data/.travis.yml +9 -1
  5. data/.yardopts +1 -1
  6. data/Gemfile +1 -1
  7. data/Guardfile +29 -8
  8. data/LICENSE +1 -1
  9. data/README.md +179 -342
  10. data/Rakefile +3 -3
  11. data/config/metrics/churn.yml +1 -1
  12. data/config/metrics/flay.yml +1 -1
  13. data/config/metrics/metric_fu.yml +1 -0
  14. data/config/metrics/rubocop.yml +4 -4
  15. data/config/metrics/simplecov.yml +1 -1
  16. data/lib/service_objects.rb +6 -9
  17. data/lib/service_objects/base.rb +190 -17
  18. data/lib/service_objects/listener.rb +21 -75
  19. data/lib/service_objects/message.rb +15 -96
  20. data/lib/service_objects/version.rb +1 -1
  21. data/service_objects.gemspec +11 -9
  22. data/spec/lib/base_spec.rb +247 -0
  23. data/spec/lib/listener_spec.rb +96 -0
  24. data/spec/lib/message_spec.rb +48 -0
  25. data/spec/spec_helper.rb +8 -6
  26. metadata +56 -93
  27. data/bin/service +0 -17
  28. data/config/metrics/pippi.yml +0 -3
  29. data/lib/service_objects/cli.rb +0 -117
  30. data/lib/service_objects/cli/locale.erb +0 -20
  31. data/lib/service_objects/cli/service.erb +0 -125
  32. data/lib/service_objects/cli/spec.erb +0 -87
  33. data/lib/service_objects/helpers.rb +0 -17
  34. data/lib/service_objects/helpers/dependable.rb +0 -63
  35. data/lib/service_objects/helpers/exceptions.rb +0 -64
  36. data/lib/service_objects/helpers/messages.rb +0 -95
  37. data/lib/service_objects/helpers/parameterized.rb +0 -85
  38. data/lib/service_objects/helpers/parameters.rb +0 -71
  39. data/lib/service_objects/helpers/validations.rb +0 -54
  40. data/lib/service_objects/invalid.rb +0 -55
  41. data/lib/service_objects/null.rb +0 -26
  42. data/lib/service_objects/parsers.rb +0 -13
  43. data/lib/service_objects/parsers/dependency.rb +0 -69
  44. data/lib/service_objects/parsers/notification.rb +0 -85
  45. data/lib/service_objects/rspec.rb +0 -75
  46. data/lib/service_objects/utils/normal_hash.rb +0 -34
  47. data/spec/tests/base_spec.rb +0 -43
  48. data/spec/tests/bin/service_spec.rb +0 -18
  49. data/spec/tests/cli_spec.rb +0 -179
  50. data/spec/tests/helpers/dependable_spec.rb +0 -77
  51. data/spec/tests/helpers/exceptions_spec.rb +0 -112
  52. data/spec/tests/helpers/messages_spec.rb +0 -64
  53. data/spec/tests/helpers/parameterized_spec.rb +0 -136
  54. data/spec/tests/helpers/parameters_spec.rb +0 -71
  55. data/spec/tests/helpers/validations_spec.rb +0 -60
  56. data/spec/tests/invalid_spec.rb +0 -69
  57. data/spec/tests/listener_spec.rb +0 -73
  58. data/spec/tests/message_spec.rb +0 -191
  59. data/spec/tests/null_spec.rb +0 -17
  60. data/spec/tests/parsers/dependency_spec.rb +0 -29
  61. data/spec/tests/parsers/notification_spec.rb +0 -84
  62. data/spec/tests/rspec_spec.rb +0 -86
  63. data/spec/tests/utils/normal_hash_spec.rb +0 -16
@@ -4,6 +4,6 @@ module ServiceObjects
4
4
 
5
5
  # The semantic version of the module.
6
6
  # @see http://semver.org/ Semantic versioning 2.0
7
- VERSION = "0.1.0".freeze
7
+ VERSION = "1.0.0".freeze
8
8
 
9
9
  end # module ServiceObjects
@@ -13,18 +13,20 @@ Gem::Specification.new do |gem|
13
13
  " both the Interactor and Observer design patterns."
14
14
  gem.license = "MIT"
15
15
 
16
- gem.require_paths = ["lib"]
17
16
  gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
- gem.executables = ["service"]
19
17
  gem.test_files = Dir["spec/**/*.rb"]
20
18
  gem.extra_rdoc_files = Dir["README.md", "LICENSE"]
19
+ gem.require_paths = ["lib"]
21
20
 
22
- gem.required_ruby_version = "~> 2.1"
23
- gem.add_runtime_dependency "activemodel", "~> 4.1"
24
- gem.add_runtime_dependency "extlib", "~> 0.9"
25
- gem.add_runtime_dependency "naught", "~> 1.0"
21
+ gem.required_ruby_version = "~> 2.0"
22
+
23
+ gem.add_runtime_dependency "attestor", "~> 2.2"
24
+ gem.add_runtime_dependency "attr_coerced", "~> 0.0"
25
+ gem.add_runtime_dependency "chronicles", "~> 0.0"
26
+ gem.add_runtime_dependency "virtus", "~> 1.0"
26
27
  gem.add_runtime_dependency "wisper", "~> 1.6"
27
- gem.add_runtime_dependency "hexx-cli", "~> 0.0"
28
- gem.add_development_dependency "hexx-rspec", "~> 0.3"
29
28
 
30
- end
29
+ gem.add_development_dependency "hexx-cli", "~> 0.0"
30
+ gem.add_development_dependency "hexx-rspec", "~> 0.4"
31
+
32
+ end # Gem::Specification
@@ -0,0 +1,247 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::Base do
4
+
5
+ let(:test_class) { Class.new(described_class) }
6
+
7
+ before { ServiceObjects::Test = test_class }
8
+ after { ServiceObjects.send :remove_const, :Test }
9
+
10
+ subject { test_class.new }
11
+
12
+ describe ".new" do
13
+
14
+ it "includes Virtus.model" do
15
+ expect(subject).to be_kind_of Virtus::Model::Core
16
+ end
17
+
18
+ it "includes Attestor::Validations" do
19
+ expect(subject).to be_kind_of Attestor::Validations
20
+ end
21
+
22
+ it "includes a Wisper::Publisher" do
23
+ expect(subject).to be_kind_of Wisper::Publisher
24
+ end
25
+
26
+ it "includes an Attr::Coerced" do
27
+ expect(subject).to be_kind_of AttrCoerced
28
+ end
29
+
30
+ end # describe .new
31
+
32
+ describe ".dependency" do
33
+
34
+ let(:implementation) { String }
35
+
36
+ context "with default value" do
37
+
38
+ before { test_class.dependency :foo, default: implementation }
39
+
40
+ it "declares the getter" do
41
+ expect(subject).to respond_to :foo
42
+ end
43
+
44
+ it "declares the setter" do
45
+ expect(subject).to respond_to :foo=
46
+ expect { subject.foo = Object }.to change { subject.foo }.to Object
47
+ end
48
+
49
+ it "sets the default value" do
50
+ expect(subject.foo).to eq implementation
51
+ end
52
+
53
+ end # context
54
+
55
+ context "without default value" do
56
+
57
+ before { test_class.dependency :foo }
58
+
59
+ it "declares the getter" do
60
+ expect(subject).to respond_to :foo
61
+ end
62
+
63
+ it "declares the setter" do
64
+ expect(subject).to respond_to :foo=
65
+ expect { subject.foo = Object }.to change { subject.foo }.to Object
66
+ end
67
+
68
+ it "sets the default value" do
69
+ expect(subject.foo).to be_nil
70
+ end
71
+
72
+ end # context
73
+
74
+ end # describe .dependency
75
+
76
+ describe "#validate" do
77
+
78
+ before { allow(subject).to receive :publish }
79
+
80
+ it "calls #validate!" do
81
+ expect(subject).to receive(:validate!).with(:foo)
82
+ subject.validate :foo
83
+ end
84
+
85
+ context "when #validate! fails" do
86
+
87
+ let(:error) { Attestor::InvalidError.new subject, "foo" }
88
+
89
+ before { allow(subject).to receive(:validate!) { fail error } }
90
+
91
+ it "doesn't fail" do
92
+ expect { subject.validate :foo }.not_to raise_error
93
+ end
94
+
95
+ it "publishes an error" do
96
+ expect(subject).to receive(:publish) do |name, *|
97
+ expect(name).to eq :error
98
+ end
99
+ subject.validate :foo
100
+ end
101
+
102
+ it "publishes error messages" do
103
+ expect(subject).to receive(:publish) do |_, messages|
104
+ expect(messages).to be_kind_of Array
105
+ expect(messages.count).to eq 1
106
+ expect(messages.first.type).to eq :error
107
+ expect(messages.first.text).to eq "foo"
108
+ end
109
+ subject.validate :foo
110
+ end
111
+
112
+ end # context
113
+
114
+ context "when #validate! passes" do
115
+
116
+ before { allow(subject).to receive(:validate!) }
117
+
118
+ it "publishes nothing" do
119
+ expect(subject).not_to receive(:publish)
120
+ subject.validate :foo
121
+ end
122
+
123
+ end # context
124
+
125
+ end # describe #validate
126
+
127
+ describe "#run" do
128
+
129
+ it "calls #run!" do
130
+ expect(subject).to receive(:run!)
131
+ subject.run
132
+ end
133
+
134
+ it "catches :published" do
135
+ allow(subject).to receive(:run!) { throw :published }
136
+ expect { subject.run }.not_to raise_error
137
+ end
138
+
139
+ it "raises NotImplementedError when #run! not implemented" do
140
+ expect { subject.run }.to raise_error do |err|
141
+ expect(err).to be_kind_of NotImplementedError
142
+ expect(err.message).to eq "#{ subject.class.name }#run! not implemented"
143
+ end
144
+ end
145
+
146
+ end # describe #run
147
+
148
+ describe "#message" do
149
+
150
+ context "with a symbolic key" do
151
+
152
+ let(:scope) { %i(service_objects service_objects/test foo) }
153
+ let(:result) { subject.message :foo, :bar, baz: :qux }
154
+
155
+ it "returns the message" do
156
+ expect(result).to be_kind_of ServiceObjects::Message
157
+ end
158
+
159
+ it "sets the proper message type" do
160
+ expect(result.type).to eq :foo
161
+ end
162
+
163
+ it "translates the key" do
164
+ expect(result.text).to eq I18n.t(:bar, scope: scope)
165
+ end
166
+
167
+ it "uses options" do
168
+ expect(I18n).to receive(:t).with(:bar, scope: scope, baz: :qux)
169
+ result
170
+ end
171
+
172
+ it "ignores the :scope option" do
173
+ expect(I18n).to receive(:t).with(:bar, scope: scope)
174
+ subject.message :foo, :bar, scope: :qux
175
+ end
176
+
177
+ end # context
178
+
179
+ context "with non-symbolic key" do
180
+
181
+ let(:result) { subject.message :foo, 11, baz: :qux }
182
+
183
+ it "returns the message" do
184
+ expect(result).to be_kind_of ServiceObjects::Message
185
+ end
186
+
187
+ it "sets the proper message type" do
188
+ expect(result.type).to eq :foo
189
+ end
190
+
191
+ it "stringifies the argument" do
192
+ expect(result.text).to eq "11"
193
+ end
194
+
195
+ end # context
196
+
197
+ end # describe #translate
198
+
199
+ describe "#publish" do
200
+
201
+ let(:listener) { double foo: nil }
202
+ before { subject.subscribe listener }
203
+
204
+ it "publishes notification" do
205
+ expect(listener).to receive :foo
206
+ begin
207
+ subject.send :publish, :foo
208
+ rescue
209
+ end
210
+ end
211
+
212
+ it "throws :published" do
213
+ expect { subject.send :publish, :success }.to raise_error do |error|
214
+ expect(error.message).to eq "uncaught throw :published"
215
+ end
216
+ end
217
+
218
+ end # describe #publish
219
+
220
+ describe "#run_service" do
221
+
222
+ let(:service) { double subscribe: nil, run: nil }
223
+ let(:listener) { double finalize: nil }
224
+
225
+ after { subject.run_service service, listener }
226
+
227
+ it "subscribes service for the listener" do
228
+ expect(service).to receive(:subscribe).with(listener, prefix: :on).once
229
+ end
230
+
231
+ it "runs the service" do
232
+ expect(service).to receive(:run).once
233
+ end
234
+
235
+ it "finalizes the listener" do
236
+ expect(listener).to receive(:finalize).once
237
+ end
238
+
239
+ it "runs commands in the proper order" do
240
+ expect(service).to receive(:subscribe).ordered
241
+ expect(service).to receive(:run).ordered
242
+ expect(listener).to receive(:finalize).ordered
243
+ end
244
+
245
+ end # describe #run_service
246
+
247
+ end # describe ServiceObjects::Attributes
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::Listener do
4
+
5
+ let(:test_class) { Class.new(described_class) { attr_reader :foo } }
6
+ let(:object) { Class.new { private def bar; end }.new }
7
+ subject { test_class.new(object) }
8
+
9
+ describe "#respond_to?" do
10
+
11
+ it "returns true if method defined" do
12
+ expect(subject).to respond_to :foo
13
+ end
14
+
15
+ it "returns true if method defined by object" do
16
+ expect(subject.respond_to?(:bar)).to be_falsey
17
+ expect(subject.respond_to?(:bar, true)).to be_truthy
18
+ end
19
+
20
+ it "returns false if method neither defined by itself nor by object" do
21
+ expect(subject).not_to respond_to :baz
22
+ end
23
+
24
+ end # describe #respond_to?
25
+
26
+ describe "arbitrary method" do
27
+
28
+ it "is delegated to object" do
29
+ expect(object).to receive(:bar)
30
+ subject.bar
31
+ end
32
+
33
+ end # describe arbitrary method
34
+
35
+ describe "#otherwise" do
36
+
37
+ it "is defined" do
38
+ expect(subject).to respond_to :otherwise
39
+ end
40
+
41
+ it "passes" do
42
+ expect { subject.otherwise }.not_to raise_error
43
+ end
44
+
45
+ end # describe #otherwise
46
+
47
+ describe "#finalize" do
48
+
49
+ context "[when own method has been called]" do
50
+
51
+ before { subject.foo }
52
+
53
+ it "calls #otherwise" do
54
+ expect(subject).to receive(:otherwise)
55
+ subject.finalize
56
+ end
57
+
58
+ it "doesn't call #otherwise twice" do
59
+ expect(subject).to receive(:otherwise).once
60
+ 2.times { subject.finalize }
61
+ end
62
+ end
63
+
64
+ context "[when own method has been called]" do
65
+
66
+ it "doesn't call it again" do
67
+ expect(subject).to receive(:otherwise).once
68
+ subject.otherwise
69
+ subject.finalize
70
+ end
71
+
72
+ end # context
73
+
74
+ context "[when delegated method has been called]" do
75
+
76
+ before { subject.bar }
77
+
78
+ it "doesn't call #otherwise" do
79
+ expect(subject).not_to receive(:otherwise)
80
+ subject.finalize
81
+ end
82
+
83
+ end # context
84
+
85
+ context "[when no methods has been called]" do
86
+
87
+ it "doesn't call #otherwise" do
88
+ expect(subject).not_to receive(:otherwise)
89
+ subject.finalize
90
+ end
91
+
92
+ end # context
93
+
94
+ end # describe #finalize
95
+
96
+ end # describe ServiceObjects::Listener
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ describe ServiceObjects::Message do
4
+
5
+ let(:type) { :foo }
6
+ let(:text) { "foo" }
7
+
8
+ subject { described_class.new type, text }
9
+
10
+ describe ".new" do
11
+
12
+ it "creates immutable object" do
13
+ expect(subject).to be_frozen
14
+ end
15
+
16
+ end # describe .new
17
+
18
+ describe "#type" do
19
+
20
+ it "is initialized" do
21
+ expect(subject.type).to eq type
22
+ end
23
+
24
+ it "is symbolized" do
25
+ subject = described_class.new type.to_s, text
26
+ expect(subject.type).to eq type
27
+ end
28
+
29
+ end # describe #type
30
+
31
+ describe "#text" do
32
+
33
+ it "is initialized" do
34
+ expect(subject.text).to eq text
35
+ end
36
+
37
+ it "is stringified" do
38
+ subject = described_class.new type, text.to_sym
39
+ expect(subject.text).to eq text
40
+ end
41
+
42
+ it "is immutable" do
43
+ expect(subject.text).to be_frozen
44
+ end
45
+
46
+ end # describe #text
47
+
48
+ end # describe ServiceObjects::Message
@@ -1,10 +1,12 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Loads the RSpec test suit.
4
- require "hexx-rspec"
3
+ begin
4
+ require "hexx-suit"
5
+ Hexx::Suit.load_metrics_for(self)
6
+ rescue LoadError
7
+ require "hexx-rspec"
8
+ Hexx::RSpec.load_metrics_for(self)
9
+ end
5
10
 
6
- # Loads runtime metrics in the current scope
7
- Hexx::RSpec.load_metrics_for(self)
8
-
9
- # Loads the code of the module.
11
+ # Loads the code under test
10
12
  require "service_objects"