trailblazer-developer 0.0.8 → 0.0.13

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
  SHA256:
3
- metadata.gz: 4ca80026aa28f6e54a1a4b97e9efd20408cacdf0e5b80528856ffffa7ac29870
4
- data.tar.gz: '069c09bff5551db399917d7e4c97a3d9698d281bb2d4efe3b9961f4daab13277'
3
+ metadata.gz: dcc1a32164a4c3e26c3d72450e416d8c3259002f2ce94782c808e4c041cb7847
4
+ data.tar.gz: fb0bede8fcfed4c533dec425f9f92b8188fd4df6ce82c39543d21d7440b7c1fc
5
5
  SHA512:
6
- metadata.gz: 04c2f24488f25194553750235358290248ffd041df2d75ce839a78df28bccef2630ae7501756225ef597f1a97588a2ac98cdd80184d5080cddcc345141410452
7
- data.tar.gz: 31dfb2eac96ee7b0fa29339ed350ffcdb77297ca4b605ac8f1ac1297f4e05bbf7f126e559f312719590397bb421cd17f2e14dcfe0cbba41656732df0acbe5351
6
+ metadata.gz: d6661e0492929cf37bbf40afbbd61d79308f113005040a61515801d72b7731adce960245d618ccb5a7db4903e082f5ae1b2a60fe139006f978e4f13ab02cf4a7
7
+ data.tar.gz: b7b1581c7733ca0066eafb8877c06d9ca7175854c56d8fa62509f384881c772a84b7dce4ba4dacd547710d4a3c1ed04da9dc9d15f7571e8852fb8c11778d4f35
data/README.md CHANGED
@@ -4,7 +4,7 @@ _Developer tools for Trailblazers._
4
4
 
5
5
  ## Documentation
6
6
 
7
- Find the complete documentation on the project website: [http://trb.to/2.1#developer]
7
+ Find the complete documentation on the project website: [http://2019.trailblazer.to/2.1/docs/developer.html]
8
8
 
9
9
  ## Summary
10
10
 
@@ -7,8 +7,11 @@ module Trailblazer
7
7
  end
8
8
 
9
9
  require "trailblazer/developer/wtf"
10
+ require "trailblazer/developer/wtf/renderer"
10
11
  require "trailblazer/developer/trace"
11
12
  require "trailblazer/developer/trace/present"
13
+ require "trailblazer/developer/trace/focusable"
14
+ require "trailblazer/developer/trace/inspector"
12
15
  require "trailblazer/developer/generate"
13
16
  require "trailblazer/developer/render/circuit"
14
17
  require "trailblazer/developer/render/linear"
@@ -1,3 +1,27 @@
1
+ # 0.0.13
2
+
3
+ * Allow focusing on selected variables for all steps in wtf
4
+ * Fix declarative deprecation warning
5
+
6
+ # 0.0.12
7
+
8
+ * Revert Hash#compact usage to support Rubies <= 2.4
9
+
10
+ # 0.0.11
11
+
12
+ * Allow injecting custom data collector in Trace API, to collect custom input/output ctx of task nodes.
13
+ * Allow focusing on specfic steps and ctx variables in Dev.wtf?
14
+ * Allow custom inspection while tracing using Inspector definations
15
+
16
+ # 0.0.10
17
+
18
+ * Make Generate::Pipeline an activity for better customization/extendability.
19
+
20
+ # 0.0.9
21
+
22
+ * `Render.strip` is now a class method.
23
+ * Added the `.type` field to the `data` field in `Generate`.
24
+
1
25
  # 0.0.8
2
26
 
3
27
  * Fix `Introspect` references.
@@ -1,4 +1,5 @@
1
1
  require "representable/hash"
2
+ require "trailblazer/activity/dsl/linear" # Railway.
2
3
 
3
4
  module Trailblazer
4
5
  module Developer
@@ -16,7 +17,7 @@ module Trailblazer
16
17
  collection :elements, class: Element do
17
18
  property :id
18
19
  property :type
19
- collection :linksTo, class: Arrow, default: [] do
20
+ collection :linksTo, class: Arrow, default: -> { [] } do
20
21
  property :target
21
22
  property :label
22
23
  property :message
@@ -30,26 +31,27 @@ module Trailblazer
30
31
  end
31
32
 
32
33
  def call(hash)
33
- elements = transform_from_hash(hash)
34
-
35
- compute_intermediate(elements)
34
+ signal, (ctx, _) = Activity::TaskWrap.invoke(Pipeline, hash: hash)
35
+ ctx[:intermediate]
36
36
  end
37
37
 
38
- def transform_from_hash(hash, parser: Representer::Activity)
39
- parser.new(OpenStruct.new).from_hash(hash).elements
38
+ def transform_from_hash(ctx, hash:, parser: Representer::Activity, **)
39
+ ctx[:elements] = parser.new(OpenStruct.new).from_hash(hash).elements
40
40
  end
41
41
 
42
- def find_start_events(elements)
43
- elements.find_all { |el| el.type == "Event" }
42
+ def find_start_events(ctx, elements:, **)
43
+ ctx[:start_events] = elements.find_all { |el| el.type == "Event" }
44
44
  end
45
45
 
46
- def compute_intermediate(elements, find_start_events: method(:find_start_events))
47
- start_events = find_start_events.(elements)
46
+ def compute_intermediate(ctx, elements:, start_events:, **)
48
47
  end_events = elements.find_all { |el| el.type == "EndEventTerminate" } # DISCUSS: is it really called TERMINATE?
49
48
 
50
49
  inter = Activity::Schema::Intermediate
51
50
 
52
- wiring = elements.collect { |el| [inter.TaskRef(el.id, el.data), el.linksTo.collect { |arrow| inter.Out(semantic_for(arrow.to_h), arrow.target) } ] }
51
+ wiring = elements.collect { |el|
52
+ data = data_for(el)
53
+
54
+ [inter.TaskRef(el.id, data), el.linksTo.collect { |arrow| inter.Out(semantic_for(arrow.to_h), arrow.target) } ] }
53
55
  wiring = Hash[wiring]
54
56
 
55
57
  # end events need this stupid special handling
@@ -63,11 +65,15 @@ module Trailblazer
63
65
  ])
