states-dsl 0.1.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.
@@ -0,0 +1,22 @@
1
+ module States
2
+ module Dsl
3
+ class ConditionGroup < Choice
4
+ def initialize(type, naming)
5
+ super(naming)
6
+ @type = type
7
+ @parts = []
8
+ end
9
+
10
+ def variable(path, &block)
11
+ c = VariableConditionPart.new(path)
12
+ c.instance_eval(&block)
13
+ @parts << c
14
+ c
15
+ end
16
+
17
+ def serializable_hash
18
+ { @type => @parts.map(&:serializable_hash) }.merge(super)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ module States
2
+ module Dsl
3
+ class Context
4
+ attr_accessor :naming, :traits, :resource_defaults
5
+
6
+ def initialize(options={})
7
+ @traits = {}
8
+ @naming = Naming.new(nil)
9
+ @naming.converter = options[:name_converter]
10
+ @resource_defaults = options[:resource] || {}
11
+ end
12
+
13
+ def create_sub_context(options={})
14
+ sub = Context.new
15
+ sub.traits = traits
16
+
17
+ sub.resource_defaults = resource_defaults
18
+ if defaults = options[:resource]
19
+ sub.resource_defaults = defaults
20
+ end
21
+
22
+ sub.naming = Naming.new(naming)
23
+ if converter = options[:name_converter]
24
+ sub.naming.converter = converter
25
+ end
26
+ sub
27
+ end
28
+
29
+ def register_trait(name, trait)
30
+ trait.context = self
31
+ @traits[name] = trait
32
+ end
33
+
34
+ def lookup_traits(names)
35
+ names.map { |nm| traits[nm] }
36
+ end
37
+
38
+ def function_resource(name)
39
+ ResourceLookup.new(resource_defaults).function(name)
40
+ end
41
+
42
+ def activity_resource(name)
43
+ ResourceLookup.new(resource_defaults).activity(name)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,10 @@
1
+ module States
2
+ module Dsl
3
+ module ErrorSupport
4
+ protected
5
+ def ensure_errors_array(arr)
6
+ [arr].flatten.map { |exc| exc == :all ? "States.ALL" : exc }
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,39 @@
1
+ module States
2
+ module Dsl
3
+ class ExecutionContext
4
+ attr_reader :context
5
+ attr_reader :resource_defaults
6
+
7
+ def initialize(context, options)
8
+ @context = if context.nil?
9
+ Context.new(options)
10
+ else
11
+ context.create_sub_context
12
+ end
13
+ if start_at = options[:start_at]
14
+ @start_at = @context.naming.ref(start_at)
15
+ end
16
+ @states = []
17
+ end
18
+
19
+ def state(name, options={}, &block)
20
+ state = State.new(name, @context, options)
21
+ state.instance_eval(&block) if block
22
+ @states << state
23
+ state
24
+ end
25
+
26
+ def start(name, options={}, &block)
27
+ @start_at = @context.naming.ref(name)
28
+ state(name, options, &block)
29
+ end
30
+
31
+ def serializable_hash
32
+ {
33
+ "StartAt" => @start_at,
34
+ "States" => @states.reduce({}) { |m,s| m[s.name.to_s] = s.serializable_hash; m }
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ module States
2
+ module Dsl
3
+ class Fail
4
+ def initialize(error=nil,cause=nil)
5
+ @error, @cause = error, cause
6
+ end
7
+
8
+ def error(err)
9
+ @error = err
10
+ end
11
+
12
+ def cause(cause)
13
+ @cause = cause
14
+ end
15
+
16
+ def serializable_hash
17
+ h = {}
18
+ h["Error"] = @error if @error
19
+ h["Cause"] = @cause if @cause
20
+ h
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ module States
2
+ module Dsl
3
+ class Namespace
4
+ def initialize
5
+ @source = {}
6
+ @plurals = {}
7
+ end
8
+
9
+ def resolve(name)
10
+ if usages = @source[name.local_name]
11
+ if usages.length == 1
12
+ usages[0].index = 0
13
+ end
14
+ name.index = usages.length
15
+ usages << name
16
+ else
17
+ @source[name.local_name] = [name]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ module States
2
+ module Dsl
3
+ class Naming
4
+ attr_accessor :converter
5
+
6
+ attr_reader :parent
7
+ attr_reader :namespace
8
+ attr_reader :children
9
+ attr_reader :names
10
+
11
+ def initialize(parent)
12
+ @parent = parent
13
+ @names = []
14
+ @references = []
15
+ @children = []
16
+ if parent
17
+ @namespace = parent.namespace
18
+ if parent.converter
19
+ self.converter = parent.converter
20
+ end
21
+ parent.children << self
22
+ else
23
+ @namespace = Namespace.new
24
+ end
25
+ end
26
+
27
+ def <<(name)
28
+ nm = StateName.new(name, self)
29
+ @names << nm
30
+ nm
31
+ end
32
+
33
+ def ref(name)
34
+ ref = StateReference.new(name, self)
35
+ @references << ref
36
+ ref
37
+ end
38
+
39
+ def convert(str)
40
+ if converter
41
+ converter.call(str)
42
+ else
43
+ str
44
+ end
45
+ end
46
+
47
+ def resolve
48
+ return if @resolved
49
+ if parent
50
+ parent.resolve
51
+ else
52
+ resolve_children
53
+ end
54
+ end
55
+
56
+ def resolve_children
57
+ @names.each { |name| @namespace.resolve(name) }
58
+ @references.each do |ref|
59
+ ref.resolved_to = @names.detect { |nm| nm.local_name == ref.name }
60
+ end
61
+ @children.each(&:resolve_children)
62
+ @resolved = true
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,21 @@
1
+ module States
2
+ module Dsl
3
+ class Parallel
4
+ def initialize(context)
5
+ @context = context
6
+ @branches = []
7
+ end
8
+
9
+ def branch(options={}, &block)
10
+ branch = ExecutionContext.new(@context, options)
11
+ branch.instance_eval(&block)
12
+ @branches << branch
13
+ branch
14
+ end
15
+
16
+ def serializable_hash
17
+ { "Branches" => @branches.map(&:serializable_hash) }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module States
2
+ module Dsl
3
+ class ResourceLookup
4
+ attr_reader :params
5
+
6
+ def initialize(defaults)
7
+ @defaults = defaults
8
+ @params = {}
9
+ end
10
+
11
+ def function(name)
12
+ resource(name, :function, :lambda)
13
+ end
14
+
15
+ def activity(name)
16
+ resource(name, :activity, :states)
17
+ end
18
+
19
+ def resource(name, type, service, options={})
20
+ @params = options.merge(name: name, type: type, service: service)
21
+ self
22
+ end
23
+
24
+ def to_s
25
+ values = {partition: "aws"}.merge(@defaults).merge(params)
26
+ ["arn", values[:partition], values[:service], values[:region], values[:account], values[:type], values[:name]].join(":")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ module States
2
+ module Dsl
3
+ class Retry
4
+ include States::Dsl::ErrorSupport
5
+
6
+ def initialize(*arguments)
7
+ options = arguments.last.is_a?(Hash) ? arguments.pop : {}
8
+ @error_equals = if arguments.length > 0
9
+ ensure_errors_array(arguments.first)
10
+ else
11
+ ensure_errors_array(options[:error_equals])
12
+ end
13
+ @max_attempts = options[:max_attempts]
14
+ @backoff_rate = options[:backoff_rate]
15
+ @interval_seconds = options[:interval_seconds]
16
+ end
17
+
18
+ def max_attempts(n)
19
+ @max_attempts = n
20
+ end
21
+
22
+ def backoff_rate(r)
23
+ @backoff_rate = r
24
+ end
25
+
26
+ def interval_seconds(s)
27
+ @interval_seconds = s
28
+ end
29
+
30
+ def serializable_hash
31
+ h = { "ErrorEquals" => @error_equals }
32
+ h["MaxAttempts"] = @max_attempts if @max_attempts
33
+ h["BackoffRate"] = @backoff_rate if @backoff_rate
34
+ h["IntervalSeconds"] = @interval_seconds if @interval_seconds
35
+ h
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ module States
2
+ module Dsl
3
+ class State < StateLike
4
+ attr_reader :name
5
+
6
+ def initialize(name, context, options={})
7
+ super(options)
8
+ @name = context.naming << name
9
+ self.context = context
10
+ end
11
+
12
+ def serializable_hash
13
+ json = super
14
+ json["Type"] ||= "Pass"
15
+ if json["Next"].nil? && !%w(Choice Fail).include?(json["Type"])
16
+ json["End"] = true
17
+ end
18
+ json
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,127 @@
1
+ module States
2
+ module Dsl
3
+ class StateLike
4
+ UNSET = Object.new
5
+
6
+ attr_accessor :context
7
+
8
+ def initialize(options={})
9
+ @traits = options[:traits] || []
10
+ @result_path = @output_path = @input_path = UNSET
11
+ @retries = []
12
+ @catches = []
13
+ end
14
+
15
+ def function(name)
16
+ resource(context.function_resource(name))
17
+ end
18
+
19
+ def activity(name)
20
+ resource(context.activity_resource(name))
21
+ end
22
+
23
+ def resource(arn)
24
+ @resource = arn
25
+ end
26
+
27
+ def result_path(path)
28
+ @result_path = path
29
+ end
30
+
31
+ def output_path(path)
32
+ @output_path = path
33
+ end
34
+
35
+ def input_path(path)
36
+ @input_path = path
37
+ end
38
+
39
+ def next_state(state)
40
+ @next_state = context.naming.ref(state)
41
+ end
42
+
43
+ def parallel(&block)
44
+ @parallel = Parallel.new(@context)
45
+ @parallel.instance_eval(&block)
46
+ @parallel
47
+ end
48
+
49
+ def choices(&block)
50
+ @choices = Choices.new(@context.naming)
51
+ @choices.instance_eval(&block)
52
+ @choices
53
+ end
54
+
55
+ def wait(&block)
56
+ @wait = Wait.new(@context.naming)
57
+ @wait.instance_eval(&block)
58
+ @wait
59
+ end
60
+
61
+ def fail(&block)
62
+ @fail = Fail.new
63
+ @fail.instance_eval(&block)
64
+ @fail
65
+ end
66
+
67
+ def retry_if(*arguments, &block)
68
+ _retry = Retry.new(*arguments)
69
+ if block_given?
70
+ _retry.instance_eval(&block)
71
+ end
72
+ @retries << _retry
73
+ end
74
+
75
+ def catch_if(options={}, &block)
76
+ katch = Catch.new(context, options)
77
+ if block_given?
78
+ katch.instance_eval(&block)
79
+ end
80
+ @catches << katch
81
+ end
82
+
83
+ def serializable_hash
84
+ j = context.lookup_traits(@traits).reduce({}) { |m, t| m.merge(t.serializable_hash) }
85
+ if @resource
86
+ j["Type"] = "Task"
87
+ j["Resource"] = @resource.to_s
88
+
89
+ elsif @parallel
90
+ j["Type"] = "Parallel"
91
+ j.merge!(@parallel.serializable_hash)
92
+
93
+ elsif @choices
94
+ j["Type"] = "Choice"
95
+ j.merge!(@choices.serializable_hash)
96
+
97
+ elsif @wait
98
+ j["Type"] = "Wait"
99
+ j.merge!(@wait.serializable_hash)
100
+
101
+ elsif @fail
102
+ j["Type"] = "Fail"
103
+ j.merge!(@fail.serializable_hash)
104
+ end
105
+
106
+ [
107
+ [@result_path, "ResultPath"],
108
+ [@input_path , "InputPath" ],
109
+ [@output_path, "OutputPath"],
110
+ ].each { |(k,v)| j[v] = k if k != UNSET }
111
+
112
+ unless @retries.empty?
113
+ j["Retry"] = @retries.map(&:serializable_hash)
114
+ end
115
+
116
+ unless @catches.empty?
117
+ j["Catch"] = @catches.map(&:serializable_hash)
118
+ end
119
+
120
+ if @next_state
121
+ j["Next"] = @next_state.to_s
122
+ end
123
+ j
124
+ end
125
+ end
126
+ end
127
+ end