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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.metrics +5 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +4 -0
- data/.yardopts +3 -0
- data/Gemfile +3 -0
- data/Guardfile +16 -0
- data/LICENSE +21 -0
- data/README.md +461 -0
- data/Rakefile +17 -0
- data/config/metrics/STYLEGUIDE +230 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +14 -0
- data/config/metrics/pippi.yml +3 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +75 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +6 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/service_objects/base.rb +43 -0
- data/lib/service_objects/helpers/dependable.rb +63 -0
- data/lib/service_objects/helpers/exceptions.rb +64 -0
- data/lib/service_objects/helpers/messages.rb +96 -0
- data/lib/service_objects/helpers/parameterized.rb +85 -0
- data/lib/service_objects/helpers/parameters.rb +71 -0
- data/lib/service_objects/helpers/validations.rb +54 -0
- data/lib/service_objects/invalid.rb +55 -0
- data/lib/service_objects/listener.rb +97 -0
- data/lib/service_objects/message.rb +117 -0
- data/lib/service_objects/null.rb +26 -0
- data/lib/service_objects/utils/normal_hash.rb +34 -0
- data/lib/service_objects/version.rb +9 -0
- data/lib/service_objects.rb +12 -0
- data/service_objects.gemspec +28 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/tests/base_spec.rb +43 -0
- data/spec/tests/helpers/dependable_spec.rb +77 -0
- data/spec/tests/helpers/exceptions_spec.rb +112 -0
- data/spec/tests/helpers/messages_spec.rb +64 -0
- data/spec/tests/helpers/parameterized_spec.rb +136 -0
- data/spec/tests/helpers/parameters_spec.rb +71 -0
- data/spec/tests/helpers/validations_spec.rb +60 -0
- data/spec/tests/invalid_spec.rb +69 -0
- data/spec/tests/listener_spec.rb +50 -0
- data/spec/tests/message_spec.rb +191 -0
- data/spec/tests/null_spec.rb +17 -0
- data/spec/tests/utils/normal_hash_spec.rb +16 -0
- metadata +182 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe ServiceObjects::Helpers::Dependable do
|
4
|
+
|
5
|
+
let(:test_class) { Class.new }
|
6
|
+
subject { test_class.new }
|
7
|
+
|
8
|
+
before { test_class.extend described_class }
|
9
|
+
|
10
|
+
describe ".depends_on" do
|
11
|
+
|
12
|
+
shared_examples "dependency declarator" do
|
13
|
+
|
14
|
+
it "[defines dependency getter]" do
|
15
|
+
expect(subject).to respond_to dependency_name
|
16
|
+
end
|
17
|
+
|
18
|
+
it "[defines dependency sette]r" do
|
19
|
+
expect(subject).to respond_to("#{ dependency_name }=").with(1).argument
|
20
|
+
end
|
21
|
+
|
22
|
+
it "[sets default dependency]" do
|
23
|
+
expect(subject.send dependency_name).to eq default_value
|
24
|
+
end
|
25
|
+
|
26
|
+
it "[resets dependency to default implementation]" do
|
27
|
+
expect { subject.send "#{ dependency_name }=", nil }
|
28
|
+
.not_to change { subject.send dependency_name }
|
29
|
+
end
|
30
|
+
|
31
|
+
end # examples definition
|
32
|
+
|
33
|
+
context "without arguments" do
|
34
|
+
|
35
|
+
it "fails" do
|
36
|
+
expect { test_class.depends_on }.to raise_error
|
37
|
+
end
|
38
|
+
|
39
|
+
end # context
|
40
|
+
|
41
|
+
context "with one argument" do
|
42
|
+
|
43
|
+
let(:default_value) { ServiceObjects::NULL }
|
44
|
+
let(:dependency_name) { :get_item }
|
45
|
+
|
46
|
+
before { test_class.depends_on :get_item }
|
47
|
+
|
48
|
+
it_behaves_like "dependency declarator"
|
49
|
+
|
50
|
+
end # context
|
51
|
+
|
52
|
+
context "with two arguments" do
|
53
|
+
|
54
|
+
let(:default_value) { Class.new }
|
55
|
+
let(:dependency_name) { :get_item }
|
56
|
+
|
57
|
+
before { test_class.depends_on :get_item, default: default_value }
|
58
|
+
|
59
|
+
it_behaves_like "dependency declarator"
|
60
|
+
|
61
|
+
end # context
|
62
|
+
|
63
|
+
context "repeatedly" do
|
64
|
+
|
65
|
+
let(:default_value) { Class.new }
|
66
|
+
let(:dependency_name) { :get_item }
|
67
|
+
|
68
|
+
before { test_class.depends_on :get_item }
|
69
|
+
before { test_class.depends_on :get_item, default: default_value }
|
70
|
+
|
71
|
+
it_behaves_like "dependency declarator"
|
72
|
+
|
73
|
+
end # context
|
74
|
+
|
75
|
+
end # describe .depends_on
|
76
|
+
|
77
|
+
end # describe ServiceObject::Helpers::Dependable
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe ServiceObjects::Helpers::Exceptions do
|
4
|
+
|
5
|
+
let(:service_invalid) { ServiceObjects::Invalid }
|
6
|
+
let(:messages_class) { ServiceObjects::Message }
|
7
|
+
let(:messages_module) { ServiceObjects::Helpers::Messages }
|
8
|
+
let(:test_class) { Class.new }
|
9
|
+
|
10
|
+
before { test_class.include described_class }
|
11
|
+
|
12
|
+
it "includes ServiceObjects::Helpers::Messages" do
|
13
|
+
expect(test_class).to include messages_module
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#escape" do
|
17
|
+
|
18
|
+
subject { test_class.new }
|
19
|
+
|
20
|
+
def escape_from_foo(with_exception: nil)
|
21
|
+
subject.escape do
|
22
|
+
fail with_exception if with_exception
|
23
|
+
"foo"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the block raises nothing" do
|
28
|
+
|
29
|
+
let(:result) { escape_from_foo }
|
30
|
+
|
31
|
+
it "yields the block" do
|
32
|
+
expect(result).to eq "foo"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when ServiceObjects::Invalid raised by the object" do
|
38
|
+
|
39
|
+
let(:exception) { service_invalid.new subject }
|
40
|
+
|
41
|
+
it "re-raises Invalid error" do
|
42
|
+
expect { escape_from_foo with_exception: exception }
|
43
|
+
.to raise_error service_invalid
|
44
|
+
end
|
45
|
+
|
46
|
+
it "doesn't mutate the object" do
|
47
|
+
expect { escape_from_foo with_exception: exception rescue nil }
|
48
|
+
.not_to change { subject }
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when ServiceObjects::Invalid raised by another object" do
|
54
|
+
|
55
|
+
let(:another_object) { test_class.new }
|
56
|
+
let(:exception) { service_invalid.new another_object }
|
57
|
+
|
58
|
+
before { another_object.add_message type: "error", text: "bar" }
|
59
|
+
|
60
|
+
it "raises Invalid error" do
|
61
|
+
expect { escape_from_foo with_exception: exception }
|
62
|
+
.to raise_error service_invalid
|
63
|
+
end
|
64
|
+
|
65
|
+
it "raises the exception of its own" do
|
66
|
+
begin
|
67
|
+
escape_from_foo with_exception: exception
|
68
|
+
rescue => err
|
69
|
+
expect(err.object).to eq subject
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "populates messages from the exception to self" do
|
74
|
+
escape_from_foo with_exception: exception rescue nil
|
75
|
+
|
76
|
+
expect(subject.messages).to eq another_object.messages
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when the block raises StandardError" do
|
82
|
+
|
83
|
+
let(:exception) { StandardError.new("text") }
|
84
|
+
let(:expected_message) { messages_class.new type: "error", text: "text" }
|
85
|
+
|
86
|
+
it "raises a SerivceObjects::Invalid" do
|
87
|
+
expect { escape_from_foo with_exception: exception }
|
88
|
+
.to raise_error service_invalid
|
89
|
+
end
|
90
|
+
|
91
|
+
it "adds an error to the messages" do
|
92
|
+
escape_from_foo with_exception: exception rescue nil
|
93
|
+
|
94
|
+
expect(subject.messages).to contain_exactly expected_message
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when the block raises another exception" do
|
100
|
+
|
101
|
+
let(:exception) { SyntaxError.new }
|
102
|
+
|
103
|
+
it "re-raises the exception unchanged" do
|
104
|
+
expect { escape_from_foo with_exception: exception }
|
105
|
+
.to raise_error exception
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end # describe .escape
|
111
|
+
|
112
|
+
end # describe ServiceObjects::Exceptions
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe ServiceObjects::Helpers::Messages do
|
4
|
+
|
5
|
+
let(:messages_class) { ServiceObjects::Message }
|
6
|
+
let(:test_class) { Class.new }
|
7
|
+
|
8
|
+
before { ServiceObjects::Test = test_class }
|
9
|
+
before { test_class.include described_class }
|
10
|
+
after { ServiceObjects.send :remove_const, :Test }
|
11
|
+
|
12
|
+
subject { test_class.new }
|
13
|
+
|
14
|
+
describe "#translate" do
|
15
|
+
|
16
|
+
let(:scope) { %w(activemodel messages models service_objects/test) }
|
17
|
+
let(:traslation) { I18n.t(:text, scope: scope, name: "name") }
|
18
|
+
|
19
|
+
it "translates symbols in the service's scope" do
|
20
|
+
expect(subject.translate(:text, name: "name")).to eq traslation
|
21
|
+
end
|
22
|
+
|
23
|
+
it "doesn't translate strings" do
|
24
|
+
expect(subject.translate("text")).to eq "text"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "converts non-symbolic argument to string" do
|
28
|
+
expect(subject.translate nil).to eq ""
|
29
|
+
expect(subject.translate 1).to eq "1"
|
30
|
+
end
|
31
|
+
|
32
|
+
end # #translate
|
33
|
+
|
34
|
+
describe "#messages" do
|
35
|
+
|
36
|
+
it "returns an array" do
|
37
|
+
expect(subject.messages).to be_kind_of Array
|
38
|
+
end
|
39
|
+
|
40
|
+
end # #messages
|
41
|
+
|
42
|
+
describe "#add_message" do
|
43
|
+
|
44
|
+
let(:message) { subject.messages.first }
|
45
|
+
|
46
|
+
it "adds a new message to the #messages" do
|
47
|
+
subject.add_message text: "foo", type: "bar", priority: 5, baz: 0
|
48
|
+
|
49
|
+
expect(message).to be_kind_of messages_class
|
50
|
+
expect(message.type).to eq "bar"
|
51
|
+
expect(message.text).to eq "foo"
|
52
|
+
expect(message.priority).to eq 5.0
|
53
|
+
end
|
54
|
+
|
55
|
+
it "translates a symbol" do
|
56
|
+
subject.add_message text: :foo, type: :bar, priority: 5, baz: 0
|
57
|
+
|
58
|
+
translation = subject.translate :foo, baz: 0
|
59
|
+
expect(message.text).to eq translation
|
60
|
+
end
|
61
|
+
|
62
|
+
end # #add_message
|
63
|
+
|
64
|
+
end # ServiceObjects::Helpers::Messages
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe ServiceObjects::Helpers::Parameterized do
|
4
|
+
|
5
|
+
let(:parameters) { ServiceObjects::Helpers::Parameters }
|
6
|
+
let(:test_class) { Class.new }
|
7
|
+
before { test_class.extend described_class }
|
8
|
+
subject { test_class.new }
|
9
|
+
|
10
|
+
it "includes ServiceObjects::Helpers::Parameters" do
|
11
|
+
expect(test_class).to include parameters
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ".allows_params" do
|
15
|
+
|
16
|
+
# ==========================================================================
|
17
|
+
# Defines behaviours
|
18
|
+
# ==========================================================================
|
19
|
+
|
20
|
+
shared_examples "white list" do
|
21
|
+
|
22
|
+
# 'allowed_params' taken from context
|
23
|
+
|
24
|
+
let(:whitelist) { Array(allowed_params).flatten.map(&:to_sym) }
|
25
|
+
|
26
|
+
it "[sets whitelist]" do
|
27
|
+
subject
|
28
|
+
expect(test_class.whitelist).to match_array whitelist
|
29
|
+
end
|
30
|
+
|
31
|
+
it "[returns whitelist]" do
|
32
|
+
expect(subject).to eq test_class.whitelist
|
33
|
+
end
|
34
|
+
|
35
|
+
end # behaviour
|
36
|
+
|
37
|
+
shared_examples "attributes creator" do
|
38
|
+
|
39
|
+
# 'allowed_params' taken from context
|
40
|
+
|
41
|
+
let(:whitelist) { Array(allowed_params).flatten.map(&:to_sym) }
|
42
|
+
let(:object) { test_class.new options }
|
43
|
+
let(:options) do
|
44
|
+
whitelist.inject({}) { |a, e| a.merge(e => rand(1..10)) }
|
45
|
+
end
|
46
|
+
|
47
|
+
before { subject }
|
48
|
+
|
49
|
+
it "[defines setters]" do
|
50
|
+
whitelist.each { |name| expect(object).to respond_to name }
|
51
|
+
end
|
52
|
+
|
53
|
+
it "[sets default values]" do
|
54
|
+
whitelist.each { |name| expect(object.send name).to eq options[name] }
|
55
|
+
end
|
56
|
+
|
57
|
+
it "[makes getters aliases to params]" do
|
58
|
+
whitelist.each do |name|
|
59
|
+
value = ("a".."z").to_a.sample
|
60
|
+
|
61
|
+
expect { object.params[name] = value }
|
62
|
+
.to change { object.send name }
|
63
|
+
.to value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "[defines getters]" do
|
68
|
+
whitelist.each { |name| expect(object).to respond_to "#{ name }=" }
|
69
|
+
end
|
70
|
+
|
71
|
+
it "[makes setters aliases to params]" do
|
72
|
+
whitelist.each do |name|
|
73
|
+
value = ("a".."z").to_a.sample
|
74
|
+
|
75
|
+
expect { object.send "#{ name }=", value }
|
76
|
+
.to change { object.params[name] }
|
77
|
+
.to value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end # behaviour
|
82
|
+
|
83
|
+
# ==========================================================================
|
84
|
+
# Tests behaviours
|
85
|
+
# ==========================================================================
|
86
|
+
|
87
|
+
context "without arguments" do
|
88
|
+
|
89
|
+
let(:allowed_params) { [] }
|
90
|
+
subject { test_class.allows_params allowed_params }
|
91
|
+
|
92
|
+
it_behaves_like "white list"
|
93
|
+
|
94
|
+
end # context
|
95
|
+
|
96
|
+
context "with one symbolic argument" do
|
97
|
+
|
98
|
+
let(:allowed_params) { :name }
|
99
|
+
subject { test_class.allows_params allowed_params }
|
100
|
+
|
101
|
+
it_behaves_like "white list"
|
102
|
+
it_behaves_like "attributes creator"
|
103
|
+
|
104
|
+
end # context
|
105
|
+
|
106
|
+
context "with one string argument" do
|
107
|
+
|
108
|
+
let(:allowed_params) { "name" }
|
109
|
+
subject { test_class.allows_params allowed_params }
|
110
|
+
|
111
|
+
it_behaves_like "white list"
|
112
|
+
it_behaves_like "attributes creator"
|
113
|
+
|
114
|
+
end # context
|
115
|
+
|
116
|
+
context "with a list of arguments" do
|
117
|
+
|
118
|
+
let(:allowed_params) { [:name, "code"] }
|
119
|
+
subject { test_class.allows_params(*allowed_params) }
|
120
|
+
|
121
|
+
it_behaves_like "white list"
|
122
|
+
it_behaves_like "attributes creator"
|
123
|
+
|
124
|
+
end # context
|
125
|
+
|
126
|
+
context "with an array of arguments" do
|
127
|
+
|
128
|
+
let(:allowed_params) { [:name, "code"] }
|
129
|
+
subject { test_class.allows_params allowed_params }
|
130
|
+
|
131
|
+
it_behaves_like "white list"
|
132
|
+
it_behaves_like "attributes creator"
|
133
|
+
|
134
|
+
end # context
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe ServiceObjects::Helpers::Parameters do
|
4
|
+
|
5
|
+
let(:test_class) { Class.new }
|
6
|
+
before { test_class.include described_class }
|
7
|
+
subject { test_class.new }
|
8
|
+
|
9
|
+
describe "#params" do
|
10
|
+
|
11
|
+
subject { test_class.new }
|
12
|
+
|
13
|
+
it "returns a hash" do
|
14
|
+
expect(subject.params).to be_kind_of Hash
|
15
|
+
end
|
16
|
+
|
17
|
+
end # describe #params
|
18
|
+
|
19
|
+
describe ".whitelist" do
|
20
|
+
|
21
|
+
it "is defined" do
|
22
|
+
expect(test_class).to respond_to :whitelist
|
23
|
+
expect { test_class.instance_eval "@whitelist = [:foo]" }
|
24
|
+
.to change { test_class.whitelist }
|
25
|
+
.to [:foo]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "returns empty array by default" do
|
29
|
+
expect(test_class.whitelist).to eq []
|
30
|
+
end
|
31
|
+
|
32
|
+
end # describe #whitelist
|
33
|
+
|
34
|
+
describe ".new" do
|
35
|
+
|
36
|
+
before { allow(test_class).to receive(:whitelist) { [:foo, :bar] } }
|
37
|
+
|
38
|
+
it "allows options" do
|
39
|
+
expect(test_class).to respond_to(:new).with(1).argument
|
40
|
+
end
|
41
|
+
|
42
|
+
it "makes params optional" do
|
43
|
+
expect(test_class).to respond_to(:new).with(0).argument
|
44
|
+
end
|
45
|
+
|
46
|
+
it "assings parameters from options" do
|
47
|
+
options = { foo: "foo" }
|
48
|
+
|
49
|
+
subject = test_class.new options
|
50
|
+
expect(subject.params).to eq options
|
51
|
+
end
|
52
|
+
|
53
|
+
it "symbolizes options keys at any level" do
|
54
|
+
source_options = { "foo" => "foo", "bar" => { "bar" => "baz" } }
|
55
|
+
target_options = { foo: "foo", bar: { bar: "baz" } }
|
56
|
+
|
57
|
+
subject = test_class.new(source_options)
|
58
|
+
expect(subject.params).to eq target_options
|
59
|
+
end
|
60
|
+
|
61
|
+
it "filters options" do
|
62
|
+
source_options = { foo: "foo", baz: "baz" }
|
63
|
+
target_options = { foo: "foo" }
|
64
|
+
|
65
|
+
subject = test_class.new(source_options)
|
66
|
+
expect(subject.params).to eq target_options
|
67
|
+
end
|
68
|
+
|
69
|
+
end # describe .new
|
70
|
+
|
71
|
+
end # describe ServiceObjects::Helpers::Whitelist
|