carry_out 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 48df2d9a646c48893cc2224a4167d522dd2c8e81
4
- data.tar.gz: e928043f8032caccc5af2f111d31d8f94a348b26
3
+ metadata.gz: 15539f051ef8fbb7bde23ab9027e1a309b318eb6
4
+ data.tar.gz: 75df54ddbd00851be278a80faaa350e2483ad0c5
5
5
  SHA512:
6
- metadata.gz: 2de51be35be58f48b5c02269631e6b731a5b61057c6f29b9c7cc3edf260a82aeee71b31a2c999b09ea412de6b125349a2b053d6d9a1c2f651b4536ee37596f8a
7
- data.tar.gz: 86e7ad493a8175f7e426a6bd0b69d919d9f1ba8d633cc3cad86eef9734d7ba3890e3fad5c4cf9614130b091d2a85f2dade390f3fc91e5b1a422791c625f7e86d
6
+ metadata.gz: c9df9545f0b391a1f31471ecbc1b85a4f5257fd9399144c75d55643cb787620ac7486dc46de7ee297877779a975b7b3a1817ac14ad62b31172895f9a851c581c
7
+ data.tar.gz: 33bcc7bc1820b9c2dbd2bd8a084f6a8168d145e854d6ee50ad0fd0ae370ce8a8255ba0a361dadc97201b277353a5b6f1b1d283063d75935f7a3edac6702593dd
data/README.md CHANGED
@@ -221,6 +221,53 @@ plan = CarryOut
221
221
  # or .unless(CarryOut.get(:silenced))
