simple_service 1.0.2 → 1.2.5
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 +4 -4
- data/.gitignore +1 -0
- data/README.md +17 -10
- data/example/hello_world.rb +3 -4
- data/example/nested_organizer.rb +29 -0
- data/example/nested_services.rb +29 -0
- data/example/override_organizer_call_method.rb +39 -0
- data/lib/simple_service/command.rb +10 -30
- data/lib/simple_service/commands/validates_commands_not_empty.rb +16 -0
- data/lib/simple_service/commands/validates_commands_properly_inherit.rb +24 -0
- data/lib/simple_service/commands/validates_expected_keys.rb +19 -0
- data/lib/simple_service/ensure_organizer_is_valid.rb +21 -0
- data/lib/simple_service/exceptions.rb +1 -1
- data/lib/simple_service/organizer.rb +42 -11
- data/lib/simple_service/service_base.rb +37 -6
- data/lib/simple_service/version.rb +1 -1
- data/lib/simple_service.rb +5 -3
- data/spec/lib/command_spec.rb +19 -12
- data/spec/lib/commands/validates_commands_not_empty_spec.rb +28 -0
- data/spec/lib/commands/validates_commands_properly_inherit_spec.rb +34 -0
- data/spec/lib/commands/validates_expected_keys_spec.rb +60 -0
- data/spec/lib/ensure_organizer_is_valid_spec.rb +17 -0
- data/spec/lib/organizer_spec.rb +10 -10
- metadata +33 -21
- data/lib/simple_service/argument_validator.rb +0 -57
- data/spec/lib/argument_validator_spec.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62127eaaf7ab561f13e676804054b5f6c5badb6b
|
4
|
+
data.tar.gz: 3c707fa3145d309d2ffe402a9083136cb464d0ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 966251837c81145882975a90ceb9ad88a97e9bcd39d182216e1fc4b0e425f8167d835a87df0bb3c3d43ab83624633a050334b2f46fb7cf35273d97815dd4e7d9
|
7
|
+
data.tar.gz: 31a500a462b2b4d98b7a49a6470ad93fe977b512744d8861b2d3e1d03536295a002060ab5c4b46ec7b2b10e7b533595bf5f0591f07ac2aeb619540adbae5327a
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -14,17 +14,18 @@ objects can be reused in multiple organizers minimizing code duplication.
|
|
14
14
|
When an organizer is instantiated a hash of arguments is passed in. This hash
|
15
15
|
is referred to as the context. The context hash is carried along throughout
|
16
16
|
the sequence of command executions and modified by each command. After a
|
17
|
-
successful run, the
|
17
|
+
successful run, the keys specified are returned. If keys are not specified, the
|
18
|
+
entire context hash is returned.
|
18
19
|
|
19
20
|
First, setup an Organizer class. An Organizer needs the following things defined:
|
20
21
|
|
21
22
|
* expects: keys that are required to be passed into initialize when an
|
22
23
|
instance of organizer is created. If not defined the organizer will
|
23
24
|
accept arbitrary arguments.
|
24
|
-
* returns: keys that will be returned when the organizer has
|
25
|
+
* returns: keys that will be returned when the organizer has called all of
|
25
26
|
its commands
|
26
|
-
* commands: classes that define all the steps that the organizer will
|
27
|
-
The organizer will
|
27
|
+
* commands: classes that define all the steps that the organizer will call.
|
28
|
+
The organizer will execute #call on each command in order and the context
|
28
29
|
hash is passed to each of these commands. Any keys within the context that
|
29
30
|
are modified will be merged back into the organizer and passed along to the
|
30
31
|
next command.
|
@@ -36,12 +37,12 @@ class ProcessSomethingComplex < SimpleService::Organizer
|
|
36
37
|
# leave out to accept any arguments/keys
|
37
38
|
expects :something, :another_thing
|
38
39
|
|
39
|
-
# optional - specifies which keys get returned after #
|
40
|
+
# optional - specifies which keys get returned after #call is executed on
|
40
41
|
# an organizer instance
|
41
42
|
returns :modified_thing
|
42
43
|
|
43
44
|
# what steps comprise this service
|
44
|
-
# #
|
45
|
+
# #call will be executed on an instance of each class in sequence
|
45
46
|
commands DoSomethingImportant, DoAnotherStep
|
46
47
|
|
47
48
|
end
|
@@ -66,7 +67,7 @@ class DoSomethingImportant < SimpleService::Command
|
|
66
67
|
# getters and setters are available for each key specified
|
67
68
|
# in expects and returns. If not using expects and returns
|
68
69
|
# simply interact with the context hash directly
|
69
|
-
def
|
70
|
+
def call
|
70
71
|
# uses getters and setters to modify the context
|
71
72
|
self.modified_something = self.something.to_i + 1
|
72
73
|
|
@@ -88,14 +89,14 @@ end
|
|
88
89
|
## Usage
|
89
90
|
|
90
91
|
Using the service is straight forward - just instantiate it, passing in the
|
91
|
-
intial context hash, and then call
|
92
|
+
intial context hash, and then call.
|
92
93
|
|
93
94
|
```ruby
|
94
95
|
starting_context = {
|
95
96
|
something: '1',
|
96
97
|
:another_thing: AnotherThing.new
|
97
98
|
}
|
98
|
-
modified_context = ProcessSomethingComplex.new(starting_context).
|
99
|
+
modified_context = ProcessSomethingComplex.new(starting_context).call
|
99
100
|
|
100
101
|
modified_context[:modified_thing] # => 2
|
101
102
|
```
|
@@ -104,6 +105,12 @@ If you are using this with a Rails app, placing top level services in
|
|
104
105
|
app/services/ and all commands in app/services/commands/ is recommended. If
|
105
106
|
not using rails, a similar structure would also be recommended.
|
106
107
|
|
108
|
+
For further examination of usage, here are a few examples:
|
109
|
+
|
110
|
+
* [hello world example](example/hello_world.rb)
|
111
|
+
* [nested services example](example/nested_services.rb)
|
112
|
+
* [override #call on the organizer](example/override_organizer_call_method.rb)
|
113
|
+
|
107
114
|
## Inspiration and Rationale
|
108
115
|
|
109
116
|
This gem is heavily inspired by two very nice gems:
|
@@ -113,7 +120,7 @@ This gem is heavily inspired by two very nice gems:
|
|
113
120
|
Mutations is a great gem, but lacks the concept of a top level organizer.
|
114
121
|
LightService brings in the notion of the organizer object, but doesn't create
|
115
122
|
instances of its action objects (what are referred to as commands here). Using
|
116
|
-
instances rather than class level
|
123
|
+
instances rather than class level #call definitions allows the use of private
|
117
124
|
methods within the command for more complex commands that still do a single thing.
|
118
125
|
|
119
126
|
The other goal of this gem is to do as little as possible above and beyond
|
data/example/hello_world.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'pry'
|
3
2
|
require 'simple_service'
|
4
3
|
|
5
4
|
class ConcatName < SimpleService::Command
|
6
5
|
expects :first_name, :last_name
|
7
6
|
returns :name
|
8
7
|
|
9
|
-
def
|
8
|
+
def call
|
10
9
|
self.name = "#{first_name} #{last_name}"
|
11
10
|
end
|
12
11
|
end
|
@@ -15,7 +14,7 @@ class CreateHelloString < SimpleService::Command
|
|
15
14
|
expects :name
|
16
15
|
returns :hello
|
17
16
|
|
18
|
-
def
|
17
|
+
def call
|
19
18
|
self.hello = "#{name}, say hello world!"
|
20
19
|
end
|
21
20
|
end
|
@@ -26,5 +25,5 @@ class SayHello < SimpleService::Organizer
|
|
26
25
|
commands ConcatName, CreateHelloString
|
27
26
|
end
|
28
27
|
|
29
|
-
result = SayHello.new(first_name: 'Ruby', last_name: 'Gem').
|
28
|
+
result = SayHello.new(first_name: 'Ruby', last_name: 'Gem').call
|
30
29
|
puts result[:hello]
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'simple_service'
|
3
|
+
|
4
|
+
class Increment < SimpleService::Command
|
5
|
+
expects :counter
|
6
|
+
returns :counter
|
7
|
+
|
8
|
+
def call
|
9
|
+
self.counter += 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class IncrementCounter < SimpleService::Organizer
|
14
|
+
expects :counter
|
15
|
+
returns :counter
|
16
|
+
commands Increment, Increment, Increment
|
17
|
+
end
|
18
|
+
|
19
|
+
class ReallyIncrementThatCounter < SimpleService::Organizer
|
20
|
+
expects :counter
|
21
|
+
returns :counter
|
22
|
+
commands IncrementCounter, IncrementCounter, IncrementCounter
|
23
|
+
end
|
24
|
+
|
25
|
+
result = IncrementCounter.new(counter: 0).call
|
26
|
+
puts "IncrementCounter: #{result[:counter]}"
|
27
|
+
|
28
|
+
result = ReallyIncrementThatCounter.new(counter: 0).call
|
29
|
+
puts "ReallyIncrementThatCounter: #{result[:counter]}"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'simple_service'
|
3
|
+
|
4
|
+
class Increment < SimpleService::Command
|
5
|
+
expects :counter
|
6
|
+
returns :counter
|
7
|
+
|
8
|
+
def execute
|
9
|
+
self.counter += 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class IncrementCounter < SimpleService::Organizer
|
14
|
+
expects :counter
|
15
|
+
returns :counter
|
16
|
+
commands Increment, Increment, Increment
|
17
|
+
end
|
18
|
+
|
19
|
+
class ReallyIncrementThatCounter < SimpleService::Organizer
|
20
|
+
expects :counter
|
21
|
+
returns :counter
|
22
|
+
commands IncrementCounter, IncrementCounter, IncrementCounter
|
23
|
+
end
|
24
|
+
|
25
|
+
result = IncrementCounter.new(counter: 0).execute
|
26
|
+
puts "IncrementCounter: #{result[:counter]}"
|
27
|
+
|
28
|
+
result = ReallyIncrementThatCounter.new(counter: 0).execute
|
29
|
+
puts "ReallyIncrementThatCounter: #{result[:counter]}"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'simple_service'
|
3
|
+
|
4
|
+
class ConcatAnotherName < SimpleService::Command
|
5
|
+
expects :first_name, :last_name
|
6
|
+
returns :name
|
7
|
+
|
8
|
+
def call
|
9
|
+
self.name = "#{first_name} #{last_name}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class CreateAnotherHelloString < SimpleService::Command
|
14
|
+
expects :name
|
15
|
+
returns :hello
|
16
|
+
|
17
|
+
def call
|
18
|
+
self.hello ||= ''
|
19
|
+
self.hello += "#{name}, say hello world!"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class SayHelloMultipleTimes < SimpleService::Organizer
|
24
|
+
expects :first_name, :last_name, :num_times
|
25
|
+
returns :hello
|
26
|
+
commands ConcatAnotherName, CreateAnotherHelloString
|
27
|
+
|
28
|
+
# overriding the #call method on the organizer allows
|
29
|
+
# you to do things like loop and call the service commands
|
30
|
+
# multiple times
|
31
|
+
def call
|
32
|
+
num_times.times do
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
result = SayHelloMultipleTimes.new(first_name: 'Ruby', last_name: 'Gem', num_times: 3).call
|
39
|
+
puts result[:hello]
|
@@ -8,40 +8,20 @@ module SimpleService
|
|
8
8
|
|
9
9
|
def initialize(context={})
|
10
10
|
@context = context
|
11
|
-
|
11
|
+
setup_call_chain
|
12
12
|
define_getters_and_setters
|
13
|
-
end
|
14
|
-
|
15
|
-
# execute is where the command's behavior is defined
|
16
|
-
# execute should be overriden by whatever class inherits from
|
17
|
-
# this class
|
18
|
-
def execute
|
19
|
-
error_msg = "#{self.class} - does not define an execute method"
|
20
|
-
raise SimpleService::ExecuteNotDefinedError , error_msg
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
13
|
|
25
|
-
|
26
|
-
|
14
|
+
unless skip_validation
|
15
|
+
ValidatesExpectedKeys.new(provided_keys: context.keys).call
|
16
|
+
end
|
27
17
|
end
|
28
18
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
self.context[key]
|
36
|
-
end
|
37
|
-
|
38
|
-
# setter
|
39
|
-
define_method "#{key}=" do |val|
|
40
|
-
self.context[key] = val
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
19
|
+
# call is where the command's behavior is defined
|
20
|
+
# call should be overriden by whatever class inherits from
|
21
|
+
# this class
|
22
|
+
def call
|
23
|
+
error_msg = "#{self.class} - does not define a call method"
|
24
|
+
raise SimpleService::CallNotDefinedError , error_msg
|
45
25
|
end
|
46
26
|
|
47
27
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SimpleService
|
2
|
+
class ValidatesCommandsNotEmpty < Command
|
3
|
+
|
4
|
+
expects :provided_commands
|
5
|
+
|
6
|
+
skip_validation true
|
7
|
+
|
8
|
+
def call
|
9
|
+
if provided_commands.nil? || provided_commands.empty?
|
10
|
+
error_msg = 'This Organizer class does not contain any command definitions'
|
11
|
+
raise SimpleService::OrganizerCommandsNotDefinedError, error_msg
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SimpleService
|
2
|
+
class ValidatesCommandsProperlyInherit < Command
|
3
|
+
|
4
|
+
expects :provided_commands
|
5
|
+
|
6
|
+
skip_validation true
|
7
|
+
|
8
|
+
def call
|
9
|
+
# valid commands inherit from Command and do not inherit from service
|
10
|
+
# reject all valid commands and anything left over is invalid
|
11
|
+
invalid_commands = provided_commands.to_a.reject do |command|
|
12
|
+
command.ancestors.include?(SimpleService::Command) ||
|
13
|
+
command.ancestors.include?(SimpleService::Organizer)
|
14
|
+
end
|
15
|
+
|
16
|
+
if invalid_commands.any?
|
17
|
+
error_msg = invalid_commands.join(', ') +
|
18
|
+
' - must inherit from SimpleService::Command'
|
19
|
+
raise SimpleService::CommandParentClassInvalidError, error_msg
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SimpleService
|
2
|
+
class ValidatesExpectedKeys < Command
|
3
|
+
|
4
|
+
expects :expected_keys, :provided_keys
|
5
|
+
|
6
|
+
skip_validation true
|
7
|
+
|
8
|
+
def call
|
9
|
+
arguments_not_included = expected_keys.to_a - provided_keys.to_a
|
10
|
+
|
11
|
+
if arguments_not_included.any?
|
12
|
+
error_msg = 'keys required by the organizer but not found in the context: ' +
|
13
|
+
arguments_not_included.join(', ')
|
14
|
+
raise ExpectedKeyError, error_msg
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SimpleService
|
2
|
+
class EnsureOrganizerIsValid < Organizer
|
3
|
+
|
4
|
+
expects :expected_keys, :provided_keys, :provided_commands
|
5
|
+
|
6
|
+
skip_validation true # false so as to not cause an infinite loop
|
7
|
+
|
8
|
+
commands ValidatesExpectedKeys,
|
9
|
+
ValidatesCommandsNotEmpty,
|
10
|
+
ValidatesCommandsProperlyInherit
|
11
|
+
|
12
|
+
def call
|
13
|
+
super
|
14
|
+
|
15
|
+
# dont return the keys within this internal service
|
16
|
+
# so we dont pollute external service objects
|
17
|
+
context.select { |k,v| !expects.include?(k) }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -3,6 +3,6 @@ module SimpleService
|
|
3
3
|
class OrganizerCommandsNotDefinedError < StandardError; end;
|
4
4
|
class CommandParentClassInvalidError < StandardError; end;
|
5
5
|
class ExpectedKeyError < StandardError; end;
|
6
|
-
class
|
6
|
+
class CallNotDefinedError < StandardError; end;
|
7
7
|
class ReturnKeyError < StandardError; end;
|
8
8
|
end
|
@@ -9,14 +9,8 @@ module SimpleService
|
|
9
9
|
def initialize(context={})
|
10
10
|
@context = context
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
expects: expects,
|
15
|
-
returns: returns,
|
16
|
-
commands: commands
|
17
|
-
).execute
|
18
|
-
|
19
|
-
setup_execute_chain
|
12
|
+
setup_call_chain
|
13
|
+
define_getters_and_setters
|
20
14
|
end
|
21
15
|
|
22
16
|
def self.commands(*args)
|
@@ -27,12 +21,49 @@ module SimpleService
|
|
27
21
|
self.class.instance_variable_get('@commands')
|
28
22
|
end
|
29
23
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
24
|
+
def call
|
25
|
+
with_validation do |_commands|
|
26
|
+
_commands.each do |command|
|
27
|
+
@context.merge!(command.new(context).call)
|
28
|
+
end
|
33
29
|
end
|
34
30
|
end
|
35
31
|
|
32
|
+
# allow execution of the service from the class level for those
|
33
|
+
# that prefer that style
|
34
|
+
def self.call(context)
|
35
|
+
self.new(context).call
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def with_validation
|
41
|
+
add_validation_keys_to_context unless skip_validation
|
42
|
+
|
43
|
+
_commands = skip_validation ? commands : [EnsureOrganizerIsValid] + commands
|
44
|
+
|
45
|
+
yield(_commands)
|
46
|
+
|
47
|
+
remove_validation_keys_from_context unless skip_validation
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_validation_keys_to_context
|
51
|
+
context.merge!(validation_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_validation_keys_from_context
|
55
|
+
validation_hash.keys.each do |key|
|
56
|
+
context.delete(key)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def validation_hash
|
61
|
+
@validation_hash ||= {
|
62
|
+
provided_keys: context.keys,
|
63
|
+
expected_keys: expects,
|
64
|
+
provided_commands: commands
|
65
|
+
}
|
66
|
+
end
|
36
67
|
end
|
37
68
|
|
38
69
|
end
|
@@ -9,22 +9,26 @@ module SimpleService
|
|
9
9
|
def returns(*args)
|
10
10
|
@returns = args
|
11
11
|
end
|
12
|
+
|
13
|
+
def skip_validation(skip=true)
|
14
|
+
@skip_validation = skip
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
module InstanceMethods
|
15
19
|
|
16
|
-
def
|
20
|
+
def setup_call_chain
|
17
21
|
self.class.class_eval do
|
18
22
|
|
19
23
|
# grab the method object and hold onto it here
|
20
|
-
|
24
|
+
call_method = instance_method(:call)
|
21
25
|
|
22
|
-
# redefine the
|
23
|
-
# and then run return key checking... allows user to implement
|
26
|
+
# redefine the call method, execute the existing call method object,
|
27
|
+
# and then run return key checking... allows user to implement call in
|
24
28
|
# their individual command classes without having to call super or any
|
25
29
|
# other method to return only specific context keys
|
26
|
-
define_method :
|
27
|
-
|
30
|
+
define_method :call do
|
31
|
+
call_method.bind(self).call
|
28
32
|
find_specified_return_keys
|
29
33
|
end
|
30
34
|
end
|
@@ -54,6 +58,33 @@ module SimpleService
|
|
54
58
|
def returns
|
55
59
|
self.class.instance_variable_get('@returns') || []
|
56
60
|
end
|
61
|
+
|
62
|
+
def skip_validation
|
63
|
+
self.class.instance_variable_get('@skip_validation')
|
64
|
+
end
|
65
|
+
|
66
|
+
def all_specified_context_keys
|
67
|
+
(expects + returns).uniq
|
68
|
+
end
|
69
|
+
|
70
|
+
def define_getters_and_setters
|
71
|
+
all_specified_context_keys.each do |key|
|
72
|
+
self.class.class_eval do
|
73
|
+
|
74
|
+
# getter
|
75
|
+
define_method key do
|
76
|
+
self.context[key]
|
77
|
+
end
|
78
|
+
|
79
|
+
# setter
|
80
|
+
define_method "#{key}=" do |val|
|
81
|
+
self.context[key] = val
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
57
88
|
end
|
58
89
|
|
59
90
|
end
|
data/lib/simple_service.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'simple_service/service_base'
|
2
|
-
require 'simple_service/argument_validator'
|
3
2
|
require 'simple_service/command'
|
4
|
-
require 'simple_service/exceptions'
|
5
3
|
require 'simple_service/organizer'
|
4
|
+
require 'simple_service/exceptions'
|
5
|
+
require 'simple_service/commands/validates_commands_not_empty'
|
6
|
+
require 'simple_service/commands/validates_commands_properly_inherit'
|
7
|
+
require 'simple_service/commands/validates_expected_keys'
|
8
|
+
require 'simple_service/ensure_organizer_is_valid'
|
6
9
|
require 'simple_service/version'
|
7
10
|
|
8
11
|
module SimpleService
|
9
|
-
# Your code goes here...
|
10
12
|
end
|
data/spec/lib/command_spec.rb
CHANGED
@@ -3,41 +3,48 @@ require 'spec_helper'
|
|
3
3
|
describe SimpleService::Command do
|
4
4
|
|
5
5
|
class ValidCommand < SimpleService::Command
|
6
|
-
|
7
6
|
expects :foo, :bar
|
8
7
|
returns :bar, :baz
|
9
|
-
|
10
|
-
def execute
|
8
|
+
def call
|
11
9
|
context.merge!(
|
12
10
|
bar: 'modified',
|
13
11
|
baz: 'blah'
|
14
12
|
)
|
15
13
|
end
|
14
|
+
end
|
16
15
|
|
16
|
+
class InvalidReturnCommand < SimpleService::Command
|
17
|
+
expects :foo
|
18
|
+
returns :foo, :baz
|
19
|
+
def call; true; end
|
17
20
|
end
|
18
21
|
|
19
|
-
|
22
|
+
|
23
|
+
class CallNotDefinedCommand < SimpleService::Command
|
20
24
|
end
|
21
25
|
|
22
|
-
describe '#
|
26
|
+
describe '#call' do
|
23
27
|
|
24
28
|
context 'when #returns is not empty' do
|
25
29
|
it 'returns the correct keys from the context' do
|
26
30
|
expect(
|
27
|
-
ValidCommand.new(foo: 'blah', bar: 'meh').
|
31
|
+
ValidCommand.new(foo: 'blah', bar: 'meh').call
|
28
32
|
).to eql(bar: 'modified', baz: 'blah')
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
32
36
|
context 'raises error' do
|
33
37
|
|
34
|
-
it 'when command does not define an
|
38
|
+
it 'when command does not define an call method' do
|
39
|
+
expect {
|
40
|
+
CallNotDefinedCommand.new.call
|
41
|
+
}.to raise_error(SimpleService::CallNotDefinedError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'when command attempts to return a key that doesnt exist' do
|
35
45
|
expect {
|
36
|
-
|
37
|
-
}.to raise_error(
|
38
|
-
SimpleService::ExecuteNotDefinedError,
|
39
|
-
'NoExecuteDefinedCommand - does not define an execute method'
|
40
|
-
)
|
46
|
+
InvalidReturnCommand.new.call
|
47
|
+
}.to raise_error(SimpleService::ReturnKeyError)
|
41
48
|
end
|
42
49
|
|
43
50
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleService::ValidatesCommandsNotEmpty do
|
4
|
+
|
5
|
+
class DummyCommand < SimpleService::Command
|
6
|
+
def call; true; end
|
7
|
+
end
|
8
|
+
|
9
|
+
context '#call' do
|
10
|
+
|
11
|
+
it 'raises error when commands are not defined' do
|
12
|
+
expect {
|
13
|
+
SimpleService::ValidatesCommandsNotEmpty.new(provided_commands: nil).call
|
14
|
+
}.to raise_error(
|
15
|
+
SimpleService::OrganizerCommandsNotDefinedError,
|
16
|
+
'This Organizer class does not contain any command definitions'
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'does not raise error when commands are defined' do
|
21
|
+
expect {
|
22
|
+
SimpleService::ValidatesCommandsNotEmpty.new(provided_commands: [DummyCommand]).call
|
23
|
+
}.to_not raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleService::ValidatesCommandsProperlyInherit do
|
4
|
+
|
5
|
+
class ValidDummyCommand < SimpleService::Command
|
6
|
+
def call; true; end
|
7
|
+
end
|
8
|
+
|
9
|
+
class InvalidDummyCommand
|
10
|
+
def call; true; end
|
11
|
+
end
|
12
|
+
|
13
|
+
context '#call' do
|
14
|
+
it 'raises error when commands do not inherit from SimpleService::Command' do
|
15
|
+
expect {
|
16
|
+
SimpleService::ValidatesCommandsProperlyInherit.new(
|
17
|
+
provided_commands: [InvalidDummyCommand]
|
18
|
+
).call
|
19
|
+
}.to raise_error(
|
20
|
+
SimpleService::CommandParentClassInvalidError,
|
21
|
+
'InvalidDummyCommand - must inherit from SimpleService::Command'
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'does not raises error when commands inherit from SimpleService::Command' do
|
26
|
+
expect {
|
27
|
+
SimpleService::ValidatesCommandsProperlyInherit.new(
|
28
|
+
provided_commands: [ValidDummyCommand]
|
29
|
+
).call
|
30
|
+
}.to_not raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleService::ValidatesExpectedKeys do
|
4
|
+
|
5
|
+
let(:valid_keys) {{
|
6
|
+
expected_keys: [:foo],
|
7
|
+
provided_keys: [:foo],
|
8
|
+
some_other_key: 'blah'
|
9
|
+
}}
|
10
|
+
|
11
|
+
context '#call' do
|
12
|
+
|
13
|
+
let(:with_valid_keys) {
|
14
|
+
SimpleService::ValidatesExpectedKeys.new(valid_keys)
|
15
|
+
}
|
16
|
+
|
17
|
+
let(:with_missing_keys) {
|
18
|
+
_keys = valid_keys.merge(expected_keys: [:foo, :baz])
|
19
|
+
SimpleService::ValidatesExpectedKeys.new(_keys)
|
20
|
+
}
|
21
|
+
|
22
|
+
let(:does_not_expect_any_keys) {
|
23
|
+
_keys = valid_keys.merge(expected_keys: [])
|
24
|
+
SimpleService::ValidatesExpectedKeys.new(_keys)
|
25
|
+
}
|
26
|
+
|
27
|
+
context 'when all arguments are valid' do
|
28
|
+
|
29
|
+
it 'does not raise error' do
|
30
|
+
expect {
|
31
|
+
with_valid_keys.call
|
32
|
+
}.to_not raise_error
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when there are expected keys missing from provided keys' do
|
38
|
+
|
39
|
+
it 'raises an error' do
|
40
|
+
expect { with_missing_keys.call }.to raise_error(
|
41
|
+
SimpleService::ExpectedKeyError,
|
42
|
+
'keys required by the organizer but not found in the context: baz'
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'no expected keys are given' do
|
49
|
+
|
50
|
+
it 'does not raise error' do
|
51
|
+
expect {
|
52
|
+
does_not_expect_any_keys.call
|
53
|
+
}.to_not raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleService::EnsureOrganizerIsValid do
|
4
|
+
|
5
|
+
context '#call' do
|
6
|
+
|
7
|
+
class FooCommand < SimpleService::Command
|
8
|
+
def call; true; end
|
9
|
+
end
|
10
|
+
|
11
|
+
class BadInheritanceCommand
|
12
|
+
def call; true; end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/spec/lib/organizer_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe SimpleService::Organizer do
|
|
7
7
|
class TestCommandOne < SimpleService::Command
|
8
8
|
expects :foo
|
9
9
|
returns :foo, :bar
|
10
|
-
def
|
10
|
+
def call
|
11
11
|
context.merge!(bar: 'bar')
|
12
12
|
end
|
13
13
|
end
|
@@ -15,7 +15,7 @@ describe SimpleService::Organizer do
|
|
15
15
|
class TestCommandTwo < SimpleService::Command
|
16
16
|
expects :foo, :bar
|
17
17
|
returns :foo, :bar, :baz
|
18
|
-
def
|
18
|
+
def call
|
19
19
|
context.merge!(baz: 'baz')
|
20
20
|
end
|
21
21
|
end
|
@@ -26,10 +26,10 @@ describe SimpleService::Organizer do
|
|
26
26
|
commands TestCommandOne, TestCommandTwo
|
27
27
|
end
|
28
28
|
|
29
|
-
describe '#
|
29
|
+
describe '#call' do
|
30
30
|
it 'returns the correct hash' do
|
31
31
|
expect(
|
32
|
-
TestOrganizer.new(foo: 'foo').
|
32
|
+
TestOrganizer.new(foo: 'foo').call
|
33
33
|
).to eql(foo: 'foo', bar: 'bar', baz: 'baz')
|
34
34
|
end
|
35
35
|
|
@@ -41,14 +41,14 @@ describe SimpleService::Organizer do
|
|
41
41
|
|
42
42
|
class TestCommandThree < SimpleService::Command
|
43
43
|
expects :foo
|
44
|
-
def
|
44
|
+
def call
|
45
45
|
context.merge!(bar: 'bar')
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
class TestCommandFour < SimpleService::Command
|
50
50
|
expects :foo, :bar
|
51
|
-
def
|
51
|
+
def call
|
52
52
|
context.merge!(baz: 'baz')
|
53
53
|
end
|
54
54
|
end
|
@@ -58,10 +58,10 @@ describe SimpleService::Organizer do
|
|
58
58
|
commands TestCommandThree, TestCommandFour
|
59
59
|
end
|
60
60
|
|
61
|
-
describe '#
|
61
|
+
describe '#call' do
|
62
62
|
it 'returns the entire context' do
|
63
63
|
expect(
|
64
|
-
TestOrganizerTwo.new(foo: 'foo', extra: 'extra').
|
64
|
+
TestOrganizerTwo.new(foo: 'foo', extra: 'extra').call
|
65
65
|
).to eql(foo: 'foo', bar: 'bar', baz: 'baz', extra: 'extra')
|
66
66
|
end
|
67
67
|
|
@@ -74,7 +74,7 @@ describe SimpleService::Organizer do
|
|
74
74
|
class GetterSetterCommand < SimpleService::Command
|
75
75
|
expects :foo, :bar
|
76
76
|
returns :baz
|
77
|
-
def
|
77
|
+
def call
|
78
78
|
self.baz = self.foo
|
79
79
|
end
|
80
80
|
end
|
@@ -87,7 +87,7 @@ describe SimpleService::Organizer do
|
|
87
87
|
|
88
88
|
it 'returns the correct hash' do
|
89
89
|
expect(
|
90
|
-
GetterSetterOrganizer.new(foo: 'baz', bar: 'bar').
|
90
|
+
GetterSetterOrganizer.new(foo: 'baz', bar: 'bar').call
|
91
91
|
).to eql({ baz: 'baz' })
|
92
92
|
end
|
93
93
|
|
metadata
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jarrod Spillers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.3'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 10.4.2
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 10.4.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 3.2.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 3.2.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: pry
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 0.10.1
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 0.10.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: codeclimate-test-reporter
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
description: A minimal service object composer with support for individual commands
|
@@ -88,25 +88,34 @@ executables: []
|
|
88
88
|
extensions: []
|
89
89
|
extra_rdoc_files: []
|
90
90
|
files:
|
91
|
-
- .gitignore
|
92
|
-
- .rspec
|
93
|
-
- .travis.yml
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".travis.yml"
|
94
94
|
- Gemfile
|
95
95
|
- LICENSE
|
96
96
|
- LICENSE.txt
|
97
97
|
- README.md
|
98
98
|
- Rakefile
|
99
99
|
- example/hello_world.rb
|
100
|
+
- example/nested_organizer.rb
|
101
|
+
- example/nested_services.rb
|
102
|
+
- example/override_organizer_call_method.rb
|
100
103
|
- lib/simple_service.rb
|
101
|
-
- lib/simple_service/argument_validator.rb
|
102
104
|
- lib/simple_service/command.rb
|
105
|
+
- lib/simple_service/commands/validates_commands_not_empty.rb
|
106
|
+
- lib/simple_service/commands/validates_commands_properly_inherit.rb
|
107
|
+
- lib/simple_service/commands/validates_expected_keys.rb
|
108
|
+
- lib/simple_service/ensure_organizer_is_valid.rb
|
103
109
|
- lib/simple_service/exceptions.rb
|
104
110
|
- lib/simple_service/organizer.rb
|
105
111
|
- lib/simple_service/service_base.rb
|
106
112
|
- lib/simple_service/version.rb
|
107
113
|
- simple_service.gemspec
|
108
|
-
- spec/lib/argument_validator_spec.rb
|
109
114
|
- spec/lib/command_spec.rb
|
115
|
+
- spec/lib/commands/validates_commands_not_empty_spec.rb
|
116
|
+
- spec/lib/commands/validates_commands_properly_inherit_spec.rb
|
117
|
+
- spec/lib/commands/validates_expected_keys_spec.rb
|
118
|
+
- spec/lib/ensure_organizer_is_valid_spec.rb
|
110
119
|
- spec/lib/organizer_spec.rb
|
111
120
|
- spec/simple_service_spec.rb
|
112
121
|
- spec/spec_helper.rb
|
@@ -120,24 +129,27 @@ require_paths:
|
|
120
129
|
- lib
|
121
130
|
required_ruby_version: !ruby/object:Gem::Requirement
|
122
131
|
requirements:
|
123
|
-
- -
|
132
|
+
- - ">="
|
124
133
|
- !ruby/object:Gem::Version
|
125
134
|
version: '0'
|
126
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
136
|
requirements:
|
128
|
-
- -
|
137
|
+
- - ">="
|
129
138
|
- !ruby/object:Gem::Version
|
130
139
|
version: '0'
|
131
140
|
requirements: []
|
132
141
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.4.
|
142
|
+
rubygems_version: 2.4.5
|
134
143
|
signing_key:
|
135
144
|
specification_version: 4
|
136
145
|
summary: A minimal service object composer with support for individual commands and
|
137
146
|
top level organizer objects
|
138
147
|
test_files:
|
139
|
-
- spec/lib/argument_validator_spec.rb
|
140
148
|
- spec/lib/command_spec.rb
|
149
|
+
- spec/lib/commands/validates_commands_not_empty_spec.rb
|
150
|
+
- spec/lib/commands/validates_commands_properly_inherit_spec.rb
|
151
|
+
- spec/lib/commands/validates_expected_keys_spec.rb
|
152
|
+
- spec/lib/ensure_organizer_is_valid_spec.rb
|
141
153
|
- spec/lib/organizer_spec.rb
|
142
154
|
- spec/simple_service_spec.rb
|
143
155
|
- spec/spec_helper.rb
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module SimpleService
|
2
|
-
class ArgumentValidator
|
3
|
-
|
4
|
-
attr_accessor :context, :expects, :commands
|
5
|
-
|
6
|
-
def initialize(opts)
|
7
|
-
@context = opts[:context]
|
8
|
-
@expects = opts[:expects]
|
9
|
-
@commands = opts[:commands]
|
10
|
-
end
|
11
|
-
|
12
|
-
def execute
|
13
|
-
validate_expected_arguments
|
14
|
-
validate_commands_not_empty
|
15
|
-
validate_commands_properly_inherit
|
16
|
-
true
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def validate_expected_arguments
|
22
|
-
arguments_not_included = []
|
23
|
-
|
24
|
-
expects.each do |expected_arg|
|
25
|
-
arguments_not_included << expected_arg unless context.has_key?(expected_arg)
|
26
|
-
end
|
27
|
-
|
28
|
-
if arguments_not_included.any?
|
29
|
-
error_msg = 'keys required by the organizer but not found in the context: ' +
|
30
|
-
arguments_not_included.join(', ')
|
31
|
-
raise ExpectedKeyError, error_msg
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def validate_commands_not_empty
|
36
|
-
if commands.nil? || commands.empty?
|
37
|
-
error_msg = 'This Organizer class does not contain any command definitions'
|
38
|
-
raise SimpleService::OrganizerCommandsNotDefinedError, error_msg
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
def validate_commands_properly_inherit
|
44
|
-
invalid_command_inherit = commands.select do |command|
|
45
|
-
# does the command class inherit from SimpleService::Command
|
46
|
-
!(command.ancestors.include?(SimpleService::Command))
|
47
|
-
end
|
48
|
-
|
49
|
-
if invalid_command_inherit.any?
|
50
|
-
error_msg = invalid_command_inherit.join(', ') +
|
51
|
-
' - must inherit from SimpleService::Command'
|
52
|
-
raise SimpleService::CommandParentClassInvalidError, error_msg
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SimpleService::ArgumentValidator do
|
4
|
-
|
5
|
-
context 'execute' do
|
6
|
-
|
7
|
-
class FooCommand < SimpleService::Command
|
8
|
-
def execute; true; end
|
9
|
-
end
|
10
|
-
|
11
|
-
class BadInheritanceCommand
|
12
|
-
def execute; true; end
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:valid_args) {{
|
16
|
-
context: { foo: 'bar'},
|
17
|
-
expects: [:foo],
|
18
|
-
returns: [:foo],
|
19
|
-
commands: [FooCommand]
|
20
|
-
}}
|
21
|
-
|
22
|
-
context 'when all arguments are valid' do
|
23
|
-
|
24
|
-
it 'does not raise error' do
|
25
|
-
expect {
|
26
|
-
SimpleService::ArgumentValidator.new(valid_args).execute
|
27
|
-
}.to_not raise_error
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'returns true' do
|
31
|
-
expect(
|
32
|
-
SimpleService::ArgumentValidator.new(valid_args).execute
|
33
|
-
).to eql true
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'raises error when context does not contain expected keys' do
|
39
|
-
expect {
|
40
|
-
args = valid_args.merge(expects: [:baz])
|
41
|
-
SimpleService::ArgumentValidator.new(args).execute
|
42
|
-
}.to raise_error(
|
43
|
-
SimpleService::ExpectedKeyError,
|
44
|
-
'keys required by the organizer but not found in the context: baz'
|
45
|
-
)
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'raises error when commands are not defined' do
|
49
|
-
expect {
|
50
|
-
args = valid_args.merge(commands: nil)
|
51
|
-
SimpleService::ArgumentValidator.new(args).execute
|
52
|
-
}.to raise_error(
|
53
|
-
SimpleService::OrganizerCommandsNotDefinedError,
|
54
|
-
'This Organizer class does not contain any command definitions'
|
55
|
-
)
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'raises error when commands do not inherit from SimpleService::Command' do
|
59
|
-
expect {
|
60
|
-
args = valid_args.merge(commands: [BadInheritanceCommand])
|
61
|
-
SimpleService::ArgumentValidator.new(args).execute
|
62
|
-
}.to raise_error(
|
63
|
-
SimpleService::CommandParentClassInvalidError,
|
64
|
-
'BadInheritanceCommand - must inherit from SimpleService::Command'
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|