usecasing 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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