service_objects 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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"