trailblazer-activity 0.15.1 → 0.16.0

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: f042c2ed7dab6bafd3932cfbc357ada176de13aed6a91ba05be74f0d9d000ede
4
- data.tar.gz: 471066060ff8ad800f77e26e0f1cc7090ff1b0a8820971c41de93f1760a6cf74
3
+ metadata.gz: cf0052816c7f4a1ed202128395c3c8324a27b139bbfcb163314848eaf5132d2d
4
+ data.tar.gz: 94f9951381191ce8f25816aa27228a17c27c7d271e246c94a8667f315ca2f885
5
5
  SHA512:
6
- metadata.gz: 02726f73b7af8b91ee4b34bc87dbb0a15246eb35d520ae2cd165519382d0578cad791466ff81e85ed4f95e31cf3988562115c40a6f90ab0c80b96c776c444809
7
- data.tar.gz: dfb7ad6686ed5f0a8668a032c2b65357b0e5c857afa6459a9f1a101e728aa454c38cc1814133172aabbf8ee63ef350dda9c33f2997527161e566e93b1c10da44
6
+ metadata.gz: 34b620b89186a2656671005b026f5f3f28151bcae374d058d047175553dd77b3a0c6c23557be84e03a297c9e7e02185b22ac09e4149ba843bed48db3261451a3
7
+ data.tar.gz: 512ac5bdb8af2ef4948c70c2292910e4d406f600c4d5a178afdfc02f8b70497f8b15e86ee297e4199ac4f3716be509986a21a7de33346418b60ce22501ab8930
data/CHANGES.md CHANGED
@@ -1,3 +1,61 @@
1
+ # 0.16.0
2
+
3
+ * Remove `Activity#[]`. Please use `activity.to_h[:config]`.
4
+ * Change `Activity#to_h[:nodes]`. This is now a `Schema::Nodes` "hash" that is keyed by task that
5
+ points to `Nodes::Attributes` data structures (a replacement for `Activity::NodeAttributes`).
6
+ This decision reduces logic and improves performance: it turned out that most of the time an introspect
7
+ lookup queries for a task, not ID.
8
+ * Introduce `Activity::Introspect.Nodes()` as a consistent and fast interface for introspection
9
+ and remove `Activity::Introspect::TaskMap`.
10
+ * Remove `Activity::NodeAttributes`.
11
+ * Move `Introspect::Graph` to `trailblazer-developer`. It's a data structure very specific
12
+ to rendering, which is not a part of pure runtime behavior. `Activity::Introspect.Graph()` is now deprecated.
13
+ * `TaskWrap.container_activity_for` now accepts `:id` for setting an ID for the containered activity to
14
+ anything other than `nil`.
15
+ * Re-add `:nodes` to the container activity hash as this provides a consistent way for treating all `Activity`s.
16
+ * Remove `Activity::Config`. This immutable hash interface was used in one place, only, and can easily
17
+ be replaced with `config.merge()`.
18
+ * Add `Introspect::Render`. Please consider this private.
19
+
20
+ ## Intermediate/Implementation
21
+
22
+ * Remove `Intermediate.call`, this is now done through `Intermediate::Compiler`.
23
+ * Introduce `Intermediate::Compiler` which is simplified and is 10% faster.
24
+ * A terminus ("end event") in `Schema::Intermediate` no longer has outputs but an empty array. The
25
+ `stop_event: true` option is still required to mark the `TaskRef` as a terminus.
26
+ * `Schema::Intermediate` now keeps a map `{<terminus ID> => :semantic}` instead of the flat termini ID list and
27
+ one default start event instead of an array. This looks as follows.
28
+
29
+ ```ruby
30
+ Schema::Intermediate.new(
31
+ {
32
+ # ...
33
+ Intermediate::TaskRef("End.success", stop_event: true) => [Inter::Out(:success, nil)]
34
+ },
35
+ ["End.success"],
36
+ [:a] # start
37
+ ```
38
+
39
+ Now becomes
40
+
41
+ ```ruby
42
+ Schema::Intermediate.new(
43
+ {
44
+ # ...
45
+ Intermediate::TaskRef("End.success", stop_event: true) => []
46
+ },
47
+ {"End.success" => :success},
48
+ :a # start
49
+ ```
50
+ * In line with the change in `Intermediate`, the `Implemention` termini `Task`s now don't have outputs anymore.
51
+
52
+ ```ruby
53
+ implementation = {
54
+ # ...
55
+ "End.success" => Schema::Implementation::Task(Activity::End.new(semantic: :success), [], []) # No need for outputs here.
56
+ }
57
+ ```
58
+
1
59
  # 0.15.1
