usecasing 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,14 +20,15 @@ module UseCase
20
20
  end
21
21
 
22
22
  def perform(ctx = { })
23
- execution_order = build_execution_order(self, {})
23
+ any_ciclic, ciclic = CyclicFinder.new(self).cyclic?
24
+ raise StandardError.new("cyclic detected: #{ciclic}") if any_ciclic
25
+ execution_order = []
26
+ build_execution_order(self, execution_order)
24
27
  tx(execution_order, ctx) do |usecase, context|
25
28
  usecase.new(context).perform
26
29
  end
27
30
  end
28
31
 
29
- private
30
-
31
32
  def tx(execution_order, context)
32
33
  ctx = Context.new(context)
33
34
  executed = []
@@ -47,20 +48,37 @@ module UseCase
47
48
  context
48
49
  end
49
50
 
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
51
+ def build_execution_order(node, result)
52
+ return result.push(node) if node.dependencies.empty?
53
+
54
+ node.dependencies.each do |item|
55
+ build_execution_order(item, result)
57
56
  end
58
- childrens.push(start_point)
59
57
 
58
+ result.push(node)
60
59
  end
61
- end
62
60
 
63
- end
61
+ # def build_execution_order
62
+ # stack = [self]
63
+ # result = []
64
+ # visited = {}
65
+
66
+ # until stack.empty?
67
+ # node = stack.last
68
+ # if(node.dependencies.empty? || visited[node.name])
69
+ # result.push(stack.pop)
70
+ # else
71
+ # stack.push(*(node.dependencies.reverse))
72
+ # visited[node.name] = true
73
+ # end
74
+ # end
75
+
76
+ # return result
77
+
78
+ # end
79
+
80
+ end #ClassMethods
81
+ end #BaseClassMethod
64
82
 
65
83
  class Base
66
84
 
@@ -0,0 +1,44 @@
1
+ require 'set'
2
+ require 'tsort'
3
+
4
+ module UseCase
5
+
6
+ class CyclicFinder
7
+ include TSort
8
+
9
+ def initialize(start_point)
10
+ @start_point = start_point
11
+ @nodes = discover_nodes
12
+ end
13
+
14
+ def tsort_each_node(&block)
15
+ @nodes.each &block
16
+ end
17
+
18
+ def tsort_each_child(node, &block)
19
+ node.dependencies.each &block
20
+ end
21
+
22
+ def cyclic?
23
+ components = strongly_connected_components
24
+ result = components.any?{ |component| component.size != 1 }
25
+ [ result, components.select{|component| component.size != 1 } ]
26
+ end
27
+
28
+ private
29
+ def discover_nodes
30
+ visited = {}
31
+ stack = [@start_point]
32
+ result = Set.new
33
+ until stack.empty?
34
+ node = stack.pop
35
+ result.add node
36
+ stack.push(*(node.dependencies)) if not visited[node]
37
+ visited[node] = true
38
+ end
39
+
40
+ return result
41
+ end
42
+
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  module Usecasing
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/usecasing.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "usecasing/version"
2
2
 
3
3
  module UseCase
4
- autoload :Context, 'usecasing/context'
5
- autoload :Base, 'usecasing/base'
4
+ autoload :Context, 'usecasing/context'
5
+ autoload :Base, 'usecasing/base'
6
+ autoload :CyclicFinder, 'usecasing/cyclic_finder'
6
7
  end
@@ -226,28 +226,28 @@ describe UseCase::Base do
226
226
 
227
227
  it 'only rollbacks usecase that ran' do
228
228
 
229
- UseCaseFailRanThird = Class.new(UseCase::Base) do
230
-
229
+ UseCaseFailRanThird = Class.new(UseCase::Base) do
230
+
231
231
  def rollback
232
- context.should_not_appear = 'true'
232
+ context.rollback_third = 'true'
233
233
  end
234
234
 
235
235
  end
236
236
 
237
237
  UseCaseFailRanSecond = Class.new(UseCase::Base) do
238
238
 
239
- def perform
240
- failure(:rollback, 'error')
241
- end
242
-
243
-
244
239
  def rollback
245
- context.rollback_second 'true_2'
240
+ context.rollback_second = 'true_2'
246
241
  end
247
242
 
248
243
  end
249
244
 
250
245
  UseCaseFailRanFirst = Class.new(UseCase::Base) do
246
+ depends UseCaseFailRanSecond
247
+
248
+ def perform
249
+ failure(:rollback, 'error')
250
+ end
251
251
 
252
252
  def rollback
253
253
  context.rollback_first = 'true_1'
@@ -256,13 +256,16 @@ describe UseCase::Base do
256
256
  end
257
257
 
258
258
  UseCaseFailRan = Class.new(UseCase::Base) do
259
- depends UseCaseFailRanFirst, UseCaseFailRanSecond, UseCaseFailRanThird
259
+ depends UseCaseFailRanFirst, UseCaseFailRanThird
260
260
  end
261
261
 
262
262
  context = UseCaseFailRan.perform
263
- expect(context.should_not_appear).to be_nil
263
+ expect(context.rollback_third).to_not be
264
+ expect(context.rollback_second).to be
265
+ expect(context.rollback_first).to be
264
266
 
265
267
  end
268
+
266
269
  end
267
270
 
268
271
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: usecasing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-20 00:00:00.000000000 Z
12
+ date: 2013-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -76,6 +76,7 @@ files:
76
76
  - lib/usecasing.rb
77
77
  - lib/usecasing/base.rb
78
78
  - lib/usecasing/context.rb
79
+ - lib/usecasing/cyclic_finder.rb
79
80
  - lib/usecasing/version.rb
80
81
  - spec/context_spec.rb
81
82
  - spec/spec_helper.rb
@@ -95,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
95
96
  version: '0'
96
97
  segments:
97
98
  - 0
98
- hash: 2175319097785181606
99
+ hash: 1663280317763873983
99
100
  required_rubygems_version: !ruby/object:Gem::Requirement
100
101
  none: false
101
102
  requirements:
@@ -104,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
105
  version: '0'
105
106
  segments:
106
107
  - 0
107
- hash: 2175319097785181606
108
+ hash: 1663280317763873983
108
109
  requirements: []
109
110
  rubyforge_project:
110
111
  rubygems_version: 1.8.24