64
66
  # pp wiring
65
67
 
66
- inter.new(wiring, end_events.collect(&:id), start_events.collect(&:id))
68
+ ctx[:intermediate] = inter.new(wiring, end_events.collect(&:id), start_events.collect(&:id))
67
69
  end
68
70
 
69
71
  # private
70
72
 
73
+ def data_for(element)
74
+ {type: element.type}.merge(element.data)
75
+ end
76
+
71
77
  # We currently use the {:label} field of an arrow to encode an output semantic.
72
78
  # The {:symbol_style} part will be filtered out as semantic. Defaults to {:success}.
73
79
  def semantic_for(label:nil, **)
@@ -79,6 +85,12 @@ module Trailblazer
79
85
  def extract_semantic(label)
80
86
  label.to_sym
81
87
  end
88
+
89
+ class Pipeline < Trailblazer::Activity::Railway
90
+ step Generate.method(:transform_from_hash), id: :transform_from_hash
91
+ step Generate.method(:find_start_events), id: :find_start_events
92
+ step Generate.method(:compute_intermediate), id: :compute_intermediate
93
+ end
82
94
  end
83
95
  end
84
96
  end
@@ -42,13 +42,13 @@ module Trailblazer
42
42
  end
43
43
 
44
44
  def inspect_end(task)
45
- class_name = strip(task.class)
45
+ class_name = Render::Circuit.strip(task.class)
46
46
  options = task.to_h
47
47
 
48
48
  "#<#{class_name}/#{options[:semantic].inspect}>"
49
49
  end
50
50
 
51
- def strip(string)
51
+ def self.strip(string)
52
52
  string.to_s.sub("Trailblazer::Activity::", "")
53
53
  end
54
54
  end
@@ -17,16 +17,23 @@ module Trailblazer::Developer
17
17
 
18
18
  alias_method :invoke, :call
19
19
 
