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
@@ -1,54 +0,0 @@
1
- # encoding: utf-8
2
- require "active_model"
3
-
4
- module ServiceObjects
5
-
6
- module Helpers
7
-
8
- # Features for service attributes validation
9
- #
10
- # @note
11
- # A target class should **include** the module
12
- #
13
- # @see http://apidock.com/rails/v4.1.8/ActiveModel/Validations
14
- # ActiveModel::Validations
15
- module Validations
16
-
17
- # @!method valid?
18
- # Runs validations and checks if the object is valid
19
- # @return [Boolean]
20
-
21
- # Raises <tt>ServiceObjects::Invalid</tt> when {#valid?} method fails
22
- #
23
- # Mutates the current object by populating its messages
24
- # with errors, added by {#valid?}
25
- #
26
- # @raise [ServiceObjects::Invalid]
27
- # when a validation fails
28
- #
29
- # @return [self] (not changed)
30
- # when a validation passes
31
- def validate!
32
- return self if valid?
33
- __errors__.each { |text| add_message text: text, type: "error" }
34
- fail Invalid.new(self)
35
- end
36
-
37
- private
38
-
39
- # @!parse include ServiceObjects::Helpers::Messages
40
- # @!parse include ActiveModel::Validations
41
- def self.included(klass)
42
- klass.include ActiveModel::Validations, Messages
43
- super
44
- end
45
-
46
- def __errors__
47
- errors.messages.values.flatten
48
- end
49
-
50
- end # module Validations
51
-
52
- end # module Helpers
53
-
54
- end # module ServiceObjects
@@ -1,55 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module ServiceObjects
4
-
5
- # The exception to be risen by invalid services
6
- #
7
- # @example
8
- # object = ServiceObjects::Base.new
9
- # fail ServiceObjects::Invalid.new object
10
- class Invalid < ::RuntimeError
11
-
12
- # @!scope class
13
- # @!method new(object)
14
- #
15
- # Constructs the exception for given service object
16
- #
17
- # @example (see ServiceObjects::Invalid)
18
- #
19
- # @param [#messages] object
20
- #
21
- # @return [ServiceObjects::Invalid]
22
- def initialize(object)
23
- @object = object
24
- validate
25
- end
26
-
27
- # @!attribute [r] object
28
- # Invalid service object
29
- #
30
- # @return [#messages]
31
- attr_reader :object
32
-
33
- # The array of messages from the invalid {#object}
34
- #
35
- # @return [Array<ServiceObjects::Message>]
36
- def messages
37
- Array(object.messages).flatten
38
- end
39
-
40
- private
41
-
42
- # Checks if the {#object} respond to {#messages}
43
- #
44
- # @raise [TypeError]
45
- # when the validation fails
46
- #
47
- # @return [undefined]
48
- def validate
49
- return if object.respond_to? :messages
50
- fail TypeError.new "#{ object.inspect } doesn't respond to #messages"
51
- end
52
-
53
- end # class Invalid
54
-
55
- end # module ServiceObjects
@@ -1,26 +0,0 @@
1
- # encoding: utf-8
2
- require "naught"
3
-
4
- module ServiceObjects #:nodoc:
5
-
6
- # Implements Null Object pattern
7
- #
8
- # @note
9
- # The constant is a singleton black hole object that returns
10
- # itself to any method call
11
- #
12
- # @example
13
- # ServiceObjects::NULL.respond_to? :arbitrary_method
14
- # # => true
15
- #
16
- # ServiceObjects::NULL.arbitrary_method
17
- # # => ServiceObjects::NULL
18
- #
19
- # @see https://github.com/avdi/naught
20
- # documentation for the 'naught' gem by Avdi Grimm
21
- NULL = Naught.build do |config|
22
- config.black_hole
23
- config.singleton
24
- end.instance
25
-
26
- end # module ServiceObjects
@@ -1,13 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module ServiceObjects
4
-
5
- # Collection of CLI arguments parsers
6
- module Parsers
7
-
8
- require_relative "parsers/dependency"
9
- require_relative "parsers/notification"
10
-
11
- end # module ServiceObjects
12
-
13
- end # module Parsers
@@ -1,69 +0,0 @@
1
- # encoding: utf-8
2
- require "hexx-cli"
3
-
4
- module ServiceObjects
5
-
6
- module Parsers
7
-
8
- # Parses and decorates a string, describing a notification
9
- #
10
- # @example
11
- # result = ServiceObjects::Parsers::Dependency.new "add_item{get_item}"
12
- # result.name # => add_item
13
- # result.type # => GetItem
14
- # result.listener # => AddItemListener
15
- class Dependency
16
-
17
- # @!scope class
18
- # @!method new(source)
19
- # Constructs the object from source
20
- #
21
- # @param [#to_s] source
22
- #
23
- # @return [Hexx::Services::Parsers::Dependency]
24
- def initialize(source)
25
- @source = source.to_s
26
- end
27
-
28
- # The name for the dependency default implementation
29
- #
30
- # @return [String]
31
- def name
32
- @name ||= injector.item
33
- end
34
-
35
- # The type for the dependency default implementation
36
- #
37
- # @return [String]
38
- def type
39
- @type ||= injection.type
40
- end
41
-
42
- # The listener name for the dependency
43
- #
44
- # @return [String]
45
- def listener
46
- @listener ||= "#{ injector.const }Listener"
47
- end
48
-
49
- private
50
-
51
- attr_reader :source
52
-
53
- def matcher
54
- @matcher ||= source.match(/^(.+){(.+)}$/)
55
- end
56
-
57
- def injector
58
- @injector ||= Hexx::CLI::Name.new matcher[1]
59
- end
60
-
61
- def injection
62
- @injection ||= Hexx::CLI::Name.new matcher[2]
63
- end
64
-
65
- end # class Dependency
66
-
67
- end # module Parsers
68
-
69
- end # module ServiceObjects
@@ -1,85 +0,0 @@
1
- # encoding: utf-8
2
- require "extlib"
3
-
4
- module ServiceObjects
5
-
6
- module Parsers
7
-
8
- # Parses and decorates a string, describing a notification
9
- #
10
- # @example
11
- # result = ServiceObjects::Parsers::Notification.new "FOund:iTem:messages"
12
- # result.name # => found
13
- # result.arguments # => ["item", "messages"]
14
- # result.non_messages # => ["item"]
15
- # result.error? # => false
16
- # result.publish_messages? # => true
17
- class Notification
18
-
19
- # @!scope class
20
- # @!method new(source)
21
- # Initializes the object from source string
22
- #
23
- # @param [#to_s] source
24
- #
25
- # @return [ServiceObjects::Parsers::Notification]
26
- def initialize(source)
27
- @source = source.to_s
28
- end
29
-
30
- # The name for the parsed value
31
- # @return [String]
32
- def name
33
- @name ||= list.first
34
- end
35
-
36
- # The type of exception to be raised and catched by service object
37
- # @return [String]
38
- def exception
39
- @exception ||= name.camel_case
40
- end
41
-
42
- # The list of published values
43
- # @return [Array<String>]
44
- def args
45
- @args ||= Array(list[1..-1])
46
- end
47
-
48
- # The list of pulished values except for messages
49
- # @return [Array<String>]
50
- def non_messages
51
- @non_messages ||= args.reject { |item| item == "messages" }
52
- end
53
-
54
- # Checks whether a notification reports an error
55
- # @return [Boolean]
56
- def error?
57
- name == "error"
58
- end
59
-
60
- # Checks whether a notification publishes messages
61
- # @return [Boolean]
62
- def publish_messages?
63
- args.include? "messages"
64
- end
65
-
66
- # Returns value to order notifications by
67
- # @return [0] if a notification is successful
68
- # @return [1] if a notification is an error
69
- def order
70
- @order = error? ? 1 : 0
71
- end
72
-
73
- private
74
-
75
- attr_reader :source
76
-
77
- def list
78
- @list ||= source.scan(/\w+/).map(&:snake_case)
79
- end
80
-
81
- end # module ServiceObjects
82
-
83
- end # module Parsers
84
-
85
- end # class Notification
@@ -1,75 +0,0 @@
1
- # encoding: utf-8
2
- require "rspec/mocks"
3
-
4
- module ServiceObjects
5
-
6
- # Collection of helpers and matchers for testing services
7
- #
8
- # @example
9
- # require "service_objects/rspec"
10
- # describe MyService do
11
- # include ServiceObjects::RSpec
12
- # end
13
- module RSpec
14
- include ::RSpec::Mocks::ExampleMethods
15
-
16
- # Params to be given to service object constructor
17
- #
18
- # @return [Hash]
19
- def params
20
- @params ||= {}
21
- end
22
-
23
- # The service object of described_class, that subscribed the listener
24
- #
25
- # @return [ServiceObjects::Base]
26
- def service
27
- @service ||= described_class.new(params).subscribe(listener)
28
- end
29
-
30
- # The spy object to listen a service's notifications
31
- #
32
- # @return [::RSpec::Mocks::Double]
33
- def listener
34
- spy
35
- end
36
-
37
- # Makes given dependency to construct object when called with params
38
- #
39
- # @example
40
- # before { inject(:get_item, with: { name: :foo }, constructs: foo) }
41
- # service.get_item.new(name: :foo) # => foo
42
- #
43
- # @return [undefined]
44
- def inject(dependency, with: {}, constructs: service_double)
45
- klass = Class.new ServiceObjects::Base
46
- allow(klass).to receive(:new).with(with).and_return constructs
47
- allow(service).to receive(dependency).and_return klass
48
- end
49
-
50
- # Mock for another services, the service under test depends from
51
- #
52
- # The block contains the code to be executed on service #run.
53
- #
54
- # @example
55
- # let(:another_service) { service_double(:foo) { |name| publish name } }
56
- # another_service.run
57
- # # another_service sends :foo to its listeners
58
- #
59
- # @param [Array<Object>] args
60
- # the list of arguments for the block
61
- # @param [Proc] block
62
- # the block to be yielded by #run method
63
- #
64
- # @return [ServiceObjects::Base]
65
- def service_double(*args, &block)
66
- object = ServiceObjects::Base.new
67
- allow(object).to receive(:run) do
68
- object.instance_exec(*args, &block) if block_given?
69
- end
70
- object
71
- end
72
-
73
- end
74
-
75
- end # module ServiceObjects
@@ -1,34 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module ServiceObjects
4
-
5
- # Utilitites for ServiceObjects module
6
- module Utils
7
-
8
- # Constructor of hash with keys, symbolized at any level
9
- #
10
- # @example
11
- # NormalHash.from { "foo" => "bar", "bar" => { "baz", "bar" => "baz" } }
12
- # # => { foo: "baz", bar: { "baz", bar: "baz" } }
13
- #
14
- # @api private
15
- module NormalHash
16
-
17
- # Recursively symbolizes keys of hash at any level
18
- #
19
- # @param [Hash] hash
20
- #
21
- # @return [Hash]
22
- def self.from(hash)
23
- return {} unless hash.is_a? Hash
24
-
25
- hash.inject({}) do |out, (key, val)|
26
- out.merge(key.to_sym => (val.is_a?(Hash) ? from(val) : val))
27
- end
28
- end
29
-
30
- end # class NormalHash
31
-
32
- end # module Utils
33
-
34
- end # module ServiceObjects
@@ -1,43 +0,0 @@
1
- # encoding: utf-8
2
-
3
- describe ServiceObjects::Base do
4
-
5
- let(:publisher) { Wisper::Publisher }
6
- let(:helpers) { ServiceObjects::Helpers }
7
-
8
- it "is Dependable" do
9
- expect(described_class).to be_kind_of helpers::Dependable
10
- end
11
-
12
- it "is Parameterized" do
13
- expect(described_class).to be_kind_of helpers::Parameterized
14
- end
15
-
16
- it "includes Messages helper" do
17
- expect(described_class).to include helpers::Messages
18
- end
19
-
20
- it "includes Parameters helper" do
21
- expect(described_class).to include helpers::Parameters
22
- end
23
-
24
- it "includes Validations helper" do
25
- expect(described_class).to include helpers::Validations
26
- end
27
-
28
- it "includes Exceptions helper" do
29
- expect(described_class).to include helpers::Exceptions
30
- end
31
-
32
- it "includes Wisper::Publisher" do
33
- expect(described_class).to include publisher
34
- end
35
-
36
- describe "#run" do
37
-
38
- it "is defined" do
39
- expect(subject).to respond_to(:run).with(0).arguments
40
- end
41
- end
42
-
43
- end # describe ServiceObjects::Base