transflow 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6c18bc0bd37bd89215142adefd13b8a965ea0994
4
- data.tar.gz: 7827d58aeef106f8cf0eb6969381b76433f44a4e
3
+ metadata.gz: 3dde7fc2cfdb940553b3a4ddabe1004d01ca49a6
4
+ data.tar.gz: 2c7b0e6c01338cd5087ac5dc332e9c5936d3a5b5
5
5
  SHA512:
6
- metadata.gz: 531682614e131a47544798c2700fd2c22258b6fa9a61c309515ef5a6bf72404dbd8a4faa29e8111c3f3c930d73243e7791546d1b4d6ff0aaa1699b0755a0833d
7
- data.tar.gz: e87f9e64c7249a0c550e43b148391da884bdd90bb23b0eeb3131249961c8fd4882a9e6f0d43a7b98e3fb7513c7d699cf63fa63138df53a184f3dbdfa61621643
6
+ metadata.gz: c4601d2a9a7a8dfd1d72c03199f696483fa1de7bf66f0e398cecd17115bbf6a54333c32c11740ec2998d7626bbb8dadc3aab9088b4ed580f0a71cd2bd0af803d
7
+ data.tar.gz: f0ccebb883cc983ace244989008a23c649e2b234ced17692923747c95d6be1b185a4528d5e64202fdf71e829b94f5162ffb3e08611eb05286556a4865b1e5b47
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 0.0.2 2015-08-16
2
+
3
+ ## Added
4
+
5
+ - Ability to publish events from operations via `publish: true` option (solnic)
6
+ - Ability to subscribe to events via `Transflow::Transaction#subscribe` interface (solnic)
7
+
8
+ [Compare v0.0.1...v0.0.2](https://github.com/rom-rb/rom/compare/v0.0.1...v0.0.2)
9
+
1
10
  # 0.0.1 2015-08-16
2
11
 
3
12
  First public release \o/
data/README.md CHANGED
@@ -51,6 +51,56 @@ errors from multiple steps without stopping the processing. It's not implemented
51
51
  yet but *probably* using pub/sub for that will do the work as we can register an
52
52
  error listener that can simply gather errors and return it as a result.
53
53
 
54
+ ## Synopsis
55
+
56
+ ``` ruby
57
+ DB = []
58
+
59
+ container = {
60
+ validate: -> input { raise "name nil" if input[:name].nil? },
61
+ persist: -> input { DB << input[:name] }
62
+ }
63
+
64
+ my_business_flow = Transflow(container: container) do
65
+ step(:validate) { step(:persist) }
66
+ end
67
+
68
+ my_business_flow[{ name: 'Jane' }]
69
+
70
+ puts DB.inspect
71
+ # ["Jane"]
72
+
73
+ ## The same but with events
74
+
75
+ NOTIFICATIONS = []
76
+
77
+ class Notify
78
+ def persist_success(user)
79
+ NOTIFICATIONS << "#{user} persisted"
80
+ end
81
+
82
+ def persist_failure(user, err)
83
+ # do sth about that
84
+ end
85
+ end
86
+
87
+ my_business_flow = Transflow(container: container) do
88
+ step(:validate) { step(:persist, publish: true) }
89
+ end
90
+
91
+ notify = Notify.new
92
+
93
+ my_business_flow.subscribe(persist: notify)
94
+
95
+ my_business_flow[{ name: 'Jane' }]
96
+
97
+ puts DB.inspect
98
+ # ["Jane"]
99
+
100
+ puts NOTIFICATIONS.inspect
101
+ # ["Jane persisted"]
102
+ ```
103
+
54
104
  ## Installation
55
105
 
56
106
  Add this line to your application's Gemfile:
data/lib/transflow.rb CHANGED
@@ -1,73 +1,21 @@
1
- require 'transproc'
2
1
  require 'transflow/version'
3
-
4
- module Transflow
5
- class Transaction
6
- attr_reader :handler
7
-
8
- attr_reader :steps
9
-
10
- def initialize(steps, handler)
11
- @steps = steps
12
- @handler = handler
13
- end
14
-
15
- def call(*args)
16
- handler.call(*args)
17
- end
18
- alias_method :[], :call
19
- end
20
-
21
- class StepDSL
22
- attr_reader :name
23
-
24
- attr_reader :handler
25
-
26
- attr_reader :container
27
-
28
- attr_reader :steps
29
-
30
- def initialize(name, options, container, steps, &block)
31
- @name = name
32
- @handler = options.fetch(:with)
33
- @container = container
34
- @steps = steps
35
- instance_exec(&block) if block
36
- end
37
-
38
- def step(*args, &block)
39
- self.class.new(*args, container, steps, &block).call
40
- end
41
-
42
- def call
43
- steps[name] = container[handler]
44
- end
45
- end
46
-
47
- class FlowDSL
48
- attr_reader :options
49
-
50
- attr_reader :container
51
-
52
- attr_reader :steps
53
-
54
- def initialize(options, &block)
55
- @options = options
56
- @container = options.fetch(:container)
57
- @steps = {}
58
- instance_exec(&block)
59
- end
60
-
61
- def step(*args, &block)
62
- StepDSL.new(*args, container, steps, &block).call
63
- end
64
-
65
- def call
66
- Transaction.new(steps, steps.values.reverse.reduce(:>>))
67
- end
68
- end
69
- end
70
-
2
+ require 'transflow/flow_dsl'
3
+
4
+ # Define a transaction flow
5
+ #
6
+ # @example
7
+ #
8
+ # container = { do_one: some_obj, do_two: some_obj }
9
+ #
10
+ # my_business_flow = Transflow(container: container) do
11
+ # step(:one, with: :do_one) { step(:two, with: :do_two }
12
+ # end
13
+ #
14
+ # my_business_flow[some_input]
15
+ #
16
+ # @options [Hash] options The option hash
17
+ #
18
+ # @api public
71
19
  def Transflow(options = {}, &block)
72
20
  Transflow::FlowDSL.new(options, &block).call
73
21
  end
@@ -0,0 +1,45 @@
1
+ require 'transproc'
2
+
3
+ require 'transflow/step_dsl'
4
+ require 'transflow/transaction'
5
+
6
+ module Transflow
7
+ class FlowDSL
8
+ module Registry
9
+ extend Transproc::Registry
10
+ end
11
+
12
+ def self.[](op)
13
+ if op.respond_to?(:>>)
14
+ op
15
+ else
16
+ Registry[op]
17
+ end
18
+ end
19
+
20
+ attr_reader :options
21
+
22
+ attr_reader :container
23
+
24
+ attr_reader :steps
25
+
26
+ def initialize(options, &block)
27
+ @options = options
28
+ @container = options.fetch(:container)
29
+ @steps = {}
30
+ instance_exec(&block)
31
+ end
32
+
33
+ def step(*args, &block)
34
+ StepDSL.new(*args, container, steps, &block).call
35
+ end
36
+
37
+ def call
38
+ Transaction.new(steps, operations.reduce(:>>))
39
+ end
40
+
41
+ def operations
42
+ steps.values.reverse.map { |op| self.class[op] }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ require 'wisper'
2
+
3
+ module Transflow
4
+ class Publisher
5
+ include Wisper::Publisher
6
+
7
+ attr_reader :name
8
+
9
+ attr_reader :op
10
+
11
+ def initialize(name, op)
12
+ @name = name
13
+ @op = op
14
+ end
15
+
16
+ def call(*args)
17
+ result = op.call(*args)
18
+ broadcast(:"#{name}_success", result)
19
+ result
20
+ rescue => err
21
+ broadcast(:"#{name}_failure", *args, err)
22
+ raise err
23
+ end
24
+ alias_method :[], :call
25
+ end
26
+ end
@@ -0,0 +1,41 @@
1
+ require 'transflow/publisher'
2
+
3
+ module Transflow
4
+ class StepDSL
5
+ attr_reader :name
6
+
7
+ attr_reader :handler
8
+
9
+ attr_reader :container
10
+
11
+ attr_reader :steps
12
+
13
+ attr_reader :publish
14
+
15
+ def initialize(name, options, container, steps, &block)
16
+ @name = name
17
+ @handler = options.fetch(:with)
18
+ @publish = options.fetch(:publish, false)
19
+ @container = container
20
+ @steps = steps
21
+ instance_exec(&block) if block
22
+ end
23
+
24
+ def step(*args, &block)
25
+ self.class.new(*args, container, steps, &block).call
26
+ end
27
+
28
+ def call
29
+ operation = container[handler]
30
+
31
+ step =
32
+ if publish
33
+ Publisher.new(name, operation)
34
+ else
35
+ operation
36
+ end
37
+
38
+ steps[name] = step
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ module Transflow
2
+ class TransactionFailedError < StandardError
3
+ attr_reader :transaction
4
+
5
+ attr_reader :original_error
6
+
7
+ def initialize(transaction, original_error)
8
+ @transaction = transaction
9
+ @original_error = original_error
10
+
11
+ super("#{transaction} failed")
12
+
13
+ set_backtrace(original_error.backtrace)
14
+ end
15
+ end
16
+
17
+ class Transaction
18
+ attr_reader :handler
19
+
20
+ attr_reader :steps
21
+
22
+ def initialize(steps, handler)
23
+ @steps = steps
24
+ @handler = handler
25
+ end
26
+
27
+ def subscribe(listeners)
28
+ listeners.each { |step, listener| steps[step].subscribe(listener) }
29
+ end
30
+
31
+ def call(*args)
32
+ handler.call(*args)
33
+ rescue Transproc::MalformedInputError => err
34
+ raise TransactionFailedError.new(self, err)
35
+ end
36
+ alias_method :[], :call
37
+
38
+ def to_s
39
+ "Transaction(#{steps.keys.join(' => ')})"
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,3 @@
1
1
  module Transflow
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  end
data/transflow.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_runtime_dependency 'transproc', '~> 0.3', '>= 0.3.1'
22
+ spec.add_runtime_dependency 'wisper'
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.10"
24
25
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 0.3.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: wisper
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
33
47
  - !ruby/object:Gem::Dependency
34
48
  name: bundler
35
49
  requirement: !ruby/object:Gem::Requirement
@@ -90,6 +104,10 @@ files:
90
104
  - bin/console
91
105
  - bin/setup
92
106
  - lib/transflow.rb
107
+ - lib/transflow/flow_dsl.rb
108
+ - lib/transflow/publisher.rb
109
+ - lib/transflow/step_dsl.rb
110
+ - lib/transflow/transaction.rb
93
111
  - lib/transflow/version.rb
94
112
  - transflow.gemspec
95
113
  homepage: https://github.com/solnic/transflow