2
60
 
3
61
  * Introduce `Extension.WrapStatic()` as a consistent interface for creating wrap_static extensions
data/Gemfile CHANGED
@@ -1,5 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
  gemspec
3
3
 
4
- # gem "trailblazer-developer", path: "../trailblazer-developer"
5
- # gem "trailblazer-context", github: "trailblazer/trailblazer-context", branch: "ruby-3"
4
+ # gem "trailblazer-developer", path: "../trailblazer-developer"
5
+ gem "benchmark-ips"
6
+ gem "standard"
@@ -1,154 +1,157 @@
1
1
  module Trailblazer
2
2
  class Activity
3
- # The Adds interface are mechanics to alter sequences/pipelines.
4
- # "one" ADDS structure: {row: ..., insert: [Insert, "id"]}
5
- #
6
- # To work with the instructions provided here, the pipeline structure
7
- # needs to expose {#to_a}.
8
- module Adds
9
- module_function
10
- # @returns Sequence/Pipeline New sequence instance
11
- # @private
12
- def insert_row(pipeline, row:, insert:)
13
- insert_function, *args = insert
3
+ # Developer's docs: https://trailblazer.to/2.1/docs/internals#internals-wiring-api-adds-interface
4
+ #
5
+ # The Adds interface are mechanics to alter sequences/pipelines.
6
+ # "one" ADDS structure: {row: ..., insert: [Insert, "id"]}
7
+ #
8
+ # To work with the instructions provided here, the pipeline structure
9
+ # needs to expose {#to_a}.
10
+ module Adds
11
+ module_function
12
+
13
+ # @returns Sequence/Pipeline New sequence instance
14
+ # @private
15
+ def insert_row(pipeline, row:, insert:)
16
+ insert_function, *args = insert
17
+
18
+ insert_function.(pipeline, row, *args)
19
+ end
14
20
 
15
- insert_function.(pipeline, row, *args)
21
+ # Inserts one or more {Adds} into {pipeline}.
22
+ def apply_adds(pipeline, adds)
23
+ adds.each do |add|
24
+ pipeline = insert_row(pipeline, **add)
16
25
  end
17
26
 
18
- # Inserts one or more {Adds} into {pipeline}.
19
- def apply_adds(pipeline, adds)
20
- adds.each do |add|
21
- pipeline = insert_row(pipeline, **add)
22
- end
23
-
24
- pipeline
25
- end
27
+ pipeline
28
+ end
26
29
 
27
- # @param inserts Array of friendly interface insertions
28
- # def call(pipeline, *inserts)
29
- # adds = build_adds_for_friendly_interface(inserts)
30
-
31
- # Adds.apply_adds(pipeline, adds)
32
- # end
33
-
34
- module FriendlyInterface
35
- # @public
36
- # @return Array of ADDS
37
- #
38
- # Translate a collection of friendly interface to ADDS.
39
- # This is a mini-DSL, if you want.
40
- def self.adds_for(inserts)
41
- inserts.collect do |task, options|
42
- build_adds(task, **options)
43
- end
44
- end
30
+ # @param inserts Array of friendly interface insertions
31
+ # def call(pipeline, *inserts)
32
+ # adds = build_adds_for_friendly_interface(inserts)
45
33
 
