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,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