222
222
  ```
223
223
 
224
+ ### Magic Directives (Experimental)
225
+
226
+ *This feature is highly experimental. It has not been thoroughly tested in larger application environments like Rails and is not yet guaranteed to remain part of this gem.*
227
+
228
+ CarryOut provides some magic methods that can improve the readability of a plan. These rely on a search strategy to find classes by name. A very limited strategy is provided out-of-the-box. This strategy accepts an array of modules and will only find classes that are direct children of any of the provided modules. The first match gets priority.
229
+
230
+ ```ruby
231
+ CarryOut.defaults = {
232
+ search: [ MyModule1 ]
233
+ }
234
+ ```
235
+
236
+ If the default strategy is insufficient (and it most likely will be), a custom strategy can be provided as a lambda/Proc. For example, a strategy that works in Rails is to put the following in an initializer:
237
+
238
+ ```ruby
239
+ CarryOut.defaults = {
240
+ search: -> (name) { name.constantize }
241
+ }
242
+ ```
243
+
244
+ #### Magic will\_, then\_, and within\_
245
+
246
+ The magic versions of `will`, `then`, and `within` will use the configured search strategy to convert the remaning portion of the directive into a class reference.
247
+
248
+ Using the default strategy as configured above:
249
+ ```ruby
250
+ module MyModule1
251
+ class SayHello
252
+ def execute; puts "Hello!"; end
253
+ end
254
+ end
255
+
256
+ plan = CarryOut.will_say_hello
257
+ ```
258
+
259
+ #### Magic returning\_as\_
260
+
261
+ The magic `returning_as_` directive is an alternative to passing the `as:` option to a `will`/`then` directive. The remainder of the directive becomes the key symbol into which the unit's return value will be stored.
262
+
263
+ ```ruby
264
+ plan = CarryOut
265
+ .will_receive_message
266
+ .returning_as_message
267
+ .then_log
268
+ .message(CarryOut.get(:message))
269
+ ```
270
+
224
271
  ## Motivation
225
272
 
226
273
  I've been trying to keep my Rails controllers clean, but I prefer to avoid shoving inter-model business logic inside database models. The recommendation I most frequently run into is to move that kind of logic into something akin to service objects. I like that idea, but I want to keep my services small and composable, and I want to separate the "what" from the "how" of my logic.
data/carry_out.gemspec CHANGED
@@ -24,10 +24,14 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
26
 
27
- spec.required_ruby_version = '~> 2.0'
27
+ spec.required_ruby_version = '>= 1.9.3'
28
28
 
29
29
  spec.add_development_dependency "bundler", "~> 1.12"
30
30
  spec.add_development_dependency "rake", "~> 10.0"
31
31
  spec.add_development_dependency "minitest", "~> 5.0"
32
- spec.add_development_dependency "coveralls"
32
+ spec.add_development_dependency "coveralls", "~> 0.8"
33
+
34
+ if RUBY_VERSION < '2.0'
35
+ spec.add_development_dependency "tins", "~> 1.6.0"
36
+ end
33
37
  end
@@ -1,15 +1,17 @@
1
1
  module CarryOut
2
2
  class Plan
3
-
3
+ MATCH_CONTINUATION_METHOD = /^(?:will|then)_(.+)/
4
+ MATCH_CONTEXT_METHOD = /^within_(.+)/
5
+ MATCH_RETURNING_METHOD = /^returning_as_(.+)/
6
+
4
7
  def initialize(unit = nil, options = {})
5
8
  @nodes = {}
6
9
  @node_meta = {}
7
10
  @previously_added_node = nil
8
11
  @wrapper = options[:within]
12
+ @search = options[:search] || []
9
13
 
10
- unless unit.nil?
11
- self.then(unit, options)
12
- end
14
+ self.then(unit, options) unless unit.nil?
13
15
  end
14
16
 
15
17
  def execute(context = nil, &block)
@@ -41,8 +43,8 @@ module CarryOut
41
43
  self.then(*args)
42
44
  end
43
45
 
44
- def then(unit, options = {})
45
- add_node(PlanNode.new(unit), options[:as])
46
+ def then(unit = nil, options = {})
47
+ add_node(PlanNode.new(unit), options[:as]) unless unit.nil?
46
48
  self
47
49
  end
48
50
 
@@ -53,8 +55,21 @@ module CarryOut
53
55
  end
54
56
 
55
57
  def method_missing(method, *args, &block)
56
- if @previously_added_node
57
- @previously_added_node.send(method, *args, &block)
58
+ if MATCH_CONTINUATION_METHOD =~ method
59
+ obj = find_object($1)
60
+ return super if obj.nil?
61
+ self.then(obj, *args, &block)
62
+ elsif MATCH_CONTEXT_METHOD =~ method
63
+ obj = find_object($1)
64
+ return super if obj.nil?
65
+ @wrapper = obj.new
66
+ self
67
+ elsif @previously_added_node
68
+ if MATCH_RETURNING_METHOD =~ method
69
+ node_meta(@previously_added_node)[:as] = $1.to_sym
70
+ else
71
+ @previously_added_node.send(method, *args, &block)
72
+ end
58
73
  self
59
74
  else
60
75
  super
@@ -106,7 +121,18 @@ module CarryOut
106
121
  node_result = node.execute(result.artifacts)
107
122
  result.add(publish_to, node_result) unless publish_to.nil?
108
123
  rescue UnitError => error
109
- result.add(publish_to || id, CarryOut::Error.new(error.error.message, error.error))
124
+ result.add(publish_to || key_for_node(node), CarryOut::Error.new(error.error.message, error.error))
125
+ end
126
+ end
127
+
128
+ def find_object(name)
129
+ constant_name = name.to_s.split('_').map { |w| w.capitalize }.join('')
130
+
131
+ if @search.respond_to?(:call)
132
+ @search.call(constant_name)
133
+ else
134
+ containing_module = @search.find { |m| m.const_get(constant_name) rescue nil }
135
+ containing_module.const_get(constant_name) unless containing_module.nil?
110
136
  end
111
137
  end
112
138
 
@@ -121,8 +147,12 @@ module CarryOut
121
147
  guards.nil? || guards.map { |guard| guard.call(artifacts) }.all?
122
148
  end
123
149
 
150
+ def key_for_node(node)
151
+ @nodes.key(node)
152
+ end
153
+
124
154
  def node_meta(node)
125
- @node_meta[@nodes.key(node)]
155
+ @node_meta[key_for_node(node)]
126
156
  end
127
157
  end
128
158
  end
@@ -1,3 +1,3 @@
1
1
  module CarryOut
2
- VERSION = "0.2.8"
2
+ VERSION = "0.2.9"
3
3
  end
data/lib/carry_out.rb CHANGED
@@ -9,15 +9,61 @@ require "carry_out/unit"
9
9
  require "carry_out/unit_error"
10
10
 
11
11
  module CarryOut
12
- def self.get(*args)
13
- Reference.new(*args)
12
+ MATCH_CONTINUATION_METHOD = /^will_/
13
+ MATCH_WITHIN_METHOD = /^within_/
14
+
15
+ class ConfiguredCarryOut
16
+ def initialize(options = {})
17
+ @config = options
18
+ end
19
+
20
+ def get(*args)
21
+ Reference.new(*args)
22
+ end
23
+
24
+ def method_missing(method, *args, &block)
25
+ if MATCH_CONTINUATION_METHOD =~ method
26
+ create_plan.send(method, *args, &block)
27
+ elsif MATCH_WITHIN_METHOD =~ method
28
+ create_plan.send(method, *args, &block)
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ def will(*args)
35
+ create_plan.will(*args)
36
+ end
37
+
38
+ def within(wrapper = nil, &block)
39
+ create_plan(within: wrapper || block)
40
+ end
41
+
42
+ private
43
+ def create_plan(options = {})
44
+ Plan.new(nil, @config.merge(options))
45
+ end
46
+ end
47
+
48
+ def self.configured_with(options = {})
49
+ ConfiguredCarryOut.new(options)
14
50
  end
15
51
 
16
- def self.will(*args)
17
- Plan.new(*args)
52
+ def self.defaults=(options = {})
53
+ @default_options = options
54
+ @default_carry_out = nil
18
55
  end
19
56
 
20
- def self.within(unit = nil, &block)
21
- Plan.new(nil, within: unit || block)
57
+ def self.method_missing(method, *args, &block)
58
+ default_carry_out.send(method, *args, &block)
22
59
  end
60
+
61
+ private
62
+ def self.default_options
63
+ @default_options ||= Hash.new
64
+ end
65
+
66
+ def self.default_carry_out
67
+ @default_carry_out ||= ConfiguredCarryOut.new(default_options)
68
+ end
23
69
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carry_out
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Fields
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: coveralls
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '0.8'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '0.8'
69
69
  description: |2
70
70
  CarryOut connects units of logic into workflows. Each unit can extend
71
71
  the DSL with parameter methods. Artifacts and errors are collected as
@@ -106,9 +106,9 @@ require_paths:
106
106
  - lib
107
107
  required_ruby_version: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - "~>"
109
+ - - ">="
110
110
  - !ruby/object:Gem::Version
111
- version: '2.0'
111
+ version: 1.9.3
112
112
  required_rubygems_version: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - ">="