46
- # @private
47
- def self.build_adds(task, id:, prepend: "task_wrap.call_task", append: false)
48
- insert, insert_id =
49
- append === false ? [:Prepend, prepend] : [:Append, append]
34
+ # Adds.apply_adds(pipeline, adds)
35
+ # end
50
36
 
51
- {
52
- insert: [Activity::Adds::Insert.method(insert), insert_id],
53
- row: TaskWrap::Pipeline::Row(id, task)
54
- }
37
+ module FriendlyInterface
38
+ # @public
39
+ # @return Array of ADDS
40
+ #
41
+ # Translate a collection of friendly interface to ADDS.
42
+ # This is a mini-DSL, if you want.
43
+ def self.adds_for(inserts)
44
+ inserts.collect do |task, options|
45
+ build_adds(task, **options)
55
46
  end
56
47
  end
57
48
 
58
- # Functions to alter the Sequence/Pipeline by inserting, replacing, or deleting a row.
59
- #
60
- # they don't mutate the data structure but rebuild it, has to respond to {to_a}
61
- #
62
- # These methods are invoked via {Adds.apply_adds} and should never be called directly.
63
- module Insert
64
- module_function
49
+ # @private
50
+ def self.build_adds(task, id:, prepend: "task_wrap.call_task", append: false)
51
+ insert, insert_id =
52
+ (append === false) ? [:Prepend, prepend] : [:Append, append]
53
+
54
+ {
55
+ insert: [Activity::Adds::Insert.method(insert), insert_id],
56
+ row: TaskWrap::Pipeline::Row(id, task)
57
+ }
58
+ end
59
+ end
65
60
 
66
- # Append {new_row} after {insert_id}.
67
- def Append(pipeline, new_row, insert_id=nil)
68
- build_from_ary(pipeline, insert_id) do |ary, index|
69
- index = ary.size if index.nil? # append to end of pipeline.
61
+ # Functions to alter the Sequence/Pipeline by inserting, replacing, or deleting a row.
62
+ #
63
+ # they don't mutate the data structure but rebuild it, has to respond to {to_a}
64
+ #
65
+ # These methods are invoked via {Adds.apply_adds} and should never be called directly.
66
+ module Insert
67
+ module_function
70
68
 
71
- range_before_index(ary, index+1) + [new_row] + Array(ary[index+1..-1])
72
- end
69
+ # Append {new_row} after {insert_id}.
70
+ def Append(pipeline, new_row, insert_id = nil)
71
+ build_from_ary(pipeline, insert_id) do |ary, index|
72
+ index = ary.size if index.nil? # append to end of pipeline.
73
+
74
+ range_before_index(ary, index + 1) + [new_row] + Array(ary[index + 1..-1])
73
75
  end
76
+ end
74
77
 
75
- # Insert {new_row} before {insert_id}.
76
- def Prepend(pipeline, new_row, insert_id=nil)
77
- build_from_ary(pipeline, insert_id) do |ary, index|
78
- index = 0 if index.nil? # Prepend to beginning of pipeline.
78
+ # Insert {new_row} before {insert_id}.
79
+ def Prepend(pipeline, new_row, insert_id = nil)
80
+ build_from_ary(pipeline, insert_id) do |ary, index|
81
+ index = 0 if index.nil? # Prepend to beginning of pipeline.
79
82
 
80
- range_before_index(ary, index) + [new_row] + ary[index..-1]
81
- end
83
+ range_before_index(ary, index) + [new_row] + ary[index..-1]
82
84
  end
85
+ end
83
86
 
84
- def Replace(pipeline, new_row, insert_id)
85
- build_from_ary(pipeline, insert_id) do |ary, index|
86
- range_before_index(ary, index) + [new_row] + ary[index+1..-1]
87
- end
87
+ def Replace(pipeline, new_row, insert_id)
88
+ build_from_ary(pipeline, insert_id) do |ary, index|
89
+ range_before_index(ary, index) + [new_row] + ary[index + 1..-1]
88
90
  end
91
+ end
89
92
 
