usecasing 0.1.0

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.
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,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in usecasing.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Thiago Dantas
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,156 @@
1
+ # UseCase your code
2
+
3
+
4
+ ## Installation
5
+
6
+ [![Build Status](https://secure.travis-ci.org/tdantas/usecasing.png)](http://travis-ci.org/tdantas/usecasing)
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ I did not (YET) upload this code to the rubygems.
11
+ To early adopters use the :git path
12
+
13
+ gem 'usecasing', :git => 'https://github.com/tdantas/usecasing.git'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ### Usage
20
+
21
+ Let's build a Invoice System, right ?
22
+ So the product owner will create some usecases/stories to YOU.
23
+
24
+ Imagine this usecase/story:
25
+
26
+ ````
27
+ As a user I want to finalize an Invoice and an email should be delivered to the customer.
28
+ ````
29
+
30
+ Let's build a controller
31
+
32
+ ````
33
+ class InvoicesController < ApplicationController
34
+
35
+ def finalize
36
+
37
+ params[:current_user] = current_user
38
+ # params = { invoice_id: 123 , current_user: #<User:007> }
39
+ context = FinalizeInvoiceUseCase.perform(params)
40
+
41
+ if context.success?
42
+ redirect_to invoices_path(context.invoice)
43
+ else
44
+ @errors = context.errors
45
+ redirect_to invoices_path
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ ````
52
+
53
+ Ok, What is FinalizeInvoiceUseCase ?
54
+
55
+ FinalizeInvoiceUseCase will be responsible for perform the Use Case/Story.
56
+ Each usecase should satisfy the [Single Responsability Principle](http://en.wikipedia.org/wiki/Single_responsibility_principle) and to achieve this principle, one usecase depends of others usecases building a Chain of Resposability.
57
+
58
+
59
+ ````
60
+
61
+ class FinalizeInvoiceUseCase < UseCase::Base
62
+ depends FindInvoice, ValidateToFinalize, FinalizeInvoice, SendEmail
63
+ end
64
+
65
+ ````
66
+
67
+ IMHO, when I read this Chain I really know what this class will do.
68
+ astute readers will ask: How FindInvoice pass values to ValidateToFinalize ?
69
+
70
+ When we call in the Controller *FinalizeInvoiceUseCase.perform* we pass a parameter (Hash) to the usecase.
71
+
72
+ This is what we call context, the usecase context will be shared between all chain.
73
+
74
+ ````
75
+ class FindInvoice < UseCase::Base
76
+
77
+ def perform
78
+
79
+ # available because it was added in the controller context
80
+ user = context.current_user
81
+
82
+ # we could do that in one before_filter
83
+ invoice = user.invoices.find(context.invoice_id)
84
+
85
+ # asign to the context make available to all chain
86
+ context.invoice = invoice
87
+
88
+ end
89
+
90
+ end
91
+ ````
92
+
93
+ Is the invoice valid to be finalized ?
94
+
95
+ ````
96
+ class ValidateToFinalize < UseCase::Base
97
+
98
+ def perform
99
+ #failure will stop the chain flow and mark the context as error.
100
+
101
+ failure(:validate, "#{context.invoice.id} not ready to be finalized") unless valid?
102
+ end
103
+
104
+ private
105
+ def valid?
106
+ #contextual validation to finalize an invoice
107
+ end
108
+ end
109
+
110
+ ````
111
+
112
+ So, after validate, we already know that the invoice exists and it is ready to be finalized.
113
+
114
+ ````
115
+ class FinalizeInvoice < UseCase::Base
116
+
117
+ def perform
118
+ invoice = context.invoice
119
+ invoice.finalize! #update database with finalize state
120
+ context.customer = invoice.customer
121
+ end
122
+
123
+ end
124
+ ````
125
+
126
+ Oww, yeah, let's notify the customer
127
+
128
+ ````
129
+ class SendEmail < UseCase::Base
130
+
131
+ def perform
132
+ to = context.customer.email
133
+
134
+ # Call whatever service
135
+ EmailService.send('customer_invoice_template', to, locals: { invoice: context.invoice } )
136
+ end
137
+
138
+ end
139
+ ````
140
+
141
+
142
+ Let me know what do you think about it.
143
+
144
+ #### TODO
145
+
146
+ Create real case examples (40%)
147
+
148
+
149
+
150
+ ## Contributing
151
+
152
+ 1. Fork it
153
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
154
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
155
+ 4. Push to the branch (`git push origin my-new-feature`)
156
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ task :default => :test
6
+ RSpec::Core::RakeTask.new(:test)
@@ -0,0 +1,82 @@
1
+ module UseCase
2
+
3
+ module BaseClassMethod
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def depends(*deps)
12
+ @dependencies ||= []
13
+ @dependencies.push(*deps)
14
+ end
15
+
16
+ def dependencies
17
+ return [] unless superclass.ancestors.include? UseCase::Base
18
+ value = (@dependencies && @dependencies.dup || []).concat(superclass.dependencies)
19
+ value
20
+ end
21
+
22
+ def perform(ctx = { })
23
+ execution_order = build_execution_order(self, {})
24
+ tx(execution_order, ctx) do |usecase, context|
25
+ usecase.new(context).perform
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def tx(execution_order, context)
32
+ ctx = Context.new(context)
33
+ executed = []
34
+ execution_order.each do |usecase|
35
+ break unless ctx.success?
36
+ executed.push(usecase)
37
+ yield usecase, ctx
38
+ end
39
+ rollback(executed, ctx) unless ctx.success?
40
+ ctx
41
+ end
42
+
43
+ def rollback(execution_order, context)
44
+ execution_order.each do |usecase|
45
+ usecase.new(context).rollback
46
+ end
47
+ context
48
+ end
49
+
50
+ def build_execution_order(start_point, visited)
51
+ raise StandardError.new("cyclic detected: #{start_point} in #{self}") if visited[start_point]
52
+ visited[start_point] = true
53
+ return [start_point] if start_point.dependencies.empty?
54
+
55
+ childrens = start_point.dependencies.each do |point|
56
+ build_execution_order(point, visited).unshift point
57
+ end
58
+ childrens.push(start_point)
59
+
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ class Base
66
+
67
+ include BaseClassMethod
68
+
69
+ attr_reader :context
70
+ def initialize(context)
71
+ @context = context
72
+ end
73
+
74
+ def perform; end
75
+ def rollback; end
76
+
77
+ def failure(key, value)
78
+ @context.failure(key, value)
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,48 @@
1
+ module UseCase
2
+
3
+ class Context
4
+
5
+ attr_reader :errors
6
+
7
+ def initialize(hash = {})
8
+ raise ArgumentError.new('Must be a Hash') unless hash.is_a? ::Hash
9
+ @values = symbolyze_keys(hash)
10
+ @errors = []
11
+ end
12
+
13
+ def method_missing(method, *args, &block)
14
+ return @values[extract_key_from(method)] = args.first if setter? method
15
+ @values[method]
16
+ end
17
+
18
+ def respond_to?(method)
19
+ @values.keys.include?(method.to_sym)
20
+ end
21
+
22
+ def success?
23
+ @errors.empty?
24
+ end
25
+
26
+ def failure(key, value)
27
+ @errors.push({ key => value })
28
+ end
29
+
30
+ private
31
+ def setter?(method)
32
+ !! ((method.to_s) =~ /=$/)
33
+ end
34
+
35
+ def extract_key_from(method)
36
+ method.to_s[0..-2].to_sym
37
+ end
38
+
39
+ def symbolyze_keys(hash)
40
+ hash.keys.reduce({ }) do |acc, key|
41
+ acc[key.to_sym] = hash[key]
42
+ acc
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,3 @@
1
+ module Usecasing
2
+ VERSION = "0.1.0"
3
+ end
data/lib/usecasing.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "usecasing/version"
2
+
3
+ module UseCase
4
+ autoload :Context, 'usecasing/context'
5
+ autoload :Base, 'usecasing/base'
6
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe UseCase::Context do
4
+
5
+
6
+ it 'receives a hash and generate setters from key' do
7
+ hash = {name: 'thiago', last: 'dantas', github: 'tdantas'}
8
+ context = described_class.new(hash)
9
+ expect(context.name).to eql(hash[:name])
10
+ expect(context.last).to eql(hash[:last])
11
+ expect(context.github).to eql(hash[:github])
12
+ end
13
+
14
+ it 'initializes without parameters' do
15
+ expect(described_class.new).to be_an(described_class)
16
+ end
17
+
18
+ it 'raises exception when argument is not a hash' do
19
+ expect {described_class.new(Object.new)}.to raise_error(ArgumentError)
20
+ end
21
+
22
+ it 'assign new values' do
23
+ context = described_class.new
24
+ context.dog_name = 'mali'
25
+ context.country = 'lisbon'
26
+ context.age = 1
27
+
28
+ expect(context.dog_name).to eql('mali')
29
+ expect(context.country).to eql('lisbon')
30
+ expect(context.age).to eql(1)
31
+ end
32
+
33
+ it 'handle hash with indifference' do
34
+ hash = { "name" => 'thiago', last: 'dantas'}
35
+ context = described_class.new(hash)
36
+ expect(context.name).to eql('thiago')
37
+ expect(context.last).to eql('dantas')
38
+ end
39
+
40
+ it 'is success when there is no error' do
41
+ context = described_class.new({})
42
+ expect(context.success?).to eql(true)
43
+ end
44
+
45
+ it 'adds error messages to errors' do
46
+ context = described_class.new({})
47
+ context.failure(:email, 'email already exist')
48
+ expect(context.errors.length).to eql(1)
49
+ expect(context.errors.first).to eql({ email: 'email already exist' })
50
+ end
51
+
52
+ it 'fails when exist errors' do
53
+ context = described_class.new({})
54
+ context.failure(:email, 'email already exist')
55
+ expect(context.success?).to eql(false)
56
+ end
57
+
58
+ end
59
+
@@ -0,0 +1,10 @@
1
+ require 'usecasing'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+ config.mock_framework = :mocha
8
+
9
+ config.order = 'random'
10
+ end
@@ -0,0 +1,268 @@
1
+ require 'spec_helper'
2
+
3
+ describe UseCase::Base do
4
+
5
+ context "depends" do
6
+
7
+ it 'initialize without any dependency' do
8
+ AppUseCaseInitialize = Class.new(UseCase::Base)
9
+ expect(AppUseCaseInitialize.dependencies).to be_empty
10
+ end
11
+
12
+ it "adds usecase dependency" do
13
+ AppOtherUseCase = Class.new
14
+ AppUseCase = Class.new(UseCase::Base) do
15
+ depends AppOtherUseCase
16
+ end
17
+
18
+ expect(AppUseCase.dependencies).to eql([AppOtherUseCase])
19
+ end
20
+
21
+
22
+ it 'subclass adds dependency from subclass to superclass' do
23
+
24
+ SuperClassDependency = Class.new(UseCase::Base)
25
+ UseCaseSuperClass = Class.new(UseCase::Base) do
26
+ depends SuperClassDependency
27
+ end
28
+
29
+ SubClassDependency = Class.new(UseCase::Base)
30
+ UseCaseSubClass = Class.new(UseCaseSuperClass) do
31
+ depends SubClassDependency
32
+ end
33
+
34
+ expect(UseCaseSubClass.dependencies).to eql([SubClassDependency, SuperClassDependency])
35
+ #idempotent operation
36
+ expect(UseCaseSubClass.dependencies).to eql([SubClassDependency, SuperClassDependency])
37
+
38
+ end
39
+
40
+
41
+ end
42
+
43
+
44
+ context '##perform' do
45
+
46
+ it 'call instance #perform method' do
47
+ AppUseCaseInstance = Class.new(UseCase::Base) do
48
+ def perform
49
+ #some business rule here
50
+ end
51
+ end
52
+ AppUseCaseInstance.any_instance.expects(:perform).once
53
+ AppUseCaseInstance.perform
54
+ end
55
+
56
+ it 'receives receives a hash and create a execution context' do
57
+
58
+ SendEmailUseCase = Class.new(UseCase::Base) do
59
+ def perform
60
+ context.sent = 'sent'
61
+ end
62
+ end
63
+
64
+ ctx = SendEmailUseCase.perform({email: 'thiago.teixeira.dantas@gmail.com' })
65
+ expect(ctx.sent).to eql('sent')
66
+ expect(ctx.email).to eql('thiago.teixeira.dantas@gmail.com')
67
+ end
68
+
69
+ it 'must receive an hash' do
70
+ UseCaseArgumentException = Class.new(UseCase::Base)
71
+ expect{ UseCaseArgumentException.perform(Object.new) }.to raise_error(ArgumentError)
72
+ end
73
+
74
+ it 'with success when usecase do not register failure' do
75
+ pending
76
+ end
77
+
78
+ it 'fail when usecase register failure' do
79
+ pending
80
+ end
81
+
82
+
83
+ it 'detects cyclic' do
84
+
85
+ CyclicFirst = Class.new(UseCase::Base)
86
+ CyclicSecond = Class.new(UseCase::Base) do
87
+ depends CyclicFirst
88
+ end
89
+
90
+ CyclicFirst.instance_eval do
91
+ depends CyclicSecond
92
+ end
93
+
94
+ FinalUseCase = Class.new(UseCase::Base) do
95
+ depends CyclicSecond
96
+ end
97
+
98
+ expect { FinalUseCase.perform }.to raise_error(StandardError, /cyclic detected/)
99
+
100
+ end
101
+
102
+ end
103
+
104
+ context '##perfoms execution chain' do
105
+ it 'executes in lexical order cascading context among usecases' do
106
+
107
+ FirstUseCase = Class.new(UseCase::Base) do
108
+ def perform
109
+ context.first = context.first_arg
110
+ end
111
+ end
112
+
113
+ SecondUseCase = Class.new(UseCase::Base) do
114
+ def perform
115
+ context.second = context.second_arg
116
+ end
117
+ end
118
+
119
+ UseCaseChain = Class.new(UseCase::Base) do
120
+ depends FirstUseCase, SecondUseCase
121
+ end
122
+
123
+ ctx = UseCaseChain.perform({:first_arg => 1, :second_arg => 2})
124
+ expect(ctx.first).to eql(1)
125
+ expect(ctx.second).to eql(2)
126
+ end
127
+
128
+
129
+ it 'stops the flow when failure happen' do
130
+
131
+ FirstUseCaseFailure = Class.new(UseCase::Base) do
132
+ def perform
133
+ context.first = context.first_arg
134
+ end
135
+ end
136
+
137
+ SecondUseCaseFailure = Class.new(UseCase::Base) do
138
+
139
+ def perform
140
+ context.second = context.second_arg
141
+ failure(:second, 'next will not be called')
142
+ end
143
+
144
+ end
145
+
146
+ ThirdUseCaseFailure = Class.new(UseCase::Base) do
147
+ def perform
148
+ context.third = true
149
+ end
150
+ end
151
+
152
+ UseCaseFailure = Class.new(UseCase::Base) do
153
+ depends FirstUseCaseFailure, SecondUseCaseFailure, ThirdUseCaseFailure
154
+ end
155
+
156
+ ThirdUseCaseFailure.any_instance.expects(:perform).never
157
+ UseCaseFailure.perform
158
+
159
+ end
160
+ end
161
+
162
+ context '#perform' do
163
+ it 'receive an Context instance' do
164
+ InstanceUseCase = Class.new(UseCase::Base) do
165
+ def perform
166
+ context.executed = true
167
+ end
168
+ end
169
+ ctx = UseCase::Context.new
170
+ InstanceUseCase.new(ctx).perform
171
+ expect(ctx.executed).to be_true
172
+ end
173
+ end
174
+
175
+
176
+ context 'rolling back the flow' do
177
+
178
+ it 'rollback without dependencies' do
179
+
180
+ UseCaseWithRollback = Class.new(UseCase::Base) do
181
+
182
+ def perform
183
+ failure(:rollback, 'must be called')
184
+ end
185
+
186
+ def rollback
187
+ context.rollback_executed = 'true'
188
+ end
189
+
190
+ end
191
+
192
+ context = UseCaseWithRollback.perform
193
+ expect(context.rollback_executed).to eql('true')
194
+
195
+ end
196
+
197
+ it 'in reverse order of execution' do
198
+ order = 0
199
+
200
+ UseCaseWithRollbackOrderDepdens = Class.new(UseCase::Base) do
201
+ define_method :rollback do
202
+ order += 1
203
+ context.first_rollback = order
204
+ end
205
+
206
+ end
207
+
208
+ UseCaseWithRollbackOrder = Class.new(UseCase::Base) do
209
+ depends UseCaseWithRollbackOrderDepdens
210
+
211
+ def perform
212
+ failure(:rollback, 'error')
213
+ end
214
+
215
+ define_method :rollback do
216
+ order += 1
217
+ context.second_rollback = order
218
+ end
219
+ end
220
+
221
+ context = UseCaseWithRollbackOrder.perform
222
+ expect(context.first_rollback).to eql(1)
223
+ expect(context.second_rollback).to eql(2)
224
+ end
225
+
226
+
227
+ it 'only rollbacks usecase that ran' do
228
+
229
+ UseCaseFailRanThird = Class.new(UseCase::Base) do
230
+
231
+ def rollback
232
+ context.should_not_appear = 'true'
233
+ end
234
+
235
+ end
236
+
237
+ UseCaseFailRanSecond = Class.new(UseCase::Base) do
238
+
239
+ def perform
240
+ failure(:rollback, 'error')
241
+ end
242
+
243
+
244
+ def rollback
245
+ context.rollback_second 'true_2'
246
+ end
247
+
248
+ end
249
+
250
+ UseCaseFailRanFirst = Class.new(UseCase::Base) do
251
+
252
+ def rollback
253
+ context.rollback_first = 'true_1'
254
+ end
255
+
256
+ end
257
+
258
+ UseCaseFailRan = Class.new(UseCase::Base) do
259
+ depends UseCaseFailRanFirst, UseCaseFailRanSecond, UseCaseFailRanThird
260
+ end
261
+
262
+ context = UseCaseFailRan.perform
263
+ expect(context.should_not_appear).to be_nil
264
+
265
+ end
266
+ end
267
+
268
+ end
data/usecasing.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'usecasing/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "usecasing"
8
+ gem.version = Usecasing::VERSION
9
+ gem.authors = ["Thiago Dantas"]
10
+ gem.email = ["thiago.teixeira.dantas@gmail.com"]
11
+ gem.description = %q{UseCase Driven approach to your code}
12
+ gem.summary = %q{UseCase Driven Approach}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+
21
+ #development dependecy
22
+ gem.add_development_dependency "rspec"
23
+ gem.add_development_dependency "rake"
24
+ gem.add_development_dependency "mocha"
25
+
26
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: usecasing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Thiago Dantas
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: mocha
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: UseCase Driven approach to your code
63
+ email:
64
+ - thiago.teixeira.dantas@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - .travis.yml
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - lib/usecasing.rb
77
+ - lib/usecasing/base.rb
78
+ - lib/usecasing/context.rb
79
+ - lib/usecasing/version.rb
80
+ - spec/context_spec.rb
81
+ - spec/spec_helper.rb
82
+ - spec/usecase_base_spec.rb
83
+ - usecasing.gemspec
84
+ homepage: ''
85
+ licenses: []
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ segments:
97
+ - 0
98
+ hash: 2175319097785181606
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ segments:
106
+ - 0
107
+ hash: 2175319097785181606
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 1.8.24
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: UseCase Driven Approach
114
+ test_files:
115
+ - spec/context_spec.rb
116
+ - spec/spec_helper.rb
117
+ - spec/usecase_base_spec.rb