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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.metrics +1 -0
- data/.travis.yml +9 -1
- data/.yardopts +1 -1
- data/Gemfile +1 -1
- data/Guardfile +29 -8
- data/LICENSE +1 -1
- data/README.md +179 -342
- data/Rakefile +3 -3
- data/config/metrics/churn.yml +1 -1
- data/config/metrics/flay.yml +1 -1
- data/config/metrics/metric_fu.yml +1 -0
- data/config/metrics/rubocop.yml +4 -4
- data/config/metrics/simplecov.yml +1 -1
- data/lib/service_objects.rb +6 -9
- data/lib/service_objects/base.rb +190 -17
- data/lib/service_objects/listener.rb +21 -75
- data/lib/service_objects/message.rb +15 -96
- data/lib/service_objects/version.rb +1 -1
- data/service_objects.gemspec +11 -9
- data/spec/lib/base_spec.rb +247 -0
- data/spec/lib/listener_spec.rb +96 -0
- data/spec/lib/message_spec.rb +48 -0
- data/spec/spec_helper.rb +8 -6
- metadata +56 -93
- data/bin/service +0 -17
- data/config/metrics/pippi.yml +0 -3
- data/lib/service_objects/cli.rb +0 -117
- data/lib/service_objects/cli/locale.erb +0 -20
- data/lib/service_objects/cli/service.erb +0 -125
- data/lib/service_objects/cli/spec.erb +0 -87
- data/lib/service_objects/helpers.rb +0 -17
- data/lib/service_objects/helpers/dependable.rb +0 -63
- data/lib/service_objects/helpers/exceptions.rb +0 -64
- data/lib/service_objects/helpers/messages.rb +0 -95
- data/lib/service_objects/helpers/parameterized.rb +0 -85
- data/lib/service_objects/helpers/parameters.rb +0 -71
- data/lib/service_objects/helpers/validations.rb +0 -54
- data/lib/service_objects/invalid.rb +0 -55
- data/lib/service_objects/null.rb +0 -26
- data/lib/service_objects/parsers.rb +0 -13
- data/lib/service_objects/parsers/dependency.rb +0 -69
- data/lib/service_objects/parsers/notification.rb +0 -85
- data/lib/service_objects/rspec.rb +0 -75
- data/lib/service_objects/utils/normal_hash.rb +0 -34
- data/spec/tests/base_spec.rb +0 -43
- data/spec/tests/bin/service_spec.rb +0 -18
- data/spec/tests/cli_spec.rb +0 -179
- data/spec/tests/helpers/dependable_spec.rb +0 -77
- data/spec/tests/helpers/exceptions_spec.rb +0 -112
- data/spec/tests/helpers/messages_spec.rb +0 -64
- data/spec/tests/helpers/parameterized_spec.rb +0 -136
- data/spec/tests/helpers/parameters_spec.rb +0 -71
- data/spec/tests/helpers/validations_spec.rb +0 -60
- data/spec/tests/invalid_spec.rb +0 -69
- data/spec/tests/listener_spec.rb +0 -73
- data/spec/tests/message_spec.rb +0 -191
- data/spec/tests/null_spec.rb +0 -17
- data/spec/tests/parsers/dependency_spec.rb +0 -29
- data/spec/tests/parsers/notification_spec.rb +0 -84
- data/spec/tests/rspec_spec.rb +0 -86
- data/spec/tests/utils/normal_hash_spec.rb +0 -16
@@ -1,87 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require "service_objects/rspec"
|
3
|
-
|
4
|
-
describe <%= project.type %>::<%= service.type %> do
|
5
|
-
|
6
|
-
# defines helpers and matcher for testing services:
|
7
|
-
#
|
8
|
-
# Helper arguments:
|
9
|
-
# * params ({} by default)
|
10
|
-
# * service
|
11
|
-
# * listener - it is subscribed for the service
|
12
|
-
#
|
13
|
-
# Helper methods:
|
14
|
-
# * service_double(*args) { |*args| ... }
|
15
|
-
#
|
16
|
-
# Matchers:
|
17
|
-
# * correspond_to(hash)
|
18
|
-
# * be_notified_on(notification, *args)
|
19
|
-
#
|
20
|
-
include ServiceObjects::RSpec
|
21
|
-
<% dependencies.each do |item| -%>
|
22
|
-
|
23
|
-
# describe "#<%= item.name %>" do
|
24
|
-
|
25
|
-
# it "is set to <%= item.type %>" do
|
26
|
-
# expect(subject.<%= item.name %>).to eq <%= item.type %>
|
27
|
-
# end
|
28
|
-
|
29
|
-
# it "is injectable" do
|
30
|
-
# injection = double
|
31
|
-
# expect { subject.<%= item.name %> = injection)
|
32
|
-
# .to change { subject.<%= item.name %> }.to injection
|
33
|
-
# end
|
34
|
-
|
35
|
-
# end # describe #<%= item.name %>
|
36
|
-
<% end -%>
|
37
|
-
|
38
|
-
describe "#run" do
|
39
|
-
<% dependencies.each do |item| -%>
|
40
|
-
|
41
|
-
# shared_context "#<%= item.name %> publishes @todo" do |options|
|
42
|
-
|
43
|
-
# before do
|
44
|
-
# injection = service_double(@todo) { publish @todo }
|
45
|
-
# inject :<%= item.name %>, with: options, constucts: injection
|
46
|
-
# end
|
47
|
-
|
48
|
-
# end # shared_context
|
49
|
-
<% end -%>
|
50
|
-
<% notifications.each do |item| -%>
|
51
|
-
|
52
|
-
# shared_examples "@todo" do
|
53
|
-
|
54
|
-
# it "[@todo]" do
|
55
|
-
# expect { service.run }
|
56
|
-
# .to change { @todo }
|
57
|
-
# .from(@todo)
|
58
|
-
# .to(@todo)
|
59
|
-
# end
|
60
|
-
|
61
|
-
# it "publishes :<%= item.name %>" do
|
62
|
-
# expect(listener)
|
63
|
-
# .to receive(:<%= item.name %>) do |<%= item.args.join(", ") %>|
|
64
|
-
<% item.args.each do |arg| -%>
|
65
|
-
# expect(<%= arg %>).to eq @todo
|
66
|
-
<% end -%>
|
67
|
-
# end
|
68
|
-
# service.run
|
69
|
-
# end
|
70
|
-
|
71
|
-
# end
|
72
|
-
<% end -%>
|
73
|
-
|
74
|
-
# context "when @todo" do
|
75
|
-
|
76
|
-
# before { params.merge! "@todo" => @todo }
|
77
|
-
<% dependencies.each do |item| -%>
|
78
|
-
# include_context "#<%= item.name %> publishes @todo", @todo
|
79
|
-
<% end -%>
|
80
|
-
|
81
|
-
# it_behaves_like "@todo"
|
82
|
-
|
83
|
-
# end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
end # describe <%= project.type %>::<%= service.type %>
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module ServiceObjects
|
4
|
-
|
5
|
-
# Contains helper objecs for the base service
|
6
|
-
module Helpers
|
7
|
-
|
8
|
-
require_relative "helpers/messages"
|
9
|
-
require_relative "helpers/validations"
|
10
|
-
require_relative "helpers/exceptions"
|
11
|
-
require_relative "helpers/dependable"
|
12
|
-
require_relative "helpers/parameters"
|
13
|
-
require_relative "helpers/parameterized"
|
14
|
-
|
15
|
-
end # module Helpers
|
16
|
-
|
17
|
-
end # module ServiceObjects
|
@@ -1,63 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module ServiceObjects
|
4
|
-
|
5
|
-
module Helpers
|
6
|
-
|
7
|
-
# Features for service dependencies declaration
|
8
|
-
#
|
9
|
-
# @note
|
10
|
-
# A target class should be **extended** by the module
|
11
|
-
module Dependable
|
12
|
-
|
13
|
-
# Declares the dependency setter and getter
|
14
|
-
#
|
15
|
-
# @example
|
16
|
-
# class AddFoo
|
17
|
-
# extend ServiceObjects::Helpers::Dependable
|
18
|
-
#
|
19
|
-
# depends_on :get_item, default: GetItem
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# service = AddFoo.new
|
23
|
-
# service.get_item
|
24
|
-
# # => GetItem
|
25
|
-
#
|
26
|
-
# # Depencency injection
|
27
|
-
# service.get_item = FindItem
|
28
|
-
# service.get_item
|
29
|
-
# # => FindItem
|
30
|
-
#
|
31
|
-
# # Resetting to default
|
32
|
-
# service.get_item = nil
|
33
|
-
# service.get_item
|
34
|
-
# # => GetItem
|
35
|
-
#
|
36
|
-
# @example Set to NULL Object by default
|
37
|
-
# class AddFoo
|
38
|
-
# extend ServiceObjects::Helpers::Dependable
|
39
|
-
#
|
40
|
-
# depends_on :get_item
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# service = AddFoo.new
|
44
|
-
# service.get_item
|
45
|
-
# # => <ServiceObjects::NULL>
|
46
|
-
#
|
47
|
-
# @param [#to_sym] name
|
48
|
-
# the name for the dependency
|
49
|
-
# @param [BaseObject] default (ServiceObjects::NULL)
|
50
|
-
# default implementation for the dependency
|
51
|
-
#
|
52
|
-
# @return [:depends_on]
|
53
|
-
# the name of the method
|
54
|
-
def depends_on(name, default: NULL)
|
55
|
-
attr_writer name
|
56
|
-
define_method(name) { instance_eval("@#{ name }") || default }
|
57
|
-
end
|
58
|
-
|
59
|
-
end # Dependable
|
60
|
-
|
61
|
-
end # module Helpers
|
62
|
-
|
63
|
-
end # module ServiceObjects
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module ServiceObjects
|
4
|
-
|
5
|
-
module Helpers
|
6
|
-
|
7
|
-
# Features for escaping from runtime errors
|
8
|
-
#
|
9
|
-
# @note
|
10
|
-
# A target class should **include** the module
|
11
|
-
module Exceptions
|
12
|
-
|
13
|
-
# Re-raises standard errors as <tt>ServiceObjects::Invalid</tt>
|
14
|
-
#
|
15
|
-
# Mutates the current object by adding error messages
|
16
|
-
#
|
17
|
-
# @example
|
18
|
-
# class MyClass
|
19
|
-
# includes ServiceObjects::Helpers::Exceptions
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# begin
|
23
|
-
# MyClass.new.escape { fail StandardError.new "foo" }
|
24
|
-
# rescue => err
|
25
|
-
# puts err.class.name
|
26
|
-
# puts messages
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# # => ServiceObjects::Invalid
|
30
|
-
# # => [<ServiceObject::Message type="error" text="foo" ...>]
|
31
|
-
#
|
32
|
-
# @yield the block
|
33
|
-
#
|
34
|
-
# @raise [ServiceObjects::Invalid]
|
35
|
-
# if the block raises +StandardError+
|
36
|
-
#
|
37
|
-
# @return [Object] the value returned by the block
|
38
|
-
def escape
|
39
|
-
yield if block_given?
|
40
|
-
rescue => error
|
41
|
-
collect_messages_from error
|
42
|
-
raise Invalid.new(self)
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
# @!parse include ServiceObjects::Helpers::Messages
|
48
|
-
def self.included(klass)
|
49
|
-
klass.include Messages
|
50
|
-
end
|
51
|
-
|
52
|
-
def collect_messages_from(error)
|
53
|
-
if error.is_a? Invalid
|
54
|
-
messages.concat(error.messages) if error.object != self
|
55
|
-
else
|
56
|
-
add_message type: "error", text: error.message
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
end # module Exceptions
|
61
|
-
|
62
|
-
end # module Helpers
|
63
|
-
|
64
|
-
end # module ServiceObjects
|
@@ -1,95 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require "extlib"
|
3
|
-
|
4
|
-
module ServiceObjects
|
5
|
-
|
6
|
-
module Helpers
|
7
|
-
|
8
|
-
# Features for collecting service messages
|
9
|
-
#
|
10
|
-
# @note
|
11
|
-
# A target class should **include** the module
|
12
|
-
module Messages
|
13
|
-
|
14
|
-
# Translates the text in the current scope with given options
|
15
|
-
#
|
16
|
-
# The method uses I18n.t library method.
|
17
|
-
#
|
18
|
-
# @example Returns a translation for symbolic argument
|
19
|
-
# class Test
|
20
|
-
# include ServiceObjects::Helpers::Messages
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# MyClass.new.translate :item
|
24
|
-
# # => translation not found: en.activemodel.messages.models.test.item
|
25
|
-
#
|
26
|
-
# @example Converts non-symbolic argument to a string.
|
27
|
-
# class Test
|
28
|
-
# include ServiceObjects::Helpers::Messages
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# MyClass.new.translate 1
|
32
|
-
# # => "1"
|
33
|
-
#
|
34
|
-
# @param [#to_s] text
|
35
|
-
# @param [Hash] options ({})
|
36
|
-
#
|
37
|
-
# @return [String]
|
38
|
-
def translate(text, options = {})
|
39
|
-
return text.to_s unless text.is_a? Symbol
|
40
|
-
I18n.t text, Utils::NormalHash.from(options).merge(scope: __scope__)
|
41
|
-
end
|
42
|
-
|
43
|
-
# A list of object messages
|
44
|
-
#
|
45
|
-
# @return [Array<ServiceObjects::Message>]
|
46
|
-
def messages
|
47
|
-
@messages ||= []
|
48
|
-
end
|
49
|
-
|
50
|
-
# Translates the text and adds a new message to the list of {#messages}
|
51
|
-
#
|
52
|
-
# @example
|
53
|
-
# class MyClass
|
54
|
-
# include ServiceObjects::Helpers::Messages
|
55
|
-
# end
|
56
|
-
#
|
57
|
-
# object = MyClass.new
|
58
|
-
# object.add_message type: "foo", text: "bar", priority: 2.5
|
59
|
-
# object.messages
|
60
|
-
# # => [<ServiceObjects::Message type="foo" text="bar" priority=2.5>]
|
61
|
-
#
|
62
|
-
# @param [Hash] options
|
63
|
-
# the list of options for the message and its translation
|
64
|
-
#
|
65
|
-
# @option options [#to_s] :text
|
66
|
-
# the text of a new message to be translated via {#translate} method
|
67
|
-
# @option options [#to_s] :type
|
68
|
-
# the type of a new message
|
69
|
-
# @option options [#to_f] :priority
|
70
|
-
# optional priority fo a new message
|
71
|
-
#
|
72
|
-
# @return [Array<ServiceObjects::Message>] The updated {#messages}
|
73
|
-
def add_message(options)
|
74
|
-
params = Utils::NormalHash.from(options)
|
75
|
-
type = params.delete :type
|
76
|
-
priority = params.delete :priority
|
77
|
-
text = translate params.delete(:text), params
|
78
|
-
messages << Message.new(text: text, type: type, priority: priority)
|
79
|
-
end
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def __scope__
|
84
|
-
@__scope__ ||= [:activemodel, :messages, :models, __class_name__.to_sym]
|
85
|
-
end
|
86
|
-
|
87
|
-
def __class_name__
|
88
|
-
self.class.name.split("::").map(&:snake_case).join("/")
|
89
|
-
end
|
90
|
-
|
91
|
-
end # module Messages
|
92
|
-
|
93
|
-
end # module Helpers
|
94
|
-
|
95
|
-
end # module Services
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module ServiceObjects
|
4
|
-
|
5
|
-
module Helpers
|
6
|
-
|
7
|
-
# Features for service parameters declaration
|
8
|
-
#
|
9
|
-
# @note
|
10
|
-
# A target class should be **extended** by the module
|
11
|
-
module Parameterized
|
12
|
-
|
13
|
-
# Whitelists {.new} options assigned to params
|
14
|
-
#
|
15
|
-
# Mutates the current class by adding the corresponding attribute
|
16
|
-
# for every parameter.
|
17
|
-
#
|
18
|
-
# @example Whitelists options
|
19
|
-
# class AddFoo
|
20
|
-
# extend ServiceObjects::Helpers::Parameterized
|
21
|
-
#
|
22
|
-
# allows_params :foo
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# service = AddFoo.new foo: "foo", bar: "baz"
|
26
|
-
# service.params # => { foo: "foo" }
|
27
|
-
#
|
28
|
-
# @example Adds attributes as aliases to corresponding params
|
29
|
-
# class AddFoo
|
30
|
-
# extend ServiceObjects::Helpers::Parameterized
|
31
|
-
#
|
32
|
-
# allows_params :foo
|
33
|
-
# end
|
34
|
-
#
|
35
|
-
# service = AddFoo.new foo: "foo"
|
36
|
-
# service.foo # => "foo"
|
37
|
-
#
|
38
|
-
# service.params[:foo] = "bar"
|
39
|
-
# service.foo # => "bar"
|
40
|
-
#
|
41
|
-
# service.foo = "baz"
|
42
|
-
# service.foo # => "baz"
|
43
|
-
# service.params[:foo] # => "baz"
|
44
|
-
#
|
45
|
-
# @param [Array<#to_sym>] list
|
46
|
-
#
|
47
|
-
# @return [Array<Symbol>]
|
48
|
-
# the list of arguments
|
49
|
-
def allows_params(*list)
|
50
|
-
@whitelist = list.flatten.map(&:to_sym).freeze
|
51
|
-
__attr_params__
|
52
|
-
|
53
|
-
whitelist
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
# @!parse include ServiceObjects::Helpers::Parameters
|
59
|
-
def self.extended(klass)
|
60
|
-
klass.include Parameters
|
61
|
-
super
|
62
|
-
end
|
63
|
-
|
64
|
-
def __attr_params__
|
65
|
-
whitelist.each(&method(:__attr_param_accessor__))
|
66
|
-
end
|
67
|
-
|
68
|
-
def __attr_param_accessor__(name)
|
69
|
-
__attr_param_reader__ name
|
70
|
-
__attr_param_writer__ name
|
71
|
-
end
|
72
|
-
|
73
|
-
def __attr_param_reader__(name)
|
74
|
-
define_method(name) { params[name] }
|
75
|
-
end
|
76
|
-
|
77
|
-
def __attr_param_writer__(name)
|
78
|
-
define_method("#{ name }=") { |value| params[name] = value }
|
79
|
-
end
|
80
|
-
|
81
|
-
end # module Parameters
|
82
|
-
|
83
|
-
end # module Helpers
|
84
|
-
|
85
|
-
end # module ServiceObjects
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module ServiceObjects
|
4
|
-
|
5
|
-
module Helpers
|
6
|
-
|
7
|
-
# Features for whitelisting service options
|
8
|
-
#
|
9
|
-
# @note
|
10
|
-
# A target class should **include** the module
|
11
|
-
module Parameters
|
12
|
-
|
13
|
-
# @!scope class
|
14
|
-
# @!attribute [r] whitelist
|
15
|
-
# Returns the list of allowed parameters
|
16
|
-
#
|
17
|
-
# @return [Array<Symbol>]
|
18
|
-
|
19
|
-
# @!attribute [r] params
|
20
|
-
# Service object parameters
|
21
|
-
#
|
22
|
-
# @return [Hash]
|
23
|
-
attr_reader :params
|
24
|
-
|
25
|
-
# Service object initializer
|
26
|
-
#
|
27
|
-
# @example Normalizing options
|
28
|
-
# class AddFoo
|
29
|
-
# include ServiceObjects::Helpers::Parameters
|
30
|
-
#
|
31
|
-
# @whitelist = [:foo]
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# service = AddFoo.new("foo" => { "bar" => "baz" })
|
35
|
-
# service.params # => { foo: { bar: "baz" } }
|
36
|
-
#
|
37
|
-
# @example Whitelisting options
|
38
|
-
# class AddFoo
|
39
|
-
# include ServiceObjects::Helpers::Parameters
|
40
|
-
#
|
41
|
-
# @whitelist = [:foo]
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# service = AddFoo.new(foo: "bar", bar: "baz")
|
45
|
-
# service.params # => { foo: "bar" }
|
46
|
-
#
|
47
|
-
# @param [Hash] options
|
48
|
-
#
|
49
|
-
# @return [undefined]
|
50
|
-
def initialize(options = {})
|
51
|
-
@params = Utils::NormalHash.from(options).slice(*__whitelist__)
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def self.included(klass)
|
57
|
-
klass
|
58
|
-
.singleton_class
|
59
|
-
.send(:define_method, :whitelist) { @whitelist ||= [] }
|
60
|
-
super
|
61
|
-
end
|
62
|
-
|
63
|
-
def __whitelist__
|
64
|
-
@whitelist ||= self.class.send :whitelist
|
65
|
-
end
|
66
|
-
|
67
|
-
end # module Parameters
|
68
|
-
|
69
|
-
end # module Helpers
|
70
|
-
|
71
|
-
end # module ServiceObjects
|