90
- def Delete(pipeline, _, insert_id)
91
- build_from_ary(pipeline, insert_id) do |ary, index|
92
- range_before_index(ary, index) + ary[index+1..-1]
93
- end
93
+ def Delete(pipeline, _, insert_id)
94
+ build_from_ary(pipeline, insert_id) do |ary, index|
95
+ range_before_index(ary, index) + ary[index + 1..-1]
94
96
  end
97
+ end
95
98
 
96
- # @private
97
- def build(sequence, rows)
98
- sequence.class.new(rows)
99
- end
99
+ # @private
100
+ def build(sequence, rows)
101
+ sequence.class.new(rows)
102
+ end
100
103
 
101
- # @private
102
- def find_index(ary, insert_id)
103
- ary.find_index { |row| row.id == insert_id }
104
- end
104
+ # @private
105
+ def find_index(ary, insert_id)
106
+ ary.find_index { |row| row.id == insert_id }
107
+ end
105
108
 
106
- # Converts the pipeline structure to an array,
107
- # automatically finds the index for {insert_id},
108
- # and calls the user block with the computed values.
109
- #
110
- # Single-entry point, could be named {#call}.
111
- # @private
112
- def apply_on_ary(pipeline, insert_id, raise_index_error: true, &block)
113
- ary = pipeline.to_a
114
-
115
- if insert_id.nil?
116
- index = nil
117
- else
118
- index = find_index(ary, insert_id) # DISCUSS: this only makes sense if there are more than {Append} using this.
119
- raise IndexError.new(pipeline, insert_id) if index.nil? && raise_index_error
120
- end
121
-
122
- _new_ary = yield(ary, index) # call the block.
109
+ # Converts the pipeline structure to an array,
110
+ # automatically finds the index for {insert_id},
111
+ # and calls the user block with the computed values.
112
+ #
113
+ # Single-entry point, could be named {#call}.
114
+ # @private
115
+ def apply_on_ary(pipeline, insert_id, raise_index_error: true, &block)
116
+ ary = pipeline.to_a
117
+
118
+ if insert_id.nil?
119
+ index = nil
120
+ else
121
+ index = find_index(ary, insert_id) # DISCUSS: this only makes sense if there are more than {Append} using this.
122
+ raise IndexError.new(pipeline, insert_id) if index.nil? && raise_index_error
123
123
  end
124
124
 
125
- def build_from_ary(pipeline, insert_id, &block)
126
- new_ary = apply_on_ary(pipeline, insert_id, &block)
125
+ _new_ary = yield(ary, index) # call the block.
126
+ end
127
127
 
128
- # Wrap the sequence/pipeline array into a concrete Sequence/Pipeline.
129
- build(pipeline, new_ary)
130
- end
128
+ def build_from_ary(pipeline, insert_id, &block)
129
+ new_ary = apply_on_ary(pipeline, insert_id, &block)
131
130
 
132
- # Always returns a valid, concat-able array for all indices
133
- # before the {index}.
134
- # @private
135
- def range_before_index(ary, index)
136
- return [] if index == 0
137
- ary[0..index-1]
138
- end
139
- end # Insert
131
+ # Wrap the sequence/pipeline array into a concrete Sequence/Pipeline.
132
+ build(pipeline, new_ary)
133
+ end
140
134
 
141
- class IndexError < ::IndexError
142
- def initialize(sequence, step_id)
143
- valid_ids = sequence.to_a.collect{ |row| row.id.inspect }
135
+ # Always returns a valid, concat-able array for all indices
136
+ # before the {index}.
137
+ # @private
138
+ def range_before_index(ary, index)
139
+ return [] if index == 0
140
+ ary[0..index - 1]
141
+ end
142
+ end # Insert
144
143
 
145
- message = "\n" \
146
- "\e[31m#{step_id.inspect} is not a valid step ID. Did you mean any of these ?\e[0m\n" \
147
- "\e[32m#{valid_ids.join("\n")}\e[0m"
144
+ class IndexError < ::IndexError
145
+ def initialize(sequence, step_id)
146
+ valid_ids = sequence.to_a.collect { |row| row.id.inspect }
148
147
 
