Skip to content

Commit

Permalink
Merge pull request #35 from B-CDD/feat/ids_level_parent
Browse files Browse the repository at this point in the history
Replace :ids_tree, :ids_matrix with :ids metadata
  • Loading branch information
serradura authored Mar 15, 2024
2 parents 3c5c228 + 20a1594 commit a3a650f
Show file tree
Hide file tree
Showing 18 changed files with 201 additions and 68 deletions.
26 changes: 17 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
- [\[Unreleased\]](#unreleased)
- [Changed](#changed)
- [\[0.13.0\] - 2024-02-01](#0130---2024-02-01)
- [Added](#added)
- [Changed](#changed)
- [Changed](#changed-1)
- [\[0.12.0\] - 2024-01-07](#0120---2024-01-07)
- [Added](#added-1)
- [Changed](#changed-1)
- [Changed](#changed-2)
- [\[0.11.0\] - 2024-01-02](#0110---2024-01-02)
- [Added](#added-2)
- [Changed](#changed-2)
- [Changed](#changed-3)
- [\[0.10.0\] - 2023-12-31](#0100---2023-12-31)
- [Added](#added-3)
- [\[0.9.1\] - 2023-12-12](#091---2023-12-12)
- [Changed](#changed-3)
- [Changed](#changed-4)
- [Fixed](#fixed)
- [\[0.9.0\] - 2023-12-12](#090---2023-12-12)
- [Added](#added-4)
- [Changed](#changed-4)
- [Changed](#changed-5)
- [\[0.8.0\] - 2023-12-11](#080---2023-12-11)
- [Added](#added-5)
- [Changed](#changed-5)
- [Changed](#changed-6)
- [Removed](#removed)
- [\[0.7.0\] - 2023-10-27](#070---2023-10-27)
- [Added](#added-6)
- [Changed](#changed-6)
- [Changed](#changed-7)
- [\[0.6.0\] - 2023-10-11](#060---2023-10-11)
- [Added](#added-7)
- [Changed](#changed-7)
- [Changed](#changed-8)
- [\[0.5.0\] - 2023-10-09](#050---2023-10-09)
- [Added](#added-8)
- [\[0.4.0\] - 2023-09-28](#040---2023-09-28)
- [Added](#added-9)
- [Changed](#changed-8)
- [Changed](#changed-9)
- [Removed](#removed-1)
- [\[0.3.0\] - 2023-09-26](#030---2023-09-26)
- [Added](#added-10)
Expand All @@ -42,6 +43,13 @@

## [Unreleased]

### Changed

- **(BREAKING)** Replace trasitions metadata `:ids_tree`, and `:ids_matrix` with `:ids` property. This property is a hash with the following keys:
- `:tree`, a graph/tree representation of the transitions ids.
- `:level_parent`, a hash with the level (depth) of each transition and its parent id.
- `:matrix`, a matrix representation of the transitions ids. It is a simplification of the `:tree` property.

## [0.13.0] - 2024-02-01

### Added
Expand Down
62 changes: 47 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
- [`BCDD::Result::Context::Expectations`](#bcddresultcontextexpectations)
- [Mixin add-ons](#mixin-add-ons)
- [`BCDD::Result.transitions`](#bcddresulttransitions)
- [`ids_tree` *versus* `ids_matrix`](#ids_tree-versus-ids_matrix)
- [`metadata: {ids:}`](#metadata-ids)
- [Configuration](#configuration)
- [Turning on/off](#turning-onoff)
- [Setting a `trace_id` fetcher](#setting-a-trace_id-fetcher)
Expand Down Expand Up @@ -1860,8 +1860,11 @@ result.transitions
:metadata => {
:duration => 0, # milliseconds
:trace_id => nil, # can be set through configuration
:ids_tree => [0, [[1, []], [2, []]]],
:ids_matrix => {0 => [0, 0], 1 => [1, 1], 2 => [2, 1]}
:ids => {
:tree => [0, [[1, []], [2, []]]],
:matrix => { 0 => [0, 0], 1 => [1, 1], 2 => [2, 1]},
:level_parent => { 0 => [0, 0], 1 => [1, 0], 2 => [1, 0]}
}
},
:records=> [
{
Expand Down Expand Up @@ -1942,18 +1945,21 @@ result.transitions

<p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>

### `ids_tree` *versus* `ids_matrix`

The `:ids_matrix`. It is a simplification of the `:ids_tree` property (a graph/tree representation of the transitions ids).
### `metadata: {ids:}`

The matrix rows are the direct transitions from the root transition block, and the columns are the transitions nested from the direct transitions.
The `:ids` metadata property is a hash with three properties:
- `:tree`, a graph/tree representation of the transitions ids.
- `:level_parent`, a hash with the level (depth) of each transition and its parent id.
- `:matrix`, a matrix representation of the transitions ids. It is a simplification of the `:tree` property.

Use these data structures to build your own visualization of the transitions.
Use these data structures to build your own visualization.

> Check out [Transitions Listener example](examples/single_listener/lib/single_transitions_listener.rb) to see how a listener can be used to build a visualization of the transitions, using these properties.
```ruby
# ids_tree #
# tree:
# A graph representation (array of arrays) of the transitions ids.
#
0 # [0, [
|- 1 # [1, [[2, []]]],
| |- 2 # [3, []],
Expand All @@ -1964,7 +1970,24 @@ Use these data structures to build your own visualization of the transitions.
| |- 7 # [8, []]
|- 8 # ]]

# ids_matrix # {
# level_parent:
# Transition ids are the keys, and the level (depth) and parent id the values.
# {
0 # 0 => [0, 0],
|- 1 # 1 => [1, 0],
| |- 2 # 2 => [2, 1],
|- 3 # 3 => [1, 0],
|- 4 # 4 => [1, 0],
| |- 5 # 5 => [2, 4],
| |- 6 # 6 => [2, 4],
| |- 7 # 7 => [3, 6],
|- 8 # 8 => [1, 0]
# }

# matrix:
# The rows are the direct transitions from the root transition block,
# and the columns are the nested transitions from the direct ones.
# {
0 | 1 | 2 | 3 | 4 # 0 => [0, 0],
- | - | - | - | - # 1 => [1, 1],
0 | | | | # 2 => [1, 2],
Expand Down Expand Up @@ -1994,8 +2017,14 @@ result = SumDivisionsByTwo.call(20, 10)
# => #<BCDD::Result::Success type=:sum value=15>

result.transitions

{:version=>1, :records=>[], :metadata=>{:duration=>0, :ids_tree=>[]}}
{
:version=>1,
:records=>[],
:metadata=>{
:duration=>0,
:ids=>{:tree=>[], :matrix=>{}, :level_parent=>{}}, :trace_id=>nil
}
}
```

<p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
Expand All @@ -2020,7 +2049,7 @@ Use it to build your additional logic on top of the transitions tracking. Exampl
- Log the transitions.
- Perform a trace of the transitions.
- Instrument the transitions (measure/report).
- Build a visualization of the transitions (Diagrams, using the `records` + `:ids_tree` and `:ids_matrix` properties).
- Build a visualization of the transitions (Diagrams, using the `records` + `metadata: {ids:}` properties).

After implementing your listener, you can set it to the `BCDD::Result.config.transitions.listener=`:

Expand Down Expand Up @@ -2086,8 +2115,11 @@ class MyTransitionsListener
# :metadata => {
# :duration => 0,
# :trace_id => nil,
# :ids_tree => [0, [[1, []], [2, []]]],
# :ids_matrix => {0 => [0, 0], 1 => [1, 1], 2 => [2, 1]}
# :ids => {
# :tree => [0, [[1, []], [2, []]]],
# :matrix => { 0 => [0, 0], 1 => [1, 1], 2 => [2, 1]},
# :level_parent => { 0 => [0, 0], 1 => [1, 0], 2 => [1, 0]}
# }
# },
# :records => [
# # ...
Expand Down
3 changes: 1 addition & 2 deletions examples/multiple_listeners/db/setup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
t.string :trace_id, index: true
t.integer :version, null: false
t.integer :duration, null: false, index: true
t.json :ids_tree, null: false, default: []
t.json :ids_matrix, null: false, default: {}
t.json :ids, null: false, default: {}
t.json :records, null: false, default: []

t.timestamps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ def on_finish(transitions:)
trace_id: metadata[:trace_id],
version: transitions[:version],
duration: metadata[:duration],
ids_tree: metadata[:ids_tree],
ids_matrix: metadata[:ids_matrix],
ids: metadata[:ids],
records: transitions[:records]
)
rescue ::StandardError => e
Expand Down
2 changes: 1 addition & 1 deletion examples/multiple_listeners/lib/runtime_breaker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ module RuntimeBreaker
def self.try_to_interrupt(env:)
return unless String(ENV[env]).strip.start_with?(/1|t/)

raise Interruption, "Runtime breaker activated (#{env})"
raise Interruption, "#{env}"
end
end
12 changes: 8 additions & 4 deletions examples/multiple_listeners/lib/transitions_listener/stdout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def on_record(record:)
end

MapNestedMessages = ->(transitions, buffer, hide_given_and_continue) do
ids_matrix = transitions.dig(:metadata, :ids_matrix)
ids_level_parent = transitions.dig(:metadata, :ids, :level_parent)

messages = buffer.filter_map { |(id, msg)| "#{' ' * ids_matrix[id].last}#{msg}" if ids_matrix[id] }
messages = buffer.filter_map { |(id, msg)| "#{' ' * ids_level_parent[id].first}#{msg}" if ids_level_parent[id] }

messages.reject! { _1.match?(/\(_(given|continue)_\)/) } if hide_given_and_continue

Expand All @@ -47,8 +47,12 @@ def before_interruption(exception:, transitions:)
bc.add_silencer { |line| /lib\/bcdd\/result/.match?(line) }
bc.add_silencer { |line| line.include?(RUBY_VERSION) }

backtrace = bc.clean(exception.backtrace)
dir = "#{FileUtils.pwd[1..]}/"

puts "\nException: #{exception.message} (#{exception.class}); Backtrace: #{backtrace.join(", ")}"
cb = bc.clean(exception.backtrace)
cb.each { _1.sub!(dir, '') }
cb.reject! { _1.match?(/block \(\d levels?\) in|in `block in|internal:kernel/) }

puts "\nException:\n #{exception.message} (#{exception.class})\n\nBacktrace:\n #{cb.join("\n ")}"
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def self.inherited(subclass)

class << self
def input=(klass)
const_defined?(:Input, false) and raise ArgumentError, 'Attributes class already defined'
const_defined?(:Input, false) and raise ArgumentError, "#{self}::Input class already defined"

unless klass.is_a?(::Class) && klass < Input
raise ArgumentError, 'must be a ApplicationService::Input subclass'
Expand Down
11 changes: 7 additions & 4 deletions examples/single_listener/lib/single_transitions_listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ def on_record(record:)
end

MapNestedMessages = ->(transitions, buffer, hide_given_and_continue) do
ids_matrix = transitions.dig(:metadata, :ids_matrix)
ids_level_parent = transitions.dig(:metadata, :ids, :level_parent)

messages = buffer.filter_map { |(id, msg)| "#{' ' * ids_matrix[id].last}#{msg}" if ids_matrix[id] }
messages = buffer.filter_map { |(id, msg)| "#{' ' * ids_level_parent[id].first}#{msg}" if ids_level_parent[id] }

messages.reject! { _1.match?(/\(_(given|continue)_\)/) } if hide_given_and_continue

Expand All @@ -74,8 +74,11 @@ def on_record(record:)
# :metadata => {
# :duration => 0,
# :trace_id => nil,
# :ids_tree => [0, [[1, []], [2, []]]],
# :ids_matrix => {0 => [0, 0], 1 => [1, 1], 2 => [2, 1]}
# :ids => {
# :tree => [0, [[1, []], [2, []]]],
# :matrix => { 0 => [0, 0], 1 => [1, 1], 2 => [2, 1]},
# :level_parent => { 0 => [0, 0], 1 => [1, 0], 2 => [1, 0]}
# }
# },
# :records => [
# # ...
Expand Down
3 changes: 2 additions & 1 deletion lib/bcdd/result/transitions/tracking.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ module Tracking
EMPTY_ARRAY = [].freeze
EMPTY_HASH = {}.freeze
EMPTY_TREE = Tree.new(nil).freeze
EMPTY_IDS = { tree: EMPTY_ARRAY, matrix: EMPTY_HASH, level_parent: EMPTY_HASH }.freeze
EMPTY = {
version: VERSION,
records: EMPTY_ARRAY,
metadata: { duration: 0, ids_tree: EMPTY_ARRAY, ids_matrix: EMPTY_HASH, trace_id: nil }.freeze
metadata: { duration: 0, ids: EMPTY_IDS, trace_id: nil }.freeze
}.freeze

def self.instance
Expand Down
4 changes: 3 additions & 1 deletion lib/bcdd/result/transitions/tracking/enabled.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ def map_transitions

trace_id = Config.instance.trace_id.call

metadata = { duration: duration, ids_tree: tree.nested_ids, ids_matrix: tree.ids_matrix, trace_id: trace_id }
ids = { tree: tree.ids, matrix: tree.ids_matrix, level_parent: tree.ids_level_parent }

metadata = { duration: duration, trace_id: trace_id, ids: ids }

{ version: Tracking::VERSION, records: records, metadata: metadata }
end
Expand Down
36 changes: 26 additions & 10 deletions lib/bcdd/result/transitions/tree.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,36 +89,52 @@ def move_to_root!
move_to!(root)
end

NestedIds = ->(node) { [node.id, node.children.map(&NestedIds)] }
Ids = ->(node) { [node.id, node.children.map(&Ids)] }

def nested_ids
NestedIds[root]
def ids
Ids[root]
end

IdsMatrix = ->(tree, row, col, ids, previous) do
def ids_list
ids.flatten
end

IdsMatrix = ->(tree, row, col, memo, previous) do
last_row = previous[0]

tree.each_with_index do |node, index|
row = [(index + 1), last_row].max

id, leaf = node

ids[id] = previous == [row, col] ? [row, col + 1] : [row, col]
memo[id] = previous == [row, col] ? [row, col + 1] : [row, col]

previous = ids[id]
previous = memo[id]

IdsMatrix[leaf, row, col + 1, ids, previous]
IdsMatrix[leaf, row, col + 1, memo, previous]
end
end

def ids_matrix
current = [0, 0]

ids = { 0 => current }
memo = { 0 => current }

IdsMatrix[ids[1], 1, 1, memo, current]

memo
end

IdsLevelParent = ->((id, node), parent = 0, level = 0, memo = {}) do
memo[id] = [level, parent]

IdsMatrix[nested_ids[1], 1, 1, ids, current]
node.each { |leaf| IdsLevelParent[leaf, id, level + 1, memo] }

memo
end

ids
def ids_level_parent
IdsLevelParent[ids]
end
end
end
Expand Down
10 changes: 6 additions & 4 deletions sig/bcdd/result/transitions.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,21 @@ class BCDD::Result
def move_down!: (?Integer level) -> Tree
def move_to_root!: () -> Tree

NestedIds: ^(Node) -> Array[untyped]

def nested_ids: () -> Array[untyped]

Ids: ^(Node) -> Array[untyped]
IdsMatrix: ::Proc
IdsLevelParent: ::Proc

def ids: () -> Array[untyped]
def ids_list: () -> Array[Integer]
def ids_matrix: () -> untyped
def ids_level_parent: () -> untyped
end

module Tracking
EMPTY_ARRAY: Array[untyped]
EMPTY_HASH: Hash[untyped, untyped]
EMPTY_TREE: Transitions::Tree
EMPTY_IDS: Hash[untyped, untyped]
VERSION: Integer
EMPTY: Hash[Symbol, untyped]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def teardown

assert_transitions(result1, size: 3)

assert_equal([0, [[1, []]]], result1.transitions[:metadata][:ids_tree])
assert_equal([0, [[1, []]]], result1.transitions[:metadata][:ids][:tree])

root = { id: 0, name: 'NormalizeAndValidateEmail', desc: nil }

Expand Down Expand Up @@ -116,7 +116,7 @@ def teardown

assert_transitions(result2, size: 5)

assert_equal([0, [[1, []], [2, []]]], result2.transitions[:metadata][:ids_tree])
assert_equal([0, [[1, []], [2, []]]], result2.transitions[:metadata][:ids][:tree])

root = { id: 0, name: 'NormalizeAndValidateEmail', desc: nil }

Expand Down
Loading

0 comments on commit a3a650f

Please sign in to comment.