hyperlayer 0.1

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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +38 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/manifest.js +7 -0
  6. data/app/assets/stylesheets/application.bootstrap.scss +2 -0
  7. data/app/assets/stylesheets/hyperlayer/app.css +47 -0
  8. data/app/assets/stylesheets/hyperlayer/application.css +18774 -0
  9. data/app/assets/stylesheets/hyperlayer/prism.css +3 -0
  10. data/app/controllers/hyperlayer/application_controller.rb +4 -0
  11. data/app/controllers/hyperlayer/events_controller.rb +95 -0
  12. data/app/controllers/hyperlayer/example_groups_controller.rb +9 -0
  13. data/app/controllers/hyperlayer/paths_controller.rb +18 -0
  14. data/app/controllers/hyperlayer/runs_controller.rb +7 -0
  15. data/app/controllers/hyperlayer/specs_controller.rb +8 -0
  16. data/app/javascript/controllers/application.js +9 -0
  17. data/app/javascript/controllers/index.js +11 -0
  18. data/app/javascript/hyperlayer/application.js +7 -0
  19. data/app/javascript/hyperlayer/prism.js +8 -0
  20. data/app/models/application_record.rb +3 -0
  21. data/app/models/hyperlayer/event.rb +28 -0
  22. data/app/models/hyperlayer/example_group.rb +6 -0
  23. data/app/models/hyperlayer/path.rb +35 -0
  24. data/app/models/hyperlayer/run.rb +5 -0
  25. data/app/models/hyperlayer/spec.rb +8 -0
  26. data/app/services/build_file_overlay.rb +26 -0
  27. data/app/services/callable.rb +129 -0
  28. data/app/services/file_builder.rb +260 -0
  29. data/app/services/find_method_from_event.rb +65 -0
  30. data/app/services/find_method_in_path.rb +98 -0
  31. data/app/services/generate_buffer.rb +116 -0
  32. data/app/services/import_events.rb +56 -0
  33. data/app/services/split_methods.rb +50 -0
  34. data/app/services/test_one.rb +34 -0
  35. data/app/services/update_code.rb +111 -0
  36. data/app/views/hyperlayer/events/_code.html.erb +36 -0
  37. data/app/views/hyperlayer/events/_event.html.erb +15 -0
  38. data/app/views/hyperlayer/events/_tree-text.html.erb +22 -0
  39. data/app/views/hyperlayer/events/_tree.html.erb +15 -0
  40. data/app/views/hyperlayer/events/index.html.erb +41 -0
  41. data/app/views/hyperlayer/example_groups/index.html.erb +25 -0
  42. data/app/views/hyperlayer/paths/_path.html.erb +52 -0
  43. data/app/views/hyperlayer/paths/index.html.erb +5 -0
  44. data/app/views/hyperlayer/paths/show.html.erb +3 -0
  45. data/app/views/hyperlayer/runs/index.html.erb +23 -0
  46. data/app/views/hyperlayer/specs/index.html.erb +24 -0
  47. data/app/views/layouts/_nav.html.erb +8 -0
  48. data/app/views/layouts/hyperlayer/application.html.erb +30 -0
  49. data/app/views/layouts/hyperlayer/mailer.html.erb +13 -0
  50. data/app/views/layouts/hyperlayer/mailer.text.erb +1 -0
  51. data/config/initializers/engine_migrations.rb +3 -0
  52. data/config/routes.rb +11 -0
  53. data/db/migrate/20231009165755_create_hyperlayer_events.rb +19 -0
  54. data/db/migrate/20231009165919_create_hyperlayer_example_groups.rb +12 -0
  55. data/db/migrate/20231009165952_create_hyperlayer_runs.rb +9 -0
  56. data/db/migrate/20231009170101_create_hyperlayer_paths.rb +10 -0
  57. data/db/migrate/20231009170121_create_hyperlayer_specs.rb +12 -0
  58. data/lib/hyperlayer/engine.rb +22 -0
  59. data/lib/hyperlayer/method_tracer.rb +12 -0
  60. data/lib/hyperlayer/tracer.rb +78 -0
  61. data/lib/hyperlayer/version.rb +3 -0
  62. data/lib/hyperlayer.rb +15 -0
  63. data/lib/tasks/listen.rake +8 -0
  64. metadata +207 -0
