trailblazer-activity 0.9.1 → 0.11.2

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
  SHA256:
3
- metadata.gz: 943560a813f46719e16777daa7f1b58f93a5871838a6e1593a913ecc5a7475a5
4
- data.tar.gz: 0a4e4286edcb7319f0002d82388dbfa9c7005ed76d214884af91e8290ff86fe3
3
+ metadata.gz: c1af98988b1c0739296afe5fdcc67174fda97f1bcccfcc3e75adb8a06e3043e3
4
+ data.tar.gz: 9f35640842440b53054d77e8f479010c715218db81f3be35d821bb0567442b95
5
5
  SHA512:
6
- metadata.gz: f754c43ff0f0a815e52b3bb5f80f4962f3c3566262b6f731aed3a1b1237bc73a16824ad68dd795ca5f7f01349030907bba302fb56863de5a2f5d57e0d7b6924f
7
- data.tar.gz: 103a79e48cf54ca69767ae4370cec9810d6d5ca5a2352db28896f6ffd232ca98f426ff87d3b6d748173af97589c211f14347ae59779d0f9e834e0ccc7f6d7852
6
+ metadata.gz: b186be55e37823824fb426d108aa5a4b8df2f2972b7a43e46e021bf33330ec75c89f07b5a6d5d6f3377a57b5d93c59f8cf6f966caf257ca2b1c81d7dfba095c1
7
+ data.tar.gz: 24b6b30334a3f610b95ebe781d9b1993db45e529bc5040174f16728ef05c35df135236296cc2daf67090fdee8dcaa84356341a3c86b4cdc14478e38bc22ae2cb
@@ -1,10 +1,12 @@
1
- sudo: false
2
1
  language: ruby
3
- rvm:
4
- - 2.6.0
5
- - 2.5.1
6
- - 2.4.4
7
- # - 2.3.7
8
- # - 2.2.10
9
- # - 2.1.10
10
2
  before_install: gem install bundler
3
+ cache: bundler
4
+ rvm:
5
+ - ruby-head
6
+ - 2.7
7
+ - 2.6
8
+ - 2.5
9
+ - 2.4
10
+ jobs:
11
+ allow_failures:
12
+ - rvm: ruby-head
data/CHANGES.md CHANGED
@@ -1,6 +1,42 @@
1
+ # 0.11.2
2
+
3
+ * Updrading `trailblazer-context` version :drum:
4
+
5
+ # 0.11.1
6
+
7
+ * Internal warning fixes.
8
+
9
+ # 0.11.0
10
+
11
+ * Support for Ruby 2.7. Most warnings are gone.
12
+
13
+ # 0.10.1
14
+
15
+ * Update IllegalSignalError exception for more clarity
16
+
17
+ # 0.10.0
18
+
19
+ * Require `developer` >= 0.0.7.
20
+ * Move `Activity::Introspect` back to this very gem.
21
+ * This is hopefully the last release before 2.1.0. :trollface:
22
+
23
+ # 0.9.4
24
+
25
+ * Move some test helpers to `Activity::Testing` to export them to other gems
26
+ * Remove introspection modules, it'll also be part of the `Dev` tools now.
27
+ * Remove tracing modules, it'll be part of the `Dev` tools now.
28
+
29
+ # 0.9.3
30
+
31
+ Unreleased.
32
+
33
+ # 0.9.2
34
+
35
+ Unreleased.
36
+
1
37
  # 0.9.1
2
38
 
3
- Use `context-0.9.1`.
39
+ * Use `context-0.9.1`.
4
40
 
5
41
  # 0.9.0
6
42
 
data/Gemfile CHANGED
@@ -6,8 +6,5 @@ gemspec
6
6
  gem "benchmark-ips"
7
7
  gem "minitest-line"
8
8
 
9
- gem "rubocop", require: false
10
-
11
9
  # gem "trailblazer-context", path: "../trailblazer-context"
12
10
  # gem "trailblazer-developer", path: "../trailblazer-developer"
13
- # gem "trailblazer-developer", github: "trailblazer/trailblazer-developer", branch: "exception-tracing"
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2018 Trailblazer GmbH
1
+ Copyright (c) 2018-2020 Trailblazer GmbH
2
2
 
3
3
  Trailblazer is an Open Source project licensed under the terms of
4
4
  the LGPLv3 license. Please see <http://www.gnu.org/licenses/lgpl-3.0.html>
