simple_service 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af47217423dfde7e55b44539cb67335bf973e827
4
+ data.tar.gz: 6f6955116fc1de25feb69748943bbd693f032fe1
5
+ SHA512:
6
+ metadata.gz: a29bd75670cad144a923b95738dc20966cd2af9c5c777ee64603f7b498d16ac948e4ed0f1003cd2e15a4dc4d0d9e34c9f03a2782fdb2fb02876d973efb80a4a4
7
+ data.tar.gz: 078d232dc698930fec97d656566edce4d29007e144849f03d14c263e0f0a220eb487525bd3e37f9d0822c2daa2dbe4965b46136f60dc6ccdbb044564a0c1ceae
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ --order rand
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-19mode
5
+ - rbx
6
+ - 2.0.0
7
+ - 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simple_service.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Jarrod Spillers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Jrod
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # SimpleService
2
+
3
+ [![Code Climate](https://codeclimate.com/github/jspillers/simple_service/badges/gpa.svg)](https://codeclimate.com/github/jspillers/simple_service)
4
+ [![Test Coverage](https://codeclimate.com/github/jspillers/simple_service/badges/coverage.svg)](https://codeclimate.com/github/jspillers/simple_service)
5
+ [![Build Status](https://travis-ci.org/jspillers/simple_service.svg?branch=master)](https://travis-ci.org/jspillers/simple_service)
6
+
7
+ SimpleService gives you a way to organize service objects such that they adhere
8
+ to the single responsibility principle. Instead of writing large service objects
9
+ that perform multiple tasks, SimpleService allows you to breakdown tasks into a
10
+ set a sequentially performed Command objects. When properly designed, these command
11
+ objects can be reused in multiple different organizers minimizing code duplication.
12
+
13
+ When an organizer is instantiated a hash of arguments is passed in. This hash
14
+ is referred to as the context. The context hash is carried along throughout
15
+ the sequence of command executions and modified by each command. After a
16
+ successful run, the entire context hash (or a specified subset) is returned.
17
+
18
+ First, setup an Organizer class. An Organizer needs the following things defined:
19
+
20
+ * expects: keys that are required to be passed into initialize when an instance
21
+ of organizer is created. If not defined the organizer will accept arbitrary arguments.
22
+ * returns: keys that will be returned when the organizer has executed all of its commands
23
+ * commands: classes that define all the steps that the organizer will execute. The organizer
24
+ will call #execute on each command in order and the context hash is passed to each of
25
+ these commands. Any keys within the context that are modified will be merged back into
26
+ the organizer and passed along to the next command.
27
+
28
+ ```ruby
29
+ class ProcessSomethingComplex < SimpleService::Organizer
30
+
31
+ # optional - ensures the following keys are provided during instantiation
32
+ # leave out to accept any arguments/keys
33
+ expects :something, :another_thing
34
+
35
+ # optional - specifies which keys get returned after #execute is called on
36
+ # an organizer instance
37
+ returns :modified_thing
38
+
39
+ # what steps comprise this service
40
+ # #execute will be called on an instance of each class in sequence
41
+ commands DoSomethingImportant, DoAnotherStep
42
+
43
+ end
44
+ ```
45
+
46
+ Next, define all command classes that make up the service. Each should inherit
47
+ from SimpleService::Command and define similar things to the organizer:
48
+
49
+ ```ruby
50
+ class DoSomethingImportant < SimpleService::Command
51
+
52
+ # optional - creates getter/setter for each key specified,
53
+ # leave blank to accept arbitrary args
54
+ expects :something
55
+
56
+ # optional - creates getter/setter for each key specified,
57
+ # leave blank to return entire context hash
58
+ returns :modified_something, :another_thing
59
+
60
+ # required - this is where the work gets done, should only
61
+ # do one thing (single responsibility principle)
62
+ # getters and setters are available for each key specified
63
+ # in expects and returns. If not using expects and returns
64
+ # simply interact with the context hash directly
65
+ def execute
66
+ # uses getters and setters to modify the context
67
+ self.modified_something = self.something.to_i + 1
68
+
69
+ # or act directly on the context hash
70
+ context[:modified_something] = context[:something].to_i + 1
71
+
72
+ # no need to return anything specific, either the keys
73
+ # specified in returns will be returned or the entire
74
+ # context if no returns are defined
75
+ end
76
+
77
+ end
78
+
79
+ class DoSomethingImportant < SimpleService::Command
80
+ ...
81
+ end
82
+ ```
83
+
84
+ ## Usage
85
+
86
+ Using the service is straight forward - just instantiate it, passing in the
87
+ intial context hash, and then call execute.
88
+
89
+ ```ruby
90
+ starting_context = {
91
+ something: '1',
92
+ :another_thing: AnotherThing.new
93
+ }
94
+ modified_context = ProcessSomethingComplex.new(starting_context).execute
95
+
96
+ modified_context[:modified_thing] # => 2
97
+ ```
98
+
99
+ If you are using this with a Rails app, placing top level services in
100
+ app/services/ and all commands in app/services/commands/ is recommended. If
101
+ not using rails, a similar structure would also be recommended.
102
+
103
+ ## Inspiration and Rationale
104
+
105
+ This gem is heavily inspired by two very nice gems: [mutations](https://github.com/cypriss/mutations) and
106
+ [light-service](https://github.com/adomokos/light-service).
107
+
108
+ Mutations is a great gem, but lacks the concept of a top level organizer.
109
+ LightService brings in the notion of the organizer object, but doesn't create
110
+ instances of its action objects (what are referred to as commands here). Using
111
+ instances rather than class level execute definitions allows the use of private
112
+ methods within the command for more complex commands that still do a single thing.
113
+
114
+ The other goal of this gem is to do as little as possible above and beyond
115
+ just using plain old Ruby objects (PORO's). Things like error handling, logging,
116
+ and context status will be left up to the individual to implement in a way that
117
+ best suits their use case.
118
+
119
+ ## Installation
120
+
121
+ Add this line to your application's Gemfile:
122
+
123
+ gem 'simple_service'
124
+
125
+ And then execute:
126
+
127
+ $ bundle
128
+
129
+ Or install it yourself as:
130
+
131
+ $ gem install simple_service
132
+
133
+ ## Contributing
134
+
135
+ 1. Fork it
136
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
137
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
138
+ 4. Push to the branch (`git push origin my-new-feature`)
139
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
9
+ rescue LoadError
10
+ # no rspec available
11
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'pry'
3
+ require 'simple_service'
4
+
5
+ class ConcatName < SimpleService::Command
6
+ expects :first_name, :last_name
7
+ returns :name
8
+
9
+ def execute
10
+ self.name = "#{first_name} #{last_name}"
11
+ end
12
+ end
13
+
14
+ class CreateHelloString < SimpleService::Command
15
+ expects :name
16
+ returns :hello
17
+
18
+ def execute
19
+ self.hello = "#{name}, say hello world!"
20
+ end
21
+ end
22
+
23
+ class SayHello < SimpleService::Organizer
24
+ expects :first_name, :last_name
25
+ returns :hello
26
+ commands ConcatName, CreateHelloString
27
+ end
28
+
29
+ result = SayHello.new(first_name: 'Ruby', last_name: 'Gem').execute
30
+ puts result[:hello]
@@ -0,0 +1,57 @@
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
@@ -0,0 +1,48 @@
1
+ module SimpleService
2
+ class Command
3
+
4
+ include ServiceBase::InstanceMethods
5
+ extend ServiceBase::ClassMethods
6
+
7
+ attr_accessor :context
8
+
9
+ def initialize(context={})
10
+ @context = context
11
+ setup_execute_chain
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
+
25
+ def all_specified_context_keys
26
+ (expects + returns)
27
+ end
28
+
29
+ def define_getters_and_setters
30
+ all_specified_context_keys.each do |key|
31
+ self.class.class_eval do
32
+
33
+ # getter
34
+ define_method key do
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
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,8 @@
1
+ module SimpleService
2
+
3
+ class OrganizerCommandsNotDefinedError < StandardError; end;
4
+ class CommandParentClassInvalidError < StandardError; end;
5
+ class ExpectedKeyError < StandardError; end;
6
+ class ExecuteNotDefinedError < StandardError; end;
7
+ class ReturnKeyError < StandardError; end;
8
+ end
@@ -0,0 +1,38 @@
1
+ module SimpleService
2
+ class Organizer
3
+
4
+ include ServiceBase::InstanceMethods
5
+ extend ServiceBase::ClassMethods
6
+
7
+ attr_accessor :context
8
+
9
+ def initialize(context={})
10
+ @context = context
11
+
12
+ ArgumentValidator.new(
13
+ context: context,
14
+ expects: expects,
15
+ returns: returns,
16
+ commands: commands
17
+ ).execute
18
+
19
+ setup_execute_chain
20
+ end
21
+
22
+ def self.commands(*args)
23
+ @commands = args
24
+ end
25
+
26
+ def commands
27
+ self.class.instance_variable_get('@commands')
28
+ end
29
+
30
+ def execute
31
+ commands.each do |command|
32
+ @context.merge!(command.new(context).execute)
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,60 @@
1
+ module SimpleService
2
+ module ServiceBase
3
+
4
+ module ClassMethods
5
+ def expects(*args)
6
+ @expects = args
7
+ end
8
+
9
+ def returns(*args)
10
+ @returns = args
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+
16
+ def setup_execute_chain
17
+ self.class.class_eval do
18
+
19
+ # grab the method object and hold onto it here
20
+ execute_method = instance_method(:execute)
21
+
22
+ # redefine the execute method, call the existing execute method object,
23
+ # and then run return key checking... allows user to implement execute in
24
+ # their individual command classes without having to call super or any
25
+ # other method to return only specific context keys
26
+ define_method :execute do
27
+ execute_method.bind(self).call
28
+ find_specified_return_keys
29
+ end
30
+ end
31
+ end
32
+
33
+ def find_specified_return_keys
34
+ if returns.nil? || returns.empty?
35
+ context
36
+ else
37
+ returns.inject({}) do |to_return, return_param|
38
+ if context.has_key?(return_param)
39
+ to_return[return_param] = context[return_param]
40
+ else
41
+ error_msg = "#{self.class} tried to return #{return_param}, but it did not exist in the context: #{context.inspect}"
42
+ raise ReturnKeyError, error_msg
43
+ end
44
+
45
+ to_return
46
+ end
47
+ end
48
+ end
49
+
50
+ def expects
51
+ self.class.instance_variable_get('@expects') || []
52
+ end
53
+
54
+ def returns
55
+ self.class.instance_variable_get('@returns') || []
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleService
2
+ VERSION = '1.0.1'
3
+ end
@@ -0,0 +1,10 @@
1
+ require 'simple_service/service_base'
2
+ require 'simple_service/argument_validator'
3
+ require 'simple_service/command'
4
+ require 'simple_service/exceptions'
5
+ require 'simple_service/organizer'
6
+ require 'simple_service/version'
7
+
8
+ module SimpleService
9
+ # Your code goes here...
10
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simple_service/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'simple_service'
8
+ spec.version = SimpleService::VERSION
9
+ spec.authors = ['Jarrod Spillers']
10
+ spec.email = ['jarrod@stacktact.com']
11
+ spec.description = %q{A minimal service object composer with support for individual commands and top level organizer objects}
12
+ spec.summary = spec.description
13
+ spec.homepage = 'https://github.com/jspillers/simple_service'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake', '~> 10.4.2'
23
+ spec.add_development_dependency 'rspec', '~> 3.2.0'
24
+ spec.add_development_dependency 'pry', '~> 0.10.1'
25
+ spec.add_development_dependency 'codeclimate-test-reporter'
26
+ end
@@ -0,0 +1,70 @@
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
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleService::Command do
4
+
5
+ class ValidCommand < SimpleService::Command
6
+
7
+ expects :foo, :bar
8
+ returns :bar, :baz
9
+
10
+ def execute
11
+ context.merge!(
12
+ bar: 'modified',
13
+ baz: 'blah'
14
+ )
15
+ end
16
+
17
+ end
18
+
19
+ class NoExecuteDefinedCommand < SimpleService::Command
20
+ end
21
+
22
+ describe '#execute' do
23
+
24
+ context 'when #returns is not empty' do
25
+ it 'returns the correct keys from the context' do
26
+ expect(
27
+ ValidCommand.new(foo: 'blah', bar: 'meh').execute
28
+ ).to eql(bar: 'modified', baz: 'blah')
29
+ end
30
+ end
31
+
32
+ context 'raises error' do
33
+
34
+ it 'when command does not define an execute method' do
35
+ expect {
36
+ NoExecuteDefinedCommand.new.execute
37
+ }.to raise_error(
38
+ SimpleService::ExecuteNotDefinedError,
39
+ 'NoExecuteDefinedCommand - does not define an execute method'
40
+ )
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ describe 'context' do
48
+
49
+ it 'defines getters for each expected key' do
50
+ expect(
51
+ ValidCommand.new(foo: 'blah', bar: 'meh')
52
+ ).to respond_to :foo
53
+ end
54
+
55
+ it 'defines setters for each expected key' do
56
+ command = ValidCommand.new(foo: 'blah', bar: 'meh')
57
+ command.foo = 'changed'
58
+ command.bar = 'changed'
59
+
60
+ expect(command.context).to eql({ foo: 'changed', bar: 'changed' })
61
+ end
62
+
63
+ it 'getter updates @context' do
64
+ command = ValidCommand.new(foo: 'blah', bar: 'meh')
65
+ command.foo = 'changed'
66
+ expect(command.context).to eql({ foo: 'changed', bar: 'meh'})
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleService::Organizer do
4
+
5
+ context 'classes with expects and returns' do
6
+
7
+ class TestCommandOne < SimpleService::Command
8
+ expects :foo
9
+ returns :foo, :bar
10
+ def execute
11
+ context.merge!(bar: 'bar')
12
+ end
13
+ end
14
+
15
+ class TestCommandTwo < SimpleService::Command
16
+ expects :foo, :bar
17
+ returns :foo, :bar, :baz
18
+ def execute
19
+ context.merge!(baz: 'baz')
20
+ end
21
+ end
22
+
23
+ class TestOrganizer < SimpleService::Organizer
24
+ expects :foo
25
+ returns :foo, :bar, :baz
26
+ commands TestCommandOne, TestCommandTwo
27
+ end
28
+
29
+ describe '#execute' do
30
+ it 'returns the correct hash' do
31
+ expect(
32
+ TestOrganizer.new(foo: 'foo').execute
33
+ ).to eql(foo: 'foo', bar: 'bar', baz: 'baz')
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ context 'classes with only expects' do
41
+
42
+ class TestCommandThree < SimpleService::Command
43
+ expects :foo
44
+ def execute
45
+ context.merge!(bar: 'bar')
46
+ end
47
+ end
48
+
49
+ class TestCommandFour < SimpleService::Command
50
+ expects :foo, :bar
51
+ def execute
52
+ context.merge!(baz: 'baz')
53
+ end
54
+ end
55
+
56
+ class TestOrganizerTwo < SimpleService::Organizer
57
+ expects :foo
58
+ commands TestCommandThree, TestCommandFour
59
+ end
60
+
61
+ describe '#execute' do
62
+ it 'returns the entire context' do
63
+ expect(
64
+ TestOrganizerTwo.new(foo: 'foo', extra: 'extra').execute
65
+ ).to eql(foo: 'foo', bar: 'bar', baz: 'baz', extra: 'extra')
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ describe 'service using getters and setters' do
73
+
74
+ class GetterSetterCommand < SimpleService::Command
75
+ expects :foo, :bar
76
+ returns :baz
77
+ def execute
78
+ self.baz = self.foo
79
+ end
80
+ end
81
+
82
+ class GetterSetterOrganizer < SimpleService::Organizer
83
+ expects :foo, :bar
84
+ returns :baz
85
+ commands GetterSetterCommand
86
+ end
87
+
88
+ it 'returns the correct hash' do
89
+ expect(
90
+ GetterSetterOrganizer.new(foo: 'baz', bar: 'bar').execute
91
+ ).to eql({ baz: 'baz' })
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleService do
4
+
5
+ end
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib', 'simple_service')
2
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
3
+ $LOAD_PATH << File.join(File.dirname(__FILE__))
4
+
5
+ require 'codeclimate-test-reporter'
6
+ CodeClimate::TestReporter.start
7
+
8
+ require 'pry'
9
+ require 'rspec'
10
+ require 'simple_service'
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_service
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jarrod Spillers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 10.4.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 10.4.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.10.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.10.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: codeclimate-test-reporter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: A minimal service object composer with support for individual commands
84
+ and top level organizer objects
85
+ email:
86
+ - jarrod@stacktact.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - .travis.yml
94
+ - Gemfile
95
+ - LICENSE
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - example/hello_world.rb
100
+ - lib/simple_service.rb
101
+ - lib/simple_service/argument_validator.rb
102
+ - lib/simple_service/command.rb
103
+ - lib/simple_service/exceptions.rb
104
+ - lib/simple_service/organizer.rb
105
+ - lib/simple_service/service_base.rb
106
+ - lib/simple_service/version.rb
107
+ - simple_service.gemspec
108
+ - spec/lib/argument_validator_spec.rb
109
+ - spec/lib/command_spec.rb
110
+ - spec/lib/organizer_spec.rb
111
+ - spec/simple_service_spec.rb
112
+ - spec/spec_helper.rb
113
+ homepage: https://github.com/jspillers/simple_service
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubyforge_project:
133
+ rubygems_version: 2.4.2
134
+ signing_key:
135
+ specification_version: 4
136
+ summary: A minimal service object composer with support for individual commands and
137
+ top level organizer objects
138
+ test_files:
139
+ - spec/lib/argument_validator_spec.rb
140
+ - spec/lib/command_spec.rb
141
+ - spec/lib/organizer_spec.rb
142
+ - spec/simple_service_spec.rb
143
+ - spec/spec_helper.rb