20
- def arguments_for_call(activity, (options, flow_options), **circuit_options)
21
- tracing_flow_options = {
20
+ def arguments_for_call(activity, (options, original_flow_options), **original_circuit_options)
21
+ default_flow_options = {
22
22
  stack: Trace::Stack.new,
23
+
24
+ input_data_collector: Trace.method(:default_input_data_collector),
25
+ output_data_collector: Trace.method(:default_output_data_collector),
23
26
  }
24
27
 
25
- tracing_circuit_options = {
28
+ flow_options = { **default_flow_options, **Hash( original_flow_options ) }
29
+
30
+ default_circuit_options = {
26
31
  wrap_runtime: ::Hash.new(Trace.merge_plan), # DISCUSS: this overrides existing {:wrap_runtime}.
27
32
  }
28
33
 
29
- return activity, [ options, tracing_flow_options.merge(flow_options) ], circuit_options.merge(tracing_circuit_options)
34
+ circuit_options = { **original_circuit_options, **default_circuit_options }
35
+
36
+ return activity, [ options, flow_options ], circuit_options
30
37
  end
31
38
  end
32
39
 
@@ -42,38 +49,45 @@ module Trailblazer::Developer
42
49
  )
43
50
  end
44
51
 
52
+ # It's important to understand that {flow[:stack]} is mutated by design. This is needed so
53
+ # in case of exceptions we still have a "global" trace - unfortunately Ruby doesn't allow
54
+ # us a better way.
45
55
  # taskWrap step to capture incoming arguments of a step.
46
- def capture_args(wrap_config, original_args)
47
- original_args = capture_for(wrap_config[:task], *original_args)
56
+ def capture_args(wrap_config, ((ctx, flow), circuit_options))
57
+ flow[:stack].indent!
48
58
 
49
- return wrap_config, original_args
59
+ flow[:stack] << Entity::Input.new(
60
+ wrap_config[:task],
61
+ circuit_options[:activity],
62
+ flow[:input_data_collector].call(wrap_config, [ctx, flow], circuit_options)
63
+ ).freeze
64
+
65
+ return wrap_config, [[ctx, flow], circuit_options]
50
66
  end
51
67
 
52
68
  # taskWrap step to capture outgoing arguments from a step.
53
- def capture_return(wrap_config, original_args)
54
- (original_options, original_flow_options, _) = original_args[0]
55
-
56
- original_flow_options[:stack] << Entity::Output.new(
57
- wrap_config[:task], {}, wrap_config[:return_signal]
69
+ def capture_return(wrap_config, ((ctx, flow), circuit_options))
70
+ flow[:stack] << Entity::Output.new(
71
+ wrap_config[:task],
72
+ {},
73
+ flow[:output_data_collector].call(wrap_config, [ctx, flow], circuit_options)
58
74
  ).freeze
59
75
 
60
- original_flow_options[:stack].unindent!
76
+ flow[:stack].unindent!
61
77
 
62
-
63
- return wrap_config, original_args
78
+ return wrap_config, [[ctx, flow], circuit_options]
64
79
  end
65
80
 
66
- # It's important to understand that {flow[:stack]} is mutated by design. This is needed so
67
- # in case of exceptions we still have a "global" trace - unfortunately Ruby doesn't allow
68
- # us a better way.
69
- def capture_for(task, (ctx, flow), activity:, **circuit_options)
70
- flow[:stack].indent!
81
+ def default_input_data_collector(wrap_config, (ctx, _), circuit_options)
82
+ graph = Trailblazer::Activity::Introspect::Graph(circuit_options[:activity])
83
+ task = wrap_config[:task]
84
+ name = (node = graph.find { |node| node[:task] == task }) ? node[:id] : task
71
85
 
72
- flow[:stack] << Entity::Input.new(
73
- task, activity, [ctx, ctx.inspect]
74
- ).freeze
86
+ { ctx: ctx, task_name: name }
87
+ end
75
88
 
76
- return [ctx, flow], circuit_options.merge(activity: activity)
89
+ def default_output_data_collector(wrap_config, (ctx, _), _)
90
+ { ctx: ctx, signal: wrap_config[:return_signal] }
77
91
  end
78
92
 
79
93
  # Structures used in {capture_args} and {capture_return}.
@@ -115,6 +129,8 @@ module Trailblazer::Developer
115
129
 
116
130
  # Mutable/stateful per design. We want a (global) stack!
117
131
  class Stack
132
+ attr_reader :top
133
+
118
134
  def initialize
119
135
  @nested = Level.new
120
136
  @stack = [ @nested ]
@@ -129,8 +145,10 @@ module Trailblazer::Developer
129
145
  @stack.pop
130
146
  end
131
147
 
132
- def <<(args)
133
- current << args
148
+ def <<(entity)
149
+ @top = entity
150
+
151
+ current << entity
134
152
  end
135
153
 
136
154
  def to_a
@@ -0,0 +1,80 @@
1
+ require 'hirb'
2
+
3
+ module Trailblazer
4
+ module Developer
5
+ module Trace
6
+
7
+ module Focusable
8
+ module_function
9
+
10
+ # Get inspect of {focus_on.variables} or current {ctx}
11
+ def capture_variables_from(ctx, focus_on:, inspector: Trace::Inspector, **flow_options)
12
+ # ctx keys to be captured, for example [:current_user, :model, ....]
13
+ variables = (selected = focus_on[:variables]).any? ? selected : ctx.keys
14
+
15
+ variables.each_with_object({}) do |variable, result|
16
+ if variable.is_a?(Proc) # To allow deep key access from ctx
17
+ result[:Custom] = inspector.(variable.call(ctx), **flow_options)
18
+ else
19
+ result[variable] = inspector.(ctx[variable], **flow_options)
20
+ end
21
+ end
22
+ end
23
+
24
+ # Generate Hirb's vertical table nodes from captured ctx of each step
25
+ # |-- some step name
26
+ # | |-- ********** Input **********
27
+ # message: "WTF!"
28
+ # seq: []
29
+ # | `-- ********** Output **********
30
+ # message: "WTF!"
31
+ # seq: [:a]
32
+ def tree_nodes_for(level, input:, output:, **options)
33
+ # TODO: Reverting `Hash#compact` usage as it is not supported in Ruby <= 2.4
34
+ # Once the support is droped, revert actual code with below and remove entity check.
35
+ # input_output_nodes = { Input: input, Output: output }.compact.collect do |table_header, entity|
36
+
37
+ input_output_nodes = { Input: input, Output: output }.collect do |table_header, entity|
38
+ next unless entity
39
+ next unless Array( entity.data[:focused_variables] ).any?
40
+
41
+ table = vertical_table_for(entity.data[:focused_variables], table_header: table_header)
42
+ Present::TreeNodes::Node.new(level + 1, table, input, output, options).freeze
43
+ end
44
+
45
+ input_output_nodes.compact
46
+ end
47
+
48
+ # @private
49
+ def vertical_table_for(focused_variables, table_header:)
50
+ patched_vertical_table.render(
51
+ Array[ focused_variables ],
52
+ description: nil,
53
+ table_header: table_header, # Custom option, not from Hirb
54
+ )
55
+ end
56
+
57
+ # Overrding `Hirb::Helpers::VerticalTable#render_rows` because there is no option
58
+ # to customize vertical table's row header :(
59
+ # We need it to print if given entity is Input/Output
60
+ #
61
+ # @private
62
+ def patched_vertical_table
63
+ table = Class.new(Hirb::Helpers::VerticalTable)
64
+
65
+ table.send(:define_method, :render_rows) do
66
+ longest_header = Hirb::String.size (@headers.values.sort_by {|e| Hirb::String.size(e) }.last || '')
67
+ stars = "*" * [(longest_header + (longest_header / 2)), 3].max
68
+
69
+ @rows.map do |row|
70
+ "#{stars} #{@options[:table_header]} #{stars}\n" +
71
+ @fields.map{ |f| "#{Hirb::String.rjust(@headers[f], longest_header)}: #{row[f]}" }.join("\n")
72
+ end
73
+ end
74
+
75
+ table
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,48 @@
1
+ module Trailblazer
2
+ module Developer
3
+ module Trace
4
+
5
+ # This module does the inspection of given `ctx` with deep traversal.
6
+ # It only gets called when focusing is going on (i.e. focus_on API).
7
+ module Inspector
8
+ module_function
9
+
10
+ def call(value, default_inspector: method(:default_inspector), **)
11
+ return hash_inspector(value, default_inspector: default_inspector) if value.is_a?(Hash)
12
+ return array_inspector(value, default_inspector: default_inspector) if value.is_a?(Array)
13
+
14
+ default_inspector.(value)
15
+ end
16
+
17
+ def hash_inspector(value, default_inspector:)
18
+ Hash[
19
+ value.collect do |key, nested_value|
20
+ [key, call(nested_value, default_inspector: default_inspector)]
21
+ end
22
+ ]
23
+ end
24
+
25
+ def array_inspector(value, default_inspector:)
26
+ value.collect do |nested_value|
27
+ call(nested_value, default_inspector: default_inspector)
28
+ end
29
+ end
30
+
31
+ # To avoid additional query that AR::Relation#inspect makes,
32
+ # we're calling AR::Relation#to_sql to get plain SQL string instead.
33
+ def activerecord_relation_inspector(value)
34
+ { query: value.to_sql }
35
+ end
36
+
37
+ def default_inspector(value)
38
+ if defined?(ActiveRecord) && value.is_a?(ActiveRecord::Relation)
39
+ return activerecord_relation_inspector(value)
40
+ end
41
+
42
+ value.inspect
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -1,15 +1,12 @@
1
- require 'trailblazer/activity'
1
+ require 'hirb'
2
2
 
3
3
  module Trailblazer::Developer
4
4
  module Trace
5
5
  module Present
6
6
  module_function
7
7
 
8
- INDENTATION = " |".freeze
9
- STEP_PREFIX = "-- ".freeze
10
-
11
8
  def default_renderer(task_node:, **)
12
- [ task_node[:level], %{#{task_node[:name]}} ]
9
+ [ task_node.level, %{#{task_node.value}} ]
13
10
  end
14
11
 
15
12
  def call(stack, level: 1, tree: [], renderer: method(:default_renderer), **options)
@@ -23,29 +20,14 @@ module Trailblazer::Developer
23
20
  renderer.(task_node: task_node, position: position, tree: tree)
24
21
  end
25
22
 
26
- render_tree_for(nodes)
27
- end
28
-
29
- def render_tree_for(nodes)
30
- nodes.map { |level, node|
31
- indentation = INDENTATION * (level -1)
32
- indentation = indentation[0...-1] + "`" if level == 1 || /End./.match(node) # start or end step
33
- indentation + STEP_PREFIX + node
34
- }.join("\n")
23
+ Hirb::Console.format_output(nodes, class: :tree, type: :directory, multi_line_nodes: true)
35
24
  end
36
25
 
37
26
  def tree_for(stack, level, tree:, **options)
38
27
  stack.each do |lvl| # always a Stack::Task[input, ..., output]
39
28
  input, output, nested = Trace::Level.input_output_nested_for_level(lvl)
40
29
 
41
- task = input.task
42
-
43
- graph = Trailblazer::Activity::Introspect::Graph(input.activity)
44
-
45
- name = (node = graph.find { |node| node[:task] == task }) ? node[:id] : task
46
- name ||= task # FIXME: bullshit
47
-
48
- tree << { level: level, input: input, output: output, name: name, **options }
30
+ tree.push(*TreeNodes.for(level, options.merge(input: input, output: output)))
49
31
 
50
32
  if nested.any? # nesting
51
33
  tree_for(nested, level + 1, options.merge(tree: tree))
@@ -54,6 +36,26 @@ module Trailblazer::Developer
54
36
  tree
55
37
  end
56
38
  end
39
+
40
+ module TreeNodes
41
+ Node = Struct.new(:level, :value, :input, :output, :options) do
42
+ # Allow access to any custom key from options, eg. color_map
43
+ def method_missing(name, *)
44
+ options[name]
45
+ end
46
+ end
47
+
48
+ module_function
49
+
50
+ def for(level, input:, output:, **options)
51
+ nodes = Array[ Node.new(level, input.data[:task_name], input, output, options).freeze ]
52
+
53
+ focused_nodes = Trace::Focusable.tree_nodes_for(level, input: input, output: output, **options)
54
+ nodes += focused_nodes if focused_nodes.length > 0
55
+
56
+ nodes
57
+ end
58
+ end
57
59
  end
58
60
  end
59
61
  end
@@ -1,7 +1,7 @@
1
1
  module Trailblazer
2
2
  module Version
3
3
  module Developer
4
- VERSION = "0.0.8"
4
+ VERSION = "0.0.13"
5
5
  end
6
6
  end
7
7
  end
@@ -12,95 +12,78 @@ module Trailblazer::Developer
12
12
  module Wtf
13
13
  module_function
14
14
 
15
- COLOR_MAP = { pass: :green, fail: :brown }
16
-
17
- SIGNALS_MAP = {
18
- 'Trailblazer::Activity::Right': :pass,
19
- 'Trailblazer::Activity::FastTrack::PassFast': :pass,
20
-
21
- 'Trailblazer::Activity::Left': :fail,
22
- 'Trailblazer::Activity::FastTrack::FailFast': :fail,
23
- }
24
-
25
15
  # Run {activity} with tracing enabled and inject a mutable {Stack} instance.
26
16
  # This allows to display the trace even when an exception happened
27
- def invoke(activity, (ctx, flow_options), *args)
28
- flow_options ||= {} # Ruby sucks.
29
-
30
- # this instance gets mutated with every step. unfortunately, there is
31
- # no other way in Ruby to keep the trace even when an exception was thrown.
32
- stack = Trace::Stack.new
33
-
34
- _returned_stack, *returned = Trace.invoke(
35
- activity,
36
- [
37
- ctx,
38
- flow_options.merge(stack: stack)
39
- ],
40
- *args
17
+ def invoke(activity, (ctx, flow_options), *circuit_options)
18
+ activity, (ctx, flow_options), circuit_options = Wtf.arguments_for_trace(
19
+ activity, [ctx, flow_options], *circuit_options
41
20
  )
42
21
 
43
- returned
22
+ _returned_stack, signal, (ctx, flow_options) = Trace.invoke(
23
+ activity, [ctx, flow_options], *circuit_options
24
+ )
25
+
26
+ return signal, [ctx, flow_options], circuit_options
44
27
  ensure
45
28
  puts Trace::Present.(
46
- stack,
47
- renderer: method(:renderer),
48
- color_map: COLOR_MAP.merge( flow_options[:color_map] || {} )
29
+ flow_options[:stack],
30
+ renderer: Wtf::Renderer,
31
+ color_map: Wtf::Renderer::DEFAULT_COLOR_MAP.merge( flow_options[:color_map] || {} ),
49
32
  )
50
33
  end
51
34
 
52
- def renderer(task_node:, position:, tree:)
53
- name, level, output, color_map = task_node.values_at(:name, :level, :output, :color_map)
35
+ def arguments_for_trace(activity, (ctx, original_flow_options), **circuit_options)
36
+ default_flow_options = {
37
+ # this instance gets mutated with every step. unfortunately, there is
38
+ # no other way in Ruby to keep the trace even when an exception was thrown.
39
+ stack: Trace::Stack.new,
54
40
 
55
- if output.nil? && tree[position.next].nil? # i.e. when exception raised
56
- return [ level, %{#{fmt(fmt(name, :red), :bold)}} ]
57
- end
41
+ input_data_collector: method(:trace_input_data_collector),
42
+ output_data_collector: method(:trace_output_data_collector),
43
+ }
58
44
 
59
- if output.nil? # i.e. on entry/exit point of activity
60
- return [ level, %{#{name}} ]
61
- end
45
+ # Merge default options with flow_options as an order of precedence
46
+ flow_options = { **default_flow_options, **Hash( original_flow_options ) }
62
47
 
63
- [ level, %{#{fmt( name, color_map[ signal_of(output.data) ] )}} ]
48
+ # Normalize `focus_on` param to
49
+ # 1. Wrap step and variable names into an array if not already
50
+ flow_options[:focus_on] = {
51
+ steps: Array( flow_options.dig(:focus_on, :steps) ),
52
+ variables: Array( flow_options.dig(:focus_on, :variables) ),
53
+ }
54
+
55
+ return activity, [ ctx, flow_options ], circuit_options
64
56
  end
65
57
 
66
- def fmt(line, style)
67
- return line unless style
68
- String.send(style, line)
58
+ # Overring default input and output data collectors to collect/capture
59
+ # 1. inspect of focusable variables for given focusable step
60
+ # 2. Or inspect of focused variables for all steps
61
+ def trace_input_data_collector(wrap_config, (ctx, flow_options), circuit_options)
62
+ data = Trace.default_input_data_collector(wrap_config, [ctx, flow_options], circuit_options)
63
+
64
+ if Wtf.caputure_variables?(step_name: data[:task_name], **flow_options)
65
+ data[:focused_variables] = Trace::Focusable.capture_variables_from(ctx, **flow_options)
66
+ end
67
+
68
+ data
69
69
  end
70
70
 
71
- def signal_of(entity_output)
72
- entity_klass = entity_output.is_a?(Class) ? entity_output : entity_output.class
73
- SIGNALS_MAP[entity_klass.name.to_sym]
71
+ def trace_output_data_collector(wrap_config, (ctx, flow_options), circuit_options)
72
+ data = Trace.default_output_data_collector(wrap_config, [ctx, flow_options], circuit_options)
73
+ input = flow_options[:stack].top
74
+
75
+ if Wtf.caputure_variables?(step_name: input.data[:task_name], **flow_options)
76
+ data[:focused_variables] = Trace::Focusable.capture_variables_from(ctx, **flow_options)
77
+ end
78
+
79
+ data
74
80
  end
75
81
 
76
- # Stolen from https://stackoverflow.com/questions/1489183/colorized-ruby-output
77
- #
78
- # TODO: this is just prototyping
79
- module String
80
- module_function
81
- def black(str); "\e[30m#{str}\e[0m" end
82
- def red(str); "\e[31m#{str}\e[0m" end
83
- def green(str); "\e[32m#{str}\e[0m" end
84
- def brown(str); "\e[33m#{str}\e[0m" end
85
- def blue(str); "\e[34m#{str}\e[0m" end
86
- def magenta(str); "\e[35m#{str}\e[0m" end
87
- def cyan(str); "\e[36m#{str}\e[0m" end
88
- def gray(str); "\e[37m#{str}\e[0m" end
89
-
90
- def bg_black(str); "\e[40m#{str}\e[0m" end
91
- def bg_red(str); "\e[41m#{str}\e[0m" end
92
- def bg_green(str); "\e[42m#{str}\e[0m" end
93
- def bg_brown(str); "\e[43m#{str}\e[0m" end
94
- def bg_blue(str); "\e[44m#{str}\e[0m" end
95
- def bg_magenta(str); "\e[45m#{str}\e[0m" end
96
- def bg_cyan(str); "\e[46m#{str}\e[0m" end
97
- def bg_gray(str); "\e[47m#{str}\e[0m" end
98
-
99
- def bold(str); "\e[1m#{str}\e[22m" end
100
- def italic(str); "\e[3m#{str}\e[23m" end
101
- def underline(str); "\e[4m#{str}\e[24m" end
102
- def blink(str); "\e[5m#{str}\e[25m" end
103
- def reverse_color(str); "\e[7m#{str}\e[27m" end
82
+ # private
83
+ def caputure_variables?(step_name:, focus_on:, **)
84
+ return true if focus_on[:steps].include?(step_name) # For given step
85
+ return true if focus_on[:steps].empty? && focus_on[:variables].any? # For selected vars but all steps
86
+ return false
104
87
  end
105
88
  end
106
89
  end
@@ -0,0 +1,78 @@
1
+ module Trailblazer::Developer
2
+ module Wtf
3
+
4
+ module Renderer
5
+ DEFAULT_COLOR_MAP = { pass: :green, fail: :brown }
6
+
7
+ SIGNALS_MAP = {
8
+ :'Trailblazer::Activity::Right' => :pass,
9
+ :'Trailblazer::Activity::FastTrack::PassFast' => :pass,
10
+
11
+ :'Trailblazer::Activity::Left' => :fail,
12
+ :'Trailblazer::Activity::FastTrack::FailFast' => :fail,
13
+ }
14
+
15
+ module_function
16
+
17
+ # tree: Array of Trace::TreeNodes::Node
18
+ # task_node - current Trace::TreeNodes::Node to render
19
+ # position - task_node's position in tree
20
+ def call(tree:, task_node:, position:)
21
+ value = value_for(tree, task_node, position)
22
+ [task_node.level, value]
23
+ end
24
+
25
+ def value_for(tree, task_node, position)
26
+ if task_node.output.nil? && tree[position.next].nil? # i.e. when exception raised
27
+ return %{#{fmt(fmt(task_node.value, :red), :bold)}}
28
+ end
29
+
30
+ if task_node.output.nil? # i.e. on entry/exit point of activity
31
+ return %{#{task_node.value}}
32
+ end
33
+
34
+ %{#{fmt(task_node.value, task_node.color_map[ signal_of(task_node) ])}}
35
+ end
36
+
37
+ def fmt(line, style)
38
+ return line unless style
39
+ String.send(style, line)
40
+ end
41
+
42
+ def signal_of(task_node)
43
+ entity_signal = task_node.output.data[:signal]
44
+ entity_klass = entity_signal.is_a?(Class) ? entity_signal : entity_signal.class
45
+
46
+ SIGNALS_MAP[entity_klass.name.to_sym]
47
+ end
48
+
49
+ # Stolen from https://stackoverflow.com/questions/1489183/colorized-ruby-output
50
+ #
51
+ # TODO: this is just prototyping
52
+ module String
53
+ module_function
54
+ def black(str); "\e[30m#{str}\e[0m" end
55
+ def red(str); "\e[31m#{str}\e[0m" end
56
+ def green(str); "\e[32m#{str}\e[0m" end
57
+ def brown(str); "\e[33m#{str}\e[0m" end
58
+ def blue(str); "\e[34m#{str}\e[0m" end
59
+ def magenta(str); "\e[35m#{str}\e[0m" end
60
+ def cyan(str); "\e[36m#{str}\e[0m" end
61
+ def gray(str); "\e[37m#{str}\e[0m" end
62
+
63
+ def bg_black(str); "\e[40m#{str}\e[0m" end
64
+ def bg_red(str); "\e[41m#{str}\e[0m" end
65
+ def bg_green(str); "\e[42m#{str}\e[0m" end
66
+ def bg_brown(str); "\e[43m#{str}\e[0m" end
67
+ def bg_blue(str); "\e[44m#{str}\e[0m" end
68
+ def bg_magenta(str); "\e[45m#{str}\e[0m" end
69
+ def bg_cyan(str); "\e[46m#{str}\e[0m" end
70
+ def bg_gray(str); "\e[47m#{str}\e[0m" end
71
+
72
+ def bold(str); "\e[1m#{str}\e[22m" end
73
+ def italic(str); "\e[3m#{str}\e[23m" end
74
+ def underline(str); "\e[4m#{str}\e[24m" end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency "trailblazer-activity", ">= 0.10.0", "< 1.0.0"
28
28
  spec.add_dependency "trailblazer-activity-dsl-linear"
29
29
  spec.add_dependency "representable"
30
+ spec.add_dependency "hirb"
30
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trailblazer-developer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-23 00:00:00.000000000 Z
11
+ date: 2020-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - ">="
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: hirb
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :runtime
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
131
145
  description: 'Developer tools for Trailblazer: debugger, tracing, visual editor integration.'
132
146
  email:
133
147
  - apotonick@gmail.com
@@ -147,15 +161,17 @@ files:
147
161
  - gems.local.rb
148
162
  - lib/trailblazer/developer.rb
149
163
  - lib/trailblazer/developer/CHANGES.md
150
- - lib/trailblazer/developer/activity.rb
151
164
  - lib/trailblazer/developer/client.rb
152
165
  - lib/trailblazer/developer/generate.rb
153
166
  - lib/trailblazer/developer/render/circuit.rb
154
167
  - lib/trailblazer/developer/render/linear.rb
155
168
  - lib/trailblazer/developer/trace.rb
169
+ - lib/trailblazer/developer/trace/focusable.rb
170
+ - lib/trailblazer/developer/trace/inspector.rb
156
171
  - lib/trailblazer/developer/trace/present.rb
157
172
  - lib/trailblazer/developer/version.rb
158
173
  - lib/trailblazer/developer/wtf.rb
174
+ - lib/trailblazer/developer/wtf/renderer.rb
159
175
  - lib/trailblazer/diagram/bpmn.rb
160
176
  - trailblazer-developer.gemspec
161
177
  homepage: http://trailblazer.to
@@ -177,8 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
193
  - !ruby/object:Gem::Version
178
194
  version: '0'
179
195
  requirements: []
180
- rubyforge_project:
181
- rubygems_version: 2.7.6
196
+ rubygems_version: 3.0.3
182
197
  signing_key:
183
198
  specification_version: 4
184
199
  summary: Developer tools for Trailblazer.
@@ -1,51 +0,0 @@
1
- module Trailblazer
2
- module Developer
3
- # Transforms an {Activity::Graph} into an abstract data structure that represents the graph via a
4
- # well-defined API. The goal is to decouple graph internals from the presentation layer.
5
- # The {Model} is usually passed into Renderer and Layouter, to render the bpmn:Diagram XML or JSON.
6
- #
7
- # It returns {Model} with {Task}s and {Flow}s.
8
- module Activity
9
- module Graph
10
- class << self
11
- Model = Struct.new(:id, :start_events, :end_events, :task, :sequence_flow)
12
- Task = Struct.new(:id, :name, :options, :incoming, :outgoing)
13
- # DISCUSS: direction ATM is the "condition" for the BPMN rendering.
14
- Flow = Struct.new(:id, :sourceRef, :targetRef, :direction)
15
-
16
- # @param Graph an object implementing the Activity::Graph interface
17
- # @return Model Generic representation of the graph, ready for rendering.
18
- def self.to_model(graph, id: "some-process") # rubocop:disable Metrics/AbcSize
19
- start_events = graph.find_all("Start.default") # FIXME. this is a static assumption.
20
- end_events = graph.find_all { |node| graph.successors(node).size.zero? }
21
- tasks = graph.find_all { |_node| true }
22
- tasks -= start_events
23
- tasks -= end_events
24
-
25
- # transform nodes into BPMN elements.
26
- start_events = start_events.collect do |evt|
27
- Task.new(evt[:id], evt[:id], evt, Incomings(graph, evt), Outgoings(graph, evt))
28
- end
29
- end_events = end_events.collect do |evt|
30
- Task.new(evt[:id], evt[:id], evt, Incomings(graph, evt), Outgoings(graph, evt))
31
- end
32
- tasks = tasks.collect { |evt| Task.new(evt[:id], evt[:id], evt, Incomings(graph, evt), Outgoings(graph, evt)) }
33
- edges = (start_events + end_events + tasks).collect { |task| [task.incoming, task.outgoing] }.flatten(2).uniq
34
-
35
- Model.new(id, start_events, end_events, tasks, edges)
36
- end
37
-
38
- private
39
-
40
- def Outgoings(graph, source)
41
- graph.successors(source).collect { |target, edge| Flow.new(edge[:id], source[:id], target[:id], edge[:_wrapped]) }
42
- end
43
-
44
- def Incomings(graph, target)
45
- graph.predecessors(target).collect { |source, edge| Flow.new(edge[:id], source[:id], target[:id], edge[:_wrapped]) }
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end