usecasing 0.1.0 → 0.1.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.
@@ -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