@@ -0,0 +1,111 @@
1
+ # require 'fast'
2
+
3
+ class UpdateCode < Parser::AST::Processor
4
+ include RuboCop::AST::Traversal
5
+
6
+ def self.call(id, code, method)
7
+ new.call(id, code, method)
8
+ end
9
+
10
+ LOCATION_MAP = {
11
+ Send: :expression,
12
+ MethodDefinition: :name
13
+ }
14
+
15
+ def call(id, code, method)
16
+ path = Path.find(id)
17
+ code = code.presence || File.read(path.path)
18
+
19
+ method = method.to_sym
20
+
21
+ # First find all instances
22
+
23
+ source = RuboCop::ProcessedSource.new(code, 2.7)
24
+ nodes = FindMethod.call(
25
+ source: source,
26
+ name: method,
27
+ method_types: [:def, :send]
28
+ )
29
+
30
+ nodes.each do |node|
31
+ # Then look again and change them all one by one
32
+ source = RuboCop::ProcessedSource.new(code, 2.7)
33
+ node = FindMethod.call(
34
+ source: source,
35
+ name: method,
36
+ method_types: [:def, :send]
37
+ ).first
38
+
39
+ type = node.loc.class.to_s.split("::").last.to_sym
40
+
41
+ ReplaceCode.call(
42
+ code: code,
43
+ node: node,
44
+ location: LOCATION_MAP[type],
45
+ with: 'geoff',
46
+ )
47
+ end
48
+
49
+ code
50
+
51
+ # Add "after/before" which allows to position
52
+ # AddMethod.call(code: code, pos: 150)
53
+ end
54
+
55
+ private
56
+
57
+ class FindMethod
58
+ include Callable
59
+ expects :source, :name, :method_types
60
+
61
+ def call
62
+ source.ast
63
+ .each_node
64
+ .map { |n| n if method_types.include?(n.type) && n.method_name == name }
65
+ .compact
66
+ end
67
+ end
68
+
69
+ class AddMethod
70
+ include Callable
71
+ expects :code, :pos
72
+
73
+ def call
74
+ code.insert(pos, "def code \n inserted.here! \n end")
75
+ end
76
+ end
77
+
78
+ class ShowCode
79
+ include Callable
80
+ expects :code, :node, :location, :with
81
+
82
+ def call
83
+ code[begin_pos...end_pos]
84
+ end
85
+
86
+ private
87
+
88
+ delegate :begin_pos, :end_pos, to: :expression
89
+
90
+ def expression
91
+ node.loc.send(location)
92
+ end
93
+ end
94
+
95
+ class ReplaceCode
96
+ include Callable
97
+ expects :code, :node, :location, :with
98
+
99
+ def call
100
+ code[begin_pos...end_pos] = with
101
+ end
102
+
103
+ private
104
+
105
+ delegate :begin_pos, :end_pos, to: :expression
106
+
107
+ def expression
108
+ node.loc.send(location)
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,36 @@
1
+ <div class="card node">
2
+ <div class="card-header">
3
+ <div class="font-monospace text-body-secondary text-uppercase small">
4
+ <%= event.defined_class %>
5
+ </div>
6
+ <div>
7
+ #<%= event.method %>
8
+ </div>
9
+ <hr />
10
+ <div class="font-monospace text-body-secondary text-uppercase small">
11
+ <%= event.arguments %>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="card-body">
16
+ <pre>
17
+ <code class="language-ruby">
18
+ <%= SplitMethods.call(event) %>
19
+ </code>
20
+ </pre>
21
+
22
+ <% if false %>
23
+ <pre style='text-wrap: wrap;'>
24
+ <code>
25
+ <%= event.variables %>
26
+ </code>
27
+ </pre>
28
+ <% end %>
29
+
30
+ <pre style='text-wrap: wrap;'>
31
+ <code>
32
+ <%= event.return_value_events&.return_value.presence || 'nil' %>
33
+ </code>
34
+ </pre>
35
+ </div>
36
+ </div>
@@ -0,0 +1,15 @@
1
+ <div class="card node">
2
+ <div class="card-body">
3
+ <pre>
4
+ <code class="language-ruby">
5
+ <%= SplitMethods.call(event) %>
6
+ </code>
7
+ </pre>
8
+
9
+ <pre style='text-wrap: wrap;'>
10
+ <code>
11
+ <%= event.return_value_events&.return_value.presence || 'nil' %>
12
+ </code>
13
+ </pre>
14
+ </div>
15
+ </div>
@@ -0,0 +1,22 @@
1
+ <% branches.each do |branch| %>
2
+ <ul>
3
+ <% branch.each do |event, sub_branches| %>
4
+ <li>
5
+ <div class='text-muted' style='font-size: 12px'><%= event.defined_class %></div>
6
+
7
+ <% if true %>
8
+ <a href="#" data-bs-toggle="modal" data-bs-target="#staticBackdrop" data-bs-anchor="<%= "#{event.defined_class}::#{event.method}" %>" class="noStyle">#<%= event.method %></a>
9
+ <% else %>
10
+ <a href="#" data-bs-toggle="offcanvas" data-bs-target="#offcanvasRight" data-bs-anchor="<%= "#{event.defined_class}::#{event.method}" %>" class="noStyle">#<%= event.method %></a>
11
+ <% end %>
12
+
13
+ <code><%= event.arguments %></code><br />
14
+ <code>&rarr; <%= event.return_value_events&.return_value.presence %></code>
15
+ </li>
16
+
17
+ <% if sub_branches.present? %>
18
+ <%= render partial: 'tree-text', locals: { branches: sub_branches } %>
19
+ <% end %>
20
+ <% end %>
21
+ </ul>
22
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <% branches.each do |branch| %>
2
+ <div class="tree-node">
3
+ <% branch.each do |event, sub_branches| %>
4
+ <div class="node-content" id="<%= "#{event.defined_class}::#{event.method}" %>">
5
+ <div class="node-code">
6
+ <%= render "code", event: event %>
7
+ </div>
8
+ </div>
9
+
10
+ <% if sub_branches.present? %>
11
+ <%= render partial: 'tree', locals: { branches: sub_branches } %>
12
+ <% end %>
13
+ <% end %>
14
+ </div>
15
+ <% end %>
@@ -0,0 +1,41 @@
1
+ <div class="container">
2
+ <div class='row'>
3
+ <div class="col">
4
+ <%= render 'tree-text', branches: @tree %>
5
+ </div>
6
+ </div>
7
+ </div>
8
+
9
+ <!-- Modal -->
10
+ <div class="modal fade" id="staticBackdrop" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
11
+ <div class="modal-dialog modal-xl">
12
+ <div class="modal-content">
13
+ <div class="modal-header">
14
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
15
+ </div>
16
+ <div class="modal-body">
17
+ <%= render 'tree', branches: @tree %>
18
+ </div>
19
+ <div class="modal-footer">
20
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
21
+ <button type="button" class="btn btn-primary">Understood</button>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+
27
+ <script>
28
+ document.addEventListener('DOMContentLoaded', (event) => {
29
+ document.getElementById('staticBackdrop').addEventListener('shown.bs.modal', function (event) {
30
+ var triggerElement = event.relatedTarget; // Element that triggered the modal
31
+ var anchorId = triggerElement.getAttribute('data-bs-anchor'); // Get the data-anchor attribute
32
+ var modalBody = this.querySelector('.modal-body');
33
+ var anchor = document.getElementById(anchorId);
34
+ if (anchor) {
35
+ setTimeout(() => {
36
+ anchor.scrollIntoView({ behavior: 'smooth' });
37
+ }, 100);
38
+ }
39
+ });
40
+ });
41
+ </script>
@@ -0,0 +1,25 @@
1
+ <div class="container-fluid">
2
+ <div class="row mt-2">
3
+ <div class="col-12">
4
+ <h5><%= @spec.location %></h5>
5
+
6
+ <table class="table">
7
+ <thead>
8
+ <tr>
9
+ <th scope="col">Example Groups</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% @example_groups.each do |example_group| %>
14
+ <tr>
15
+ <td>
16
+ <%= link_to(example_group.description, run_spec_example_group_events_path(@run, params[:spec_id], example_group)) %><br />
17
+ <%= example_group.location %>
18
+ </td>
19
+ </tr>
20
+ <% end %>
21
+ </tbody>
22
+ </table>
23
+ </div>
24
+ </div>
25
+ </div>
@@ -0,0 +1,52 @@
1
+ <div class="row mt-2">
2
+ <div class="col-4">
3
+ <table class="table">
4
+ <thead>
5
+ <tr>
6
+ <th scope="col">Method</th>
7
+ <th scope="col">Type</th>
8
+ <th scope="col">Value</th>
9
+ <th scope="col">Line #</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% path.events.distinct.order(line_number: :asc).each do |event| %>
14
+ <tr>
15
+ <td><%= event.method %></td>
16
+ <td><%= event.event_type %></td>
17
+ <td>
18
+ <code class='small text-wrap'>
19
+ <%= event.return_value %>
20
+ </code>
21
+ </td>
22
+ <td><%= event.line_number %></td>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
27
+ </div>
28
+ <div class="col-4">
29
+ <div class="card mb-4">
30
+ <div class="card-header">
31
+ <%= path.path.split('/')[5..-1].join('/') %> (<%= path.id %>)
32
+ </div>
33
+
34
+ <div class="card-body">
35
+ <pre><code class='language-ruby'><%= path.overlay.html_safe %></code></pre>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ <div class="col-4">
40
+ <% if false %>
41
+ <div class="card mb-4">
42
+ <div class="card-header">
43
+ <%= path.path.split('/')[5..-1].join('/') %> (<%= path.id %>)
44
+ </div>
45
+
46
+ <div class="card-body">
47
+ <pre><code class='language-ruby'><%= path.overlay_code.html_safe %></code></pre>
48
+ </div>
49
+ </div>
50
+ <% end %>
51
+ </div>
52
+ </div>
@@ -0,0 +1,5 @@
1
+ <div class="container-fluid">
2
+ <% @paths.each do |path| %>
3
+ <%= render 'path', path: path %>
4
+ <% end %>
5
+ </div>
@@ -0,0 +1,3 @@
1
+ <div class="container-fluid mt-4">
2
+ <%= render 'path', path: @path %>
3
+ </div>
@@ -0,0 +1,23 @@
1
+ <div class="container-fluid">
2
+ <div class="row mt-2">
3
+ <div class="col-8">
4
+ <table class="table">
5
+ <thead>
6
+ <tr>
7
+ <th scope="col">Spec</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <% @runs.each do |run| %>
12
+ <tr>
13
+ <td>
14
+ <%= link_to(run.process, run_specs_path(run)) %><br />
15
+ <%= run.specs.count %> specs
16
+ </td>
17
+ </tr>
18
+ <% end %>
19
+ </tbody>
20
+ </table>
21
+ </div>
22
+ </div>
23
+ </div>
@@ -0,0 +1,24 @@
1
+ <div class="container-fluid">
2
+ <div class="row mt-2">
3
+ <div class="col-8">
4
+ <table class="table">
5
+ <thead>
6
+ <tr>
7
+ <th scope="col">Spec</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <% @specs.each do |spec| %>
12
+ <tr>
13
+ <td>
14
+ <%= link_to(spec.description, run_spec_example_groups_path(@run, spec)) %><br />
15
+ <%= spec.location %><br />
16
+ <%= spec.example_groups.count %> example groups
17
+ </td>
18
+ </tr>
19
+ <% end %>
20
+ </tbody>
21
+ </table>
22
+ </div>
23
+ </div>
24
+ </div>
@@ -0,0 +1,8 @@
1
+ <nav class="navbar navbar-expand-lg bg-light">
2
+ <div class="container-fluid">
3
+ <a class="navbar-brand" href="#">⚡️ Hyperlayer</a>
4
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
5
+ <span class="navbar-toggler-icon"></span>
6
+ </button>
7
+ </div>
8
+ </nav>
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Hyperlayer</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+
9
+ <%= stylesheet_link_tag 'hyperlayer/application', media: 'all', 'data-turbolinks-track': 'reload' %>
10
+ <%= stylesheet_link_tag 'hyperlayer/app', media: 'all', 'data-turbolinks-track': 'reload' %>
11
+
12
+ <link href="https://unpkg.com/prismjs@1.29.0/themes/prism.css" rel="stylesheet" />
13
+ <link href="https://unpkg.com/prismjs@1.29.0/plugins/line-highlight/prism-line-highlight.css" rel="stylesheet" />
14
+ </head>
15
+
16
+ <body>
17
+ <%= render 'layouts/nav' %>
18
+
19
+ <div class="container-fluid mt-4">
20
+ <div class="row align-items-start">
21
+ <%= yield %>
22
+ </div>
23
+ </div>
24
+
25
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
26
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
27
+ <script src="https://unpkg.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.js"></script>
28
+ <script src="https://unpkg.com/prismjs@1.29.0/plugins/line-highlight/prism-line-highlight.js"></script>
29
+ </body>
30
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,3 @@
1
+ Hyperlayer::Engine.config.paths['db/migrate'].expanded.each do |expanded_path|
2
+ Rails.application.config.paths['db/migrate'] << expanded_path
3
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,11 @@
1
+ Hyperlayer::Engine.routes.draw do
2
+ resources :runs, only: [:index] do
3
+ resources :specs, only: [:index, :show] do
4
+ resources :example_groups do
5
+ resources :events, only: [:index]
6
+ end
7
+ end
8
+ end
9
+
10
+ root 'runs#index'
11
+ end
@@ -0,0 +1,19 @@
1
+ class CreateHyperlayerEvents < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :hyperlayer_events do |t|
4
+ t.string :location
5
+ t.string :defined_class
6
+ t.string :event_type
7
+ t.string :method
8
+ t.text :return_value
9
+ t.integer :path_id
10
+ t.integer :line_number
11
+ t.jsonb :spec
12
+ t.integer :example_group_id
13
+ t.jsonb :arguments
14
+ t.jsonb :variables
15
+
16
+ t.timestamps
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ class CreateHyperlayerExampleGroups < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :hyperlayer_example_groups do |t|
4
+ t.string :location
5
+ t.string :description
6
+ t.integer :spec_id
7
+ t.jsonb :data
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ class CreateHyperlayerRuns < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :hyperlayer_runs do |t|
4
+ t.integer :process
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class CreateHyperlayerPaths < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :hyperlayer_paths do |t|
4
+ t.string :path
5
+ t.boolean :spec
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ class CreateHyperlayerSpecs < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :hyperlayer_specs do |t|
4
+ t.string :location
5
+ t.string :description
6
+ t.jsonb :data
7
+ t.integer :run_id
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ module Hyperlayer
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Hyperlayer
4
+
5
+ initializer "hyperlayer.use_parent_app_database" do
6
+ database_config = Rails.configuration.database_configuration[Rails.env]
7
+ ActiveRecord::Base.establish_connection(database_config)
8
+ end
9
+
10
+ initializer "hyperlayer.load_migrations" do |app|
11
+ unless app.root.to_s.match?(config.root.to_s)
12
+ config.paths["db/migrate"].expanded.each do |expanded_path|
13
+ app.config.paths["db/migrate"] << expanded_path
14
+ end
15
+ end
16
+ end
17
+
18
+ initializer "hyperlayer.assets.precompile" do |app|
19
+ app.config.assets.precompile += %w( hyperlayer/application.css hyperlayer/app.css hyperlayer/prism.css hyperlayer/prism.js hyperlayer/application.js )
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ # lib/hyperlayer/method_tracer.rb
2
+
3
+ class MethodTracer
4
+ def self.arguments_for(tp)
5
+ method_params = tp.self.method(tp.method_id).parameters
6
+ method_params.map do |type, name|
7
+ [name, tp.binding.local_variable_get(name)]
8
+ end.to_h
9
+ rescue => e
10
+ {} # Return an empty hash in case of errors
11
+ end
12
+ end
@@ -0,0 +1,78 @@
1
+ # lib/hyperlayer/tracer.rb
2
+
3
+ module Hyperlayer
4
+ module Tracer
5
+ def self.trace_rspec!
6
+ trace = setup_trace
7
+ trace.enable
8
+
9
+ RSpec.configure do |config|
10
+ config.after(:suite) { trace.disable }
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def self.setup_trace
17
+ TracePoint.new(:call, :return) do |tp|
18
+ next unless relevant_path?(tp.path)
19
+
20
+ event_data = extract_event_data(tp)
21
+
22
+ Redis.new(url: 'redis://localhost:6379').publish('events', event_data.to_json)
23
+ end
24
+ end
25
+
26
+ def self.relevant_path?(path)
27
+ path.include?('tembo')
28
+ end
29
+
30
+ def self.extract_event_data(tp)
31
+ args = MethodTracer.arguments_for(tp)
32
+
33
+ event = {
34
+ path: tp.path,
35
+ line_number: tp.lineno,
36
+ defined_class: tp.defined_class.to_s,
37
+ event: tp.event,
38
+ method_id: tp.method_id,
39
+ arguments: args,
40
+ return_value: (tp.event == :return ? tp.return_value.to_s : nil)
41
+ }
42
+
43
+ # RSpec metadata extraction (as per your original code)
44
+ if defined?(RSpec) && RSpec.respond_to?(:current_example) && RSpec.current_example
45
+ metadata = Hashie::Mash.new(RSpec.current_example.metadata)
46
+
47
+ tree = []
48
+ tree << metadata.except(:example_group, :block)
49
+ tree << metadata.example_group.except(:parent_example_group, :block)
50
+
51
+ parent = metadata.example_group.parent_example_group
52
+
53
+ while parent
54
+ tree << parent.except(:parent_example_group, :block)
55
+ parent = parent.parent_example_group
56
+ end
57
+
58
+ tree.each do |branch|
59
+ branch['described_class'] = branch['described_class'].to_s
60
+ branch['description_args'] = [branch['description_args'].first.to_s]
61
+
62
+ if branch['execution_result']
63
+ branch['execution_result'] = branch['execution_result'].started_at.to_f
64
+ end
65
+ end
66
+
67
+ event[:spec] = {
68
+ process: Process.pid,
69
+ run: metadata.execution_result.started_at.to_f.to_s,
70
+ tree: tree
71
+ }
72
+ end
73
+
74
+ event[:return_value] = nil if event[:return_value]&.class != String
75
+ event
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,3 @@
1
+ module Hyperlayer
2
+ VERSION = "0.1"
3
+ end
data/lib/hyperlayer.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "hyperlayer/version"
2
+ require "hyperlayer/engine"
3
+
4
+ require 'json'
5
+ require 'redis'
6
+ require 'hashie'
7
+ require 'pry'
8
+ require 'hyperlayer/method_tracer'
9
+ require 'hyperlayer/tracer'
10
+
11
+ module Hyperlayer
12
+ def self.trace_rspec!
13
+ Tracer.trace_rspec!
14
+ end
15
+ end