composable_operations 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c6eeabae9917ce517a8f6ba380b3485479edde5a
4
- data.tar.gz: 94ab6cddddbea6be52e2e426a9cc56088bd4b5ac
3
+ metadata.gz: 35bf16a747c65f1dcd6f9e7003f6fb574d86b4b5
4
+ data.tar.gz: d456bb506cef1eb336fbf82d3d80718d28e0c648
5
5
  SHA512:
6
- metadata.gz: bb094f4b9cd7c25d96cb1ebdc27727c0e23d9dd86ad6c386aa1b40107bad8060cc8635a27d4a01bbb91cad34b1cb3644a6eed92ed88ba27c0df456f8671afb73
7
- data.tar.gz: 62f381ac83ebdf643a5e04d1e1d61b60cd1e578fa6202e386fe88db20972d187223a606ba67fd9b091a02a434a78baaf0a1b0230425114b18e65bad46e3686b6
6
+ metadata.gz: caaec98652d28e2f1af2856a93adef45536ce173ff04e632362e5d97e64c22c7d415bc6a2206da36889675d3435e30222fd96bf7be3cc003e300d03c6a262609
7
+ data.tar.gz: 84498a024f0c4564ef33dd276566090d0898d8fadc10e8a4eff7680e70721140943ba5d1c19dc365e8682d87d8010c513979856d1cc378af7eba983c39c879f7
@@ -1,4 +1,5 @@
1
1
  require 'smart_properties'
2
+ require 'delegate'
2
3
 
3
4
  module ComposableOperations
4
5
  # Your code goes here...
@@ -1,13 +1,32 @@
1
1
  module ComposableOperations
2
2
  class ComposedOperation < Operation
3
+
4
+ class AutoConfiguringOperation < SimpleDelegator
5
+
6
+ def initialize(operation_class, options = {})
7
+ super(operation_class)
8
+ @__options__ = options
9
+ end
10
+
11
+ def new(input = nil, options = {})
12
+ options = Hash(__options__).merge(Hash(options))
13
+ __getobj__.new(input, options)
14
+ end
15
+
16
+ protected
17
+
18
+ attr_reader :__options__
19
+
20
+ end
21
+
3
22
  class << self
4
23
 
5
24
  def operations
6
25
  [] + Array((super if defined? super)) + Array(@operations)
7
26
  end
8
27
 
9
- def use(operation)
10
- (@operations ||= []) << operation
28
+ def use(operation, options = {})
29
+ (@operations ||= []) << AutoConfiguringOperation.new(operation, options)
11
30
  end
12
31
 
13
32
  def compose(*operations, &block)
@@ -24,54 +43,24 @@ module ComposableOperations
24
43
  end
25
44
  end
26
45
 
27
- def transitions
28
- transitions = []
29
- klass = self
30
- while klass != Operation
31
- klass = klass.superclass
32
- transitions += Array(klass.instance_variable_get(:@transitions))
33
- end
34
- transitions += Array(@transitions)
35
- transitions
36
- end
37
-
38
-
39
- protected
40
-
41
- def between(&callback)
42
- (@transitions ||= []) << callback
43
- end
44
-
45
- end
46
-
47
- def operations
48
- self.class.operations
49
46
  end
50
47
 
51
48
  protected
52
49
 
53
50
  def execute
54
- [nil, *operations, nil].each_cons(2).inject(input) do |data, operations|
55
- if operation = operations.last
56
- operation = operation.new(data)
57
- operation.perform
58
-
59
- if operation.failed?
60
- fail operation.message, operation.result, operation.backtrace
61
- elsif operation.halted?
62
- halt operation.message, operation.result
63
- end
64
-
65
- transition(*operations, data) if operations.first && operations.last
66
- operation.result
67
- else
68
- data
51
+ self.class.operations.inject(input) do |data, operation_and_options|
52
+ operation, options = *operation_and_options
53
+ operation = operation.new(data, options)
54
+ operation.perform
55
+
56
+ if operation.failed?
57
+ fail operation.message, operation.result, operation.backtrace
58
+ elsif operation.halted?
59
+ halt operation.message, operation.result
69
60
  end
70
- end
71
- end
72
61
 
73
- def transition(a, b, payload)
74
- self.class.transitions.each { |transition| instance_exec(a, b, payload, &transition) }
62
+ operation.result
63
+ end
75
64
  end
76
65
 
77
66
  end
@@ -1,3 +1,3 @@
1
1
  module ComposableOperations
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -26,6 +26,21 @@ describe ComposableOperations::ComposedOperation do
26
26
  end
27
27
  end
28
28
 
29
+ let(:string_multiplier) do
30
+ Class.new(ComposableOperations::Operation) do
31
+ property :multiplicator, default: 1, converts: :to_i, required: true
32
+ property :separator, default: ' ', converts: :to_s, required: true
33
+
34
+ def self.name
35
+ "StringMultiplier"
36
+ end
37
+
38
+ def execute
39
+ (Array(input) * multiplicator).join(separator)
40
+ end
41
+ end
42
+ end
43
+
29
44
  let(:halting_operation) do
30
45
  Class.new(ComposableOperations::Operation) do
31
46
  def execute
@@ -50,7 +65,23 @@ describe ComposableOperations::ComposedOperation do
50
65
 
51
66
  end
52
67
 
53
- context "when composed of two operations using the factory method '#chain'" do
68
+ context "when composed of two operations, one that generates a string and one that multiplies it" do
69
+
70
+ subject(:composed_operation) do
71
+ string_generator = self.string_generator
72
+ string_multiplier = self.string_multiplier
73
+
74
+ Class.new(described_class) do
75
+ use string_generator
76
+ use string_multiplier, separator: ' - ', multiplicator: 3
77
+ end.new
78
+ end
79
+
80
+ it { should succeed_to_perform.and_return('chunky bacon - chunky bacon - chunky bacon') }
81
+
82
+ end
83
+
84
+ context "when composed of two operations using the factory method '.compose'" do
54
85
 
55
86
  subject(:composed_operation) do
56
87
  described_class.compose(string_generator, string_capitalizer).new
@@ -101,35 +132,4 @@ describe ComposableOperations::ComposedOperation do
101
132
  it { should utilize_operations(string_generator, halting_operation, string_capitalizer) }
102
133
  end
103
134
 
104
- context "when composed of two operations and provided with a between block" do
105
-
106
-
107
- let(:logger) { stub("Logger").as_null_object }
108
-
109
- subject(:composed_operation) do
110
- string_generator = string_generator()
111
- string_capitalizer = string_capitalizer()
112
- logger = logger()
113
-
114
- operation = described_class.compose do
115
- use string_generator
116
- use string_capitalizer
117
-
118
- between do |a, b, payload|
119
- logger.info("#{a.name} -> #{b.name} with #{payload.inspect} as payload")
120
- end
121
- end
122
-
123
- operation.new
124
- end
125
-
126
- it { should succeed_to_perform.and_return("CHUNKY BACON") }
127
-
128
- it "should generate the correct log message" do
129
- logger.should_receive(:info).with("StringGenerator -> StringCapitalizer with \"chunky bacon\" as payload")
130
- composed_operation.perform
131
- end
132
-
133
- end
134
-
135
135
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: composable_operations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Tennhard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-12 00:00:00.000000000 Z
11
+ date: 2013-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: smart_properties