149
- super(message)
150
- end
148
+ message = "\n" \
149
+ "\e[31m#{step_id.inspect} is not a valid step ID. Did you mean any of these ?\e[0m\n" \
150
+ "\e[32m#{valid_ids.join("\n")}\e[0m"
151
+
152
+ super(message)
151
153
  end
152
154
  end
155
+ end
153
156
  end
154
157
  end
@@ -22,8 +22,8 @@ module Trailblazer
22
22
  # and returns the return value of the user's callable. By design, it is *not* circuit-interface compatible.
23
23
  class Step
24
24
  def initialize(step, user_proc, **)
25
- @step = step
26
- @user_proc = user_proc
25
+ @step = step
26
+ @user_proc = user_proc
27
27
  end
28
28
 
29
29
  # Translate the circuit interface to the step's step-interface. However,
@@ -91,7 +91,7 @@ module Trailblazer
91
91
  def inspect # TODO: make me private!
92
92
  user_step = @circuit_step.instance_variable_get(:@user_proc) # DISCUSS: to we want Step#to_h?
93
93
 
94
- %{#<Trailblazer::Activity::TaskBuilder::Task user_proc=#{Trailblazer::Activity::Introspect.render_task(user_step)}>}
94
+ %(#<Trailblazer::Activity::TaskBuilder::Task user_proc=#{Trailblazer::Activity::Introspect.render_task(user_step)}>)
95
95
  end
96
96
  alias_method :to_s, :inspect
97
97
  end
@@ -58,7 +58,7 @@ module Trailblazer
58
58
  task,
59
59
  signal: last_signal,
60
60
  outputs: @map[task],
61
- exec_context: circuit_options[:exec_context], # passed at run-time from DSL
61
+ exec_context: circuit_options[:exec_context] # passed at run-time from DSL
62
62
  )
63
63
  end
64
64
  end
@@ -66,7 +66,11 @@ module Trailblazer
66
66
 
67
67
  # Returns the circuit's components.
68
68
  def to_h
69
- { map: @map, end_events: @stop_events, start_task: @start_task }
69
+ {
70
+ map: @map,
71
+ end_events: @stop_events,
72
+ start_task: @start_task
73
+ }
70
74
  end
71
75
 
72
76
  private
@@ -5,16 +5,15 @@ module Trailblazer
5
5
 
6
6
  def warn(caller_location, message)
7
7
  location = caller_location ? location_for(caller_location) : nil
8
- warning = [location, message].compact.join(" ")
8
+ warning = [location, message].compact.join(" ")
9
9
 
10
- Kernel.warn %{[Trailblazer] #{warning}\n}
10
+ Kernel.warn %([Trailblazer] #{warning}\n)
11
11
  end
12
12
 
13
13
  def location_for(caller_location)
14
- caller_location = caller_location
15
- line_no = caller_location.lineno
14
+ line_no = caller_location.lineno
16
15
 
17
- %{#{caller_location.absolute_path}:#{line_no}}
16
+ %(#{caller_location.absolute_path}:#{line_no})
18
17
  end
19
18
  end
20
19
  end
@@ -0,0 +1,53 @@
1
+ module Trailblazer
2
+ class Activity
3
+ module Introspect
4
+ # @private
5
+ module Render
6
+ module_function
7
+
8
+ def call(activity, **options)
9
+ nodes = Introspect.Nodes(activity)
10
+ circuit_map = activity.to_h[:circuit].to_h[:map]
11
+
12
+ content = nodes.collect do |task, node|
13
+ outgoings = circuit_map[task]
14
+
15
+ conns = outgoings.collect do |signal, target|
16
+ " {#{signal}} => #{inspect_with_matcher(target, **options)}"
17
+ end
18
+
19
+ [
20
+ inspect_with_matcher(node.task, **options),
21
+ conns.join("\n")
22
+ ]
23
+ end
24
+
25
+ content = content.join("\n")
26
+
27
+ "\n#{content}".gsub(/0x\w+/, "0x")
28
+ end
29
+
30
+ # If Ruby had pattern matching, this function wasn't necessary.
31
+ def inspect_with_matcher(task, inspect_task: method(:inspect_task), inspect_end: method(:inspect_end))
32
+ return inspect_task.(task) unless task.is_a?(Trailblazer::Activity::End)
33
+ inspect_end.(task)
34
+ end
35
+
36
+ def inspect_task(task)
37
+ task.inspect
38
+ end
39
+
40
+ def inspect_end(task)
41
+ class_name = strip(task.class)
42
+ options = task.to_h
43
+
44
+ "#<#{class_name}/#{options[:semantic].inspect}>"
45
+ end
46
+
47
+ def strip(string)
48
+ string.to_s.sub("Trailblazer::Activity::", "")
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -5,142 +5,49 @@ module Trailblazer
5
5
  # It abstracts internals about circuits and provides a convenient API to third-parties
6
6
  # such as tracing, rendering an activity, or finding particular tasks.
7
7
  module Introspect
8
- # A TaskMap is a way to introspect an {Activity}. It allows finding a {TaskAttributes}
9
- # instance by its ID given at compile-time, or its task.
10
- #
11
- # It is much simpler and faster than the Graph interface that might get (re)moved.
12
- def self.TaskMap(activity)
8
+ # Public entry point for {Activity} instance introspection.
9
+ def self.Nodes(activity, task: nil, **options)
13
10
  schema = activity.to_h
14
11
  nodes = schema[:nodes]
15
12
 
16
- task_map_tuples =
17
- nodes.collect do |node_attributes|
18
- [
19
- task = node_attributes[:task],
20
- TaskMap::TaskAttributes(id: node_attributes[:id], task: task)
21
- ]
22
- end
23
-
24
- TaskMap[task_map_tuples].freeze
13
+ return Nodes.find_by_id(nodes, options[:id]) if options.key?(:id)
14
+ return nodes.fetch(task) if task
15
+ nodes
25
16
  end
26
17
 
27
- class TaskMap < Hash
28
- TaskAttributes = Struct.new(:id, :task) # TODO: extend at some point.
29
-
30
- def self.TaskAttributes(id:, task:)
31
- TaskMap::TaskAttributes.new(id, task).freeze
32
- end
33
-
34
- def find_by_id(id)
35
- tuple = find { |task, attrs| attrs[:id] == id } or return
18
+ module Nodes
19
+ # @private
20
+ # @return Attributes data structure
21
+ def self.find_by_id(nodes, id)
22
+ tuple = nodes.find { |task, attrs| attrs.id == id } or return
36
23
  tuple[1]
37
24
  end
38
25
  end
39
26
 
40
- # TODO: order of step/fail/pass in Node would be cool to have
41
-
42
- # TODO: Remove Graph. This is only useful to render the full
43
- # circuit, which is a very specific task that could sit in `developer`,
44
- # instead.
45
- # Some thoughts here:
46
- # * where do we need Schema.outputs? and where task.outputs?
47
- #
48
- #
49
- # @private This API is still under construction.
50
- class Graph
51
- def initialize(activity)
52
- @schema = activity.to_h or raise
53
- @circuit = @schema[:circuit]
54
- @map = @circuit.to_h[:map]
55
- @configs = @schema[:nodes]
56
- end
57
-
58
- def find(id = nil, &block)
59
- return find_by_id(id) unless block_given?
60
-
61
- find_with_block(&block)
62
- end
63
-
64
- # TODO: convert to {#to_a}.
65
- def collect(strategy: :circuit)
66
- @map.keys.each_with_index.collect { |task, i| yield find_with_block { |node| node.task == task }, i }
67
- end
68
-
69
- def stop_events
70
- @circuit.to_h[:end_events]
71
- end
72
-
73
- private
74
-
75
- def find_by_id(id)
76
- node = @configs.find { |_node| _node.id == id } or return
77
- node_for(node)
78
- end
79
-
80
- def find_with_block
81
- existing = @configs.find { |node| yield Node(node.task, node.id, node.outputs, node.data) } or return
82
-
83
- node_for(existing)
84
- end
85
-
86
- # Build a {Graph::Node} with outputs etc.
87
- def node_for(node_attributes)
88
- Node(
89
- node_attributes.task,
90
- node_attributes.id,
91
- node_attributes.outputs, # [#<struct Trailblazer::Activity::Output signal=Trailblazer::Activity::Right, semantic=:success>]
92
- outgoings_for(node_attributes),
93
- node_attributes.data,
94
- )
95
- end
96
-
97
- def Node(*args)
98
- Node.new(*args).freeze
99
- end
100
-
101
- Node = Struct.new(:task, :id, :outputs, :outgoings, :data)
102
- Outgoing = Struct.new(:output, :task)
103
-
104
- def outgoings_for(node)
105
- outputs = node.outputs
106
- connections = @map[node.task]
107
-
108
- connections.collect do |signal, target|
109
- output = outputs.find { |out| out.signal == signal }
110
- Outgoing.new(output, target)
111
- end
112
- end
113
- end
114
-
115
- def self.Graph(*args)
116
- Graph.new(*args)
117
- end
118
-
119
27
  # @private
120
28
  def self.find_path(activity, segments)
121
- raise ArgumentError.new(%{[Trailblazer] Please pass #{activity}.to_h[:activity] into #find_path.}) unless activity.kind_of?(Trailblazer::Activity)
29
+ raise ArgumentError.new(%([Trailblazer] Please pass #{activity}.to_h[:activity] into #find_path.)) unless activity.is_a?(Trailblazer::Activity)
122
30
 
123
- task_attributes = TaskMap::TaskAttributes(id: nil, task: activity)
124
- last_graph, last_activity = nil, TaskWrap.container_activity_for(activity) # needed for empty/root path
31
+ segments = [nil, *segments]
125
32
 
126
- segments.each do |segment|
127
- task_map = Introspect.TaskMap(activity)
128
- task, task_attributes = (task_map.find { |task, attributes| attributes[:id] == segment } or return) # DISCUSS: should we abstract these internals of {TaskMap} in {find_by_id}?
33
+ attributes = nil
34
+ last_activity = nil
35
+ activity = TaskWrap.container_activity_for(activity) # needed for empty/root path
129
36
 
37
+ segments.each do |segment|
38
+ attributes = Introspect.Nodes(activity, id: segment) or return nil
130
39
  last_activity = activity
131
- last_graph = task_map
132
-
133
- activity = task
40
+ activity = attributes.task
134
41
  end
135
42
 
136
- return task_attributes, last_activity, last_graph
43
+ return attributes, last_activity
137
44
  end
138
45
 
139
46
  def self.render_task(proc)
140
47
  if proc.is_a?(Method)
141
48
 
142
49
  receiver = proc.receiver
143
- receiver = receiver.is_a?(Class) ? (receiver.name || "#<Class:0x>") : (receiver.name || "#<Module:0x>") #"#<Class:0x>"
50
+ receiver = receiver.is_a?(Class) ? (receiver.name || "#<Class:0x>") : (receiver.name || "#<Module:0x>") # "#<Class:0x>"
144
51
 
145
52
  return "#<Method: #{receiver}.#{proc.name}>"
146
53
  elsif proc.is_a?(Symbol)
@@ -149,6 +56,13 @@ module Trailblazer
149
56
 
150
57
  proc.inspect
151
58
  end
59
+
60
+ # TODO: remove with 0.1.0.
61
+ def self.Graph(*args)
62
+ Deprecate.warn caller_locations[0], %(`Trailblazer::Activity::Introspect::Graph` is deprecated. Please use `Trailblazer::Developer::Introspect.Graph`)
63
+
64
+ Trailblazer::Developer::Introspect::Graph.new(*args)
65
+ end
152
66
  end # Introspect
153
67
  end
154
68
  end