data/README.md CHANGED
@@ -1,22 +1,22 @@
1
1
  # Activity
2
2
 
3
- implements Intermediate, Implementation, compiler and `Activity::Implementation`, Activity::Interface
3
+ Implements Intermediate, Implementation and compiler
4
4
 
5
5
  The `activity` gem brings a light-weight DSL to define business processes, and the runtime logic to run those activities.
6
6
 
7
7
  A process is a set of arbitrary pieces of logic you define, chained together and put into a meaningful context by an activity. Activity lets you focus on the implementation of steps while Trailblazer takes care of the control flow.
8
8
 
9
- Please find the [full documentation on the Trailblazer website](http://trailblazer.to/api-docs). [Note that the docs are WIP.]
9
+ Please find the [full documentation on the Trailblazer website](https://2019.trailblazer.to/2.1/docs/activity.html). [Note that the docs are WIP.]
10
10
 
11
11
  ## Example
12
12
 
13
- The `activity` gem provides three default patterns to model processes: `Path`, `Railway` and `FastTrack`. Here's an example what a railway activity could look like, along with some more complex connections.
13
+ In conjunction with [`dsl-linear`](https://github.com/trailblazer/trailblazer-activity-dsl-linear), the `activity` gem provides three default patterns to model processes: `Path`, `Railway` and `FastTrack`. Here's an example of what a railway activity could look like, along with some more complex connections (you can read more about Railway strategy in the [docs](https://2019.trailblazer.to/2.1/docs/activity.html#activity-strategy-railway)).
14
14
 
15
15
  ```ruby
16
- module Memo::Update
17
- extend Trailblazer::Activity::Railway()
18
- module_function
16
+ require "trailblazer-activity"
17
+ require "trailblazer-activity-dsl-linear"
19
18
 
19
+ class Memo::Update < Trailblazer::Activity::Railway
20
20
  # here goes your business logic
21
21
  #
22
22
  def find_model(ctx, id:, **)
@@ -39,10 +39,10 @@ module Memo::Update
39
39
 
40
40
  # here comes the DSL describing the layout of the activity
41
41
  #
42
- step method(:find_model)
43
- step method(:validate), Output(:failure) => End(:validation_error)
44
- step method(:save)
45
- fail method(:log_error)
42
+ step :find_model
43
+ step :validate, Output(:failure) => End(:validation_error)
44
+ step :save
45
+ fail :log_error
46
46
  end
47
47
  ```
48
48
 
@@ -71,17 +71,22 @@ With Activity, modeling business processes turns out to be ridiculously simple:
71
71
  ## Features
72
72
 
73
73
  * Activities can model any process with arbitrary flow and connections.
74
- * Nesting and compositions are allowed and encouraged.
74
+ * Nesting and compositions are allowed and encouraged (via Trailblazer's [`dsl-linear`](https://github.com/trailblazer/trailblazer-activity-dsl-linear) gem).
75
75
  * Different step interfaces, manual processing of DSL options, etc is all possible.
76
76
  * Steps can be any kind of callable objects.
77
- * Tracing!
77
+ * Tracing! (via Trailblazer's [`developer`](https://github.com/trailblazer/trailblazer-developer) gem)
78
78
 
79
79
  ## Operation
80
80
 
81
- Trailblazer's [`Operation`](http://trailblazer.to/2.1/operation) internally uses an activity to model the processes.
81
+ Trailblazer's [`Operation`](https://2019.trailblazer.to/2.1/docs/operation.html#operation-overview) internally uses an activity to model the processes.
82
+
83
+ ## Workflow
84
+ Activities can be formed into bigger compounds and using workflow, you can build long-running processes such as a moderated blog post or a parcel delivery. Also, you don't have to use the DSL but can use the [`editor`](https://2019.trailblazer.to/2.1/docs/pro.html#pro-editor)instead(cool for more complex, long-running flows). Here comes a sample screenshot.
85
+
86
+ <img src="http://2019.trailblazer.to/2.1/dist/img/flow.png">
82
87
 
83
88
  ## License
84
89
 
85
90
  © Copyright 2018, Trailblazer GmbH
86
91
 
87
- Licensed under the LGPLv3 license. We also offer a [commercial-friendly license](http://trailblazer.to/pro).
92
+ Licensed under the LGPLv3 license. We also offer a commercial-friendly [license](https://2019.trailblazer.to/2.1/docs/pro.html#pro-license).
data/Rakefile CHANGED
@@ -1,13 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
- require "rubocop/rake_task"
4
3
 
5
4
  Rake::TestTask.new(:test) do |t|
6
5
  t.libs << "test"
7
6
  t.libs << "lib"
8
- t.test_files = FileList["**/*_test.rb"] - FileList["test/docs/*"] + ["test/docs/activity_test.rb"]
7
+ t.test_files = FileList["test/**/*_test.rb"] - FileList["test/docs/*"] + ["test/docs/activity_test.rb"]
9
8
  end
10
9
 
11
- RuboCop::RakeTask.new
12
-
13
- task :default => :test
10
+ task default: %i[test]
@@ -7,10 +7,10 @@ module Trailblazer
7
7
  @schema = schema
8
8
  end
9
9
 
10
- def call(args, circuit_options={})
10
+ def call(args, **circuit_options)
11
11
  @schema[:circuit].(
12
12
  args,
13
- circuit_options.merge(activity: self)
13
+ **(circuit_options.merge(activity: self))
14
14
  )
15
15
  end
16
16
 
@@ -34,27 +34,15 @@ module Trailblazer
34
34
  end # Activity
35
35
  end
36
36
 
37
- # require "trailblazer/activity/interface"
38
37
  require "trailblazer/activity/structures"
39
38
  require "trailblazer/activity/schema"
40
- require "trailblazer/activity/schema/implementation"
41
- require "trailblazer/activity/schema/intermediate"
42
39
  require "trailblazer/activity/circuit"
43
40
  require "trailblazer/activity/config"
44
-
41
+ require "trailblazer/activity/introspect"
45
42
  require "trailblazer/activity/task_wrap"
46
- require "trailblazer/activity/task_wrap/pipeline"
47
- require "trailblazer/activity/task_wrap/call_task"
48
- require "trailblazer/activity/task_wrap/runner"
49
- require "trailblazer/activity/task_wrap/variable_mapping"
50
- require "trailblazer/activity/task_wrap/inject"
51
-
52
- require "trailblazer/activity/trace"
53
- require "trailblazer/activity/present"
43
+ require "trailblazer/activity/task_builder"
54
44
 
55
- require "trailblazer/activity/introspect"
56
45
  require "trailblazer/option"
57
46
  require "trailblazer/context"
58
- require "trailblazer/activity/task_builder"
59
47
 
60
48
 
@@ -45,13 +45,22 @@ module Trailblazer
45
45
  last_signal, args, _discarded_circuit_options = runner.(
46
46
  task,
47
47
  args,
48
- circuit_options
48
+ **circuit_options
49
49
  )
50
50
 
51
51
  # Stop execution of the circuit when we hit a stop event (< End). This could be an task's End or Suspend.
52
52
  return [ last_signal, args ] if @stop_events.include?(task) # DISCUSS: return circuit_options here?
53
53
 
54
- task = next_for(task, last_signal) or raise IllegalSignalError.new("<#{@name}>[#{task}][ #{last_signal.inspect} ]")
54
+ if (next_task = next_for(task, last_signal))
55
+ task = next_task
56
+ else
57
+ raise IllegalSignalError.new(
58
+ task,
59
+ signal: last_signal,
60
+ outputs: @map[task],
61
+ exec_context: circuit_options[:exec_context], # passed at run-time from DSL
62
+ )
63
+ end
55
64
  end
56
65
  end
57
66
 
@@ -67,7 +76,26 @@ module Trailblazer
67
76
  outputs[signal]
68
77
  end
69
78
 
79
+ # Common reasons to raise IllegalSignalError are
80
+ # * Returning invalid signal from custom Macros
81
+ # * Returning invalid signal from steps which are not taskWrapped, for example: `step task: method(:validate)`
82
+ #
83
+ # Rest assured, it won't be raised in case of below scenarios where they can return any value,
84
+ # * Steps with instance method signature, for example, `step :load_user`
85
+ # * Steps with proc signature, for example `step ->(ctx, **){}`
70
86
  class IllegalSignalError < RuntimeError
87
+ attr_reader :task, :signal
88
+
89
+ def initialize(task, signal:, outputs:, exec_context:)
90
+ @task = task
91
+ @signal = signal
92
+
93
+ message = "#{exec_context.class}: \n\t" \
94
+ "\sUnrecognized Signal `#{signal.inspect}` returned from #{task.inspect}. Registered signals are, \n" \
95
+ "- #{outputs.keys.join("\n- ")}"
96
+
97
+ super(message)
98
+ end
71
99
  end
72
100
  end
73
101
  end
@@ -28,6 +28,7 @@ module Trailblazer
28
28
 
29
29
  return state[directive] if args.size == 1
30
30
  return state[directive][key] if state.key?(directive)
31
+
31
32
  nil
32
33
  end
33
34
  end
@@ -4,10 +4,6 @@ module Trailblazer
4
4
  # It abstracts internals about circuits and provides a convenient API to third-parties such as
5
5
  # tracing, rendering an activity, or finding particular tasks.
6
6
  module Introspect
7
- def self.Graph(*args)
8
- Graph.new(*args)
9
- end
10
-
11
7
  # TODO: order of step/fail/pass in Node would be cool to have
12
8
 
13
9
  # @private This API is still under construction.
@@ -20,13 +16,14 @@ module Trailblazer
20
16
  @configs = @schema[:nodes]
21
17
  end
22
18
 
23
- def find(id=nil, &block)
19
+ def find(id = nil, &block)
24
20
  return find_by_id(id) unless block_given?
21
+
25
22
  find_with_block(&block)
26
23
  end
27
24
 
28
- def collect(strategy: :circuit, &block)
29
- @map.keys.each_with_index.collect { |task, i| yield find_with_block { |node| node.task==task }, i }
25
+ def collect(strategy: :circuit)
26
+ @map.keys.each_with_index.collect { |task, i| yield find_with_block { |node| node.task == task }, i }
30
27
  end
31
28
 
32
29
  def stop_events
@@ -36,11 +33,11 @@ module Trailblazer
36
33
  private
37
34
 
38
35
  def find_by_id(id)
39
- node = @configs.find { |node| node.id == id } or return
36
+ node = @configs.find { |_node| _node.id == id } or return
40
37
  node_for(node)
41
38
  end
42
39
 
43
- def find_with_block(&block)
40
+ def find_with_block
44
41
  existing = @configs.find { |node| yield Node(node.task, node.id, node.outputs, node.data) } or return
45
42
 
46
43
  node_for(existing)
@@ -67,6 +64,10 @@ module Trailblazer
67
64
  end
68
65
  end
69
66
  end
70
- end #Introspect
67
+
68
+ def self.Graph(*args)
69
+ Graph.new(*args)
70
+ end
71
+ end # Introspect
71
72
  end
72
73
  end
@@ -11,3 +11,5 @@ module Trailblazer
11
11
  end # Schema
12
12
  end
13
13
  end
14
+ require "trailblazer/activity/schema/implementation"
15
+ require "trailblazer/activity/schema/intermediate"
@@ -20,7 +20,7 @@ class Trailblazer::Activity
20
20
  nodes = node_attributes(intermediate, implementation)
21
21
  outputs = outputs(intermediate.stop_task_ids, nodes)
22
22
  config = config(implementation, config: config_default)
23
- schema = Schema.new(circuit, outputs, nodes, config)
23
+ Schema.new(circuit, outputs, nodes, config)
24
24
  end
25
25
 
26
26
  # From the intermediate "template" and the actual implementation, compile a {Circuit} instance.
@@ -83,10 +83,10 @@ class Trailblazer::Activity
83
83
  config
84
84
  end
85
85
 
86
- private
86
+
87
87
 
88
88
  # Apply to any array.
89
- def self.for_semantic(outputs, semantic)
89
+ private_class_method def self.for_semantic(outputs, semantic)
90
90
  outputs.find { |out| out.semantic == semantic } or raise "`#{semantic}` not found"
91
91
  end
92
92
  end # Intermediate
@@ -2,13 +2,7 @@ module Trailblazer
2
2
  class Activity
3
3
  # Generic run-time structures that are built via the DSL.
4
4
 
5
- # Builds an {Activity::End} instance.
6
- def self.End(semantic)
7
- End.new(semantic: semantic)
8
- end
9
-
10
5
  # Any instance of subclass of End will halt the circuit's execution when hit.
11
-
12
6
  # An End event is a simple structure typically found as the last task invoked
13
7
  # in an activity. The special behavior is that it
14
8
  # a) maintains a semantic that is used to further connect that very event
@@ -18,8 +12,8 @@ module Trailblazer
18
12
  @options = options.merge(semantic: semantic)
19
13
  end
20
14
 
21
- def call(args, circuit_options)
22
- return self, args, circuit_options
15
+ def call(args, **circuit_options)
16
+ return self, args, **circuit_options
23
17
  end
24
18
 
25
19
  def to_h
@@ -27,15 +21,15 @@ module Trailblazer
27
21
  end
28
22
 
29
23
  def to_s
30
- %{#<#{self.class.name} #{@options.collect{ |k,v| "#{k}=#{v.inspect}" }.join(" ")}>}
24
+ %{#<#{self.class.name} #{@options.collect { |k, v| "#{k}=#{v.inspect}" }.join(" ")}>}
31
25
  end
32
26
 
33
- alias_method :inspect, :to_s
27
+ alias inspect to_s
34
28
  end
35
29
 
36
30
  class Start < End
37
- def call(args, circuit_options)
38
- return Activity::Right, args, circuit_options
31
+ def call(args, **circuit_options)
32
+ return Activity::Right, args, **circuit_options
39
33
  end
40
34
  end
41
35
 
@@ -53,5 +47,10 @@ module Trailblazer
53
47
  def self.Output(signal, semantic)
54
48
  Output.new(signal, semantic).freeze
55
49
  end
50
+
51
+ # Builds an {Activity::End} instance.
52
+ def self.End(semantic)
53
+ End.new(semantic: semantic)
54
+ end
56
55
  end
57
56
  end
@@ -11,7 +11,11 @@ module Trailblazer
11
11
  # Translates the return value of the user step into a valid signal.
12
12
  # Note that it passes through subclasses of {Signal}.
13
13
  def self.binary_signal_for(result, on_true, on_false)
14
- result.is_a?(Class) && result < Activity::Signal ? result : (result ? on_true : on_false)
14
+ if result.is_a?(Class) && result < Activity::Signal
15
+ result
16
+ else
17
+ result ? on_true : on_false
18
+ end
15
19
  end
16
20
 
17
21
  class Task
@@ -3,12 +3,12 @@ module Trailblazer
3
3
  #
4
4
  # Example with tracing:
5
5
  #
6
- # Call the task_wrap circuit:
7
- # |-- Start
8
- # |-- Trace.capture_args [optional]
9
- # |-- Call (call actual task) id: "task_wrap.call_task"
10
- # |-- Trace.capture_return [optional]
11
- # |-- Wrap::End
6
+ # Call the task_wrap circuit:
7
+ # |-- Start
8
+ # |-- Trace.capture_args [optional]
9
+ # |-- Call (call actual task) id: "task_wrap.call_task"
10
+ # |-- Trace.capture_return [optional]
11
+ # |-- Wrap::End
12
12
  module TaskWrap
13
13
  module_function
14
14
 
@@ -21,7 +21,7 @@ module Trailblazer
21
21
  )
22
22
 
23
23
  # signal, (ctx, flow), circuit_options =
24
- Runner.(activity, args, circuit_options)
24
+ Runner.(activity, args, **circuit_options)
25
25
  end
26
26
 
27
27
  # {:extension} API
@@ -29,7 +29,8 @@ module Trailblazer
29
29
  # Gets executed in {Intermediate.call} which also provides {config}.
30
30
 
31
31
  def initial_wrap_static(*)
32
- initial_sequence = TaskWrap::Pipeline.new([["task_wrap.call_task", TaskWrap.method(:call_task)]])
32
+ # return initial_sequence
33
+ TaskWrap::Pipeline.new([["task_wrap.call_task", TaskWrap.method(:call_task)]])
33
34
  end
34
35
 
35
36
  # Use this in your macros if you want to extend the {taskWrap}.
@@ -51,3 +52,8 @@ module Trailblazer
51
52
  end # TaskWrap
52
53
  end
53
54
  end
55
+ require "trailblazer/activity/task_wrap/pipeline"
56
+ require "trailblazer/activity/task_wrap/call_task"
57
+ require "trailblazer/activity/task_wrap/runner"
58
+ require "trailblazer/activity/task_wrap/variable_mapping"
59
+ require "trailblazer/activity/task_wrap/inject"