dev_suite 0.2.7 → 0.2.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +12 -0
- data/.github/workflows/ci.yml +1 -1
- data/.sonarcloud.properties +23 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +17 -33
- data/README.md +216 -0
- data/dev_suite.gemspec +1 -0
- data/examples/helpers/api_helper.rb +51 -0
- data/examples/helpers/data_helper.rb +72 -0
- data/examples/helpers/helpers.rb +4 -0
- data/examples/workflow/basic_workflow.rb +15 -0
- data/examples/workflow/composite_workflow.rb +21 -0
- data/examples/workflow/conditional_workflow.rb +17 -0
- data/examples/workflow/full_workflow.rb +79 -0
- data/examples/workflow/loop_workflow.rb +17 -0
- data/examples/workflow/order_processing_workflow.rb +163 -0
- data/examples/workflow/parallel_workflow.rb +17 -0
- data/lib/dev_suite/dev_suite.rb +3 -0
- data/lib/dev_suite/method_tracer/config/config.rb +11 -0
- data/lib/dev_suite/method_tracer/config/configuration.rb +16 -0
- data/lib/dev_suite/method_tracer/config.rb +9 -0
- data/lib/dev_suite/method_tracer/helpers.rb +41 -0
- data/lib/dev_suite/method_tracer/logger.rb +46 -0
- data/lib/dev_suite/method_tracer/method_tracer.rb +20 -0
- data/lib/dev_suite/method_tracer/tracer.rb +65 -0
- data/lib/dev_suite/method_tracer.rb +7 -0
- data/lib/dev_suite/request_builder/builder/base.rb +27 -0
- data/lib/dev_suite/request_builder/builder/builder.rb +10 -0
- data/lib/dev_suite/request_builder/builder/http.rb +32 -0
- data/lib/dev_suite/request_builder/builder.rb +9 -0
- data/lib/dev_suite/request_builder/config/config.rb +11 -0
- data/lib/dev_suite/request_builder/config/configuration.rb +24 -0
- data/lib/dev_suite/request_builder/config.rb +9 -0
- data/lib/dev_suite/request_builder/formatter/base.rb +13 -0
- data/lib/dev_suite/request_builder/formatter/formatter.rb +10 -0
- data/lib/dev_suite/request_builder/formatter/graphql.rb +19 -0
- data/lib/dev_suite/request_builder/formatter.rb +9 -0
- data/lib/dev_suite/request_builder/request_builder.rb +21 -0
- data/lib/dev_suite/request_builder/tool/base.rb +19 -0
- data/lib/dev_suite/request_builder/tool/curl.rb +91 -0
- data/lib/dev_suite/request_builder/tool/tool.rb +11 -0
- data/lib/dev_suite/request_builder/tool/validator/curl.rb +38 -0
- data/lib/dev_suite/request_builder/tool/validator/validator.rb +11 -0
- data/lib/dev_suite/request_builder/tool/validator.rb +11 -0
- data/lib/dev_suite/request_builder/tool.rb +9 -0
- data/lib/dev_suite/request_builder.rb +7 -0
- data/lib/dev_suite/request_logger/adapter/adapter.rb +11 -9
- data/lib/dev_suite/request_logger/adapter/faraday.rb +12 -1
- data/lib/dev_suite/request_logger/adapter/middleware/faraday.rb +3 -3
- data/lib/dev_suite/request_logger/adapter/net_http.rb +15 -6
- data/lib/dev_suite/request_logger/config/configuration.rb +1 -0
- data/lib/dev_suite/request_logger/extractor/base.rb +8 -2
- data/lib/dev_suite/request_logger/extractor/extractor.rb +5 -6
- data/lib/dev_suite/request_logger/extractor/faraday.rb +32 -14
- data/lib/dev_suite/request_logger/extractor/net_http.rb +53 -12
- data/lib/dev_suite/request_logger/logger.rb +9 -3
- data/lib/dev_suite/request_logger/request.rb +12 -0
- data/lib/dev_suite/request_logger/response.rb +34 -9
- data/lib/dev_suite/utils/construct/component/base.rb +13 -0
- data/lib/dev_suite/utils/construct/component/component.rb +1 -0
- data/lib/dev_suite/utils/construct/component/manager.rb +27 -10
- data/lib/dev_suite/utils/construct/component/validator/base.rb +25 -0
- data/lib/dev_suite/utils/construct/component/validator/validation_error.rb +21 -0
- data/lib/dev_suite/utils/construct/component/validator/validation_rule.rb +68 -0
- data/lib/dev_suite/utils/construct/component/validator/validator.rb +15 -0
- data/lib/dev_suite/utils/construct/component/validator.rb +13 -0
- data/lib/dev_suite/utils/construct/config/dependency_handler.rb +25 -34
- data/lib/dev_suite/utils/construct/config/settings/base.rb +43 -26
- data/lib/dev_suite/utils/data/base_operations.rb +61 -0
- data/lib/dev_suite/utils/data/data.rb +19 -0
- data/lib/dev_suite/utils/data/path_access.rb +172 -0
- data/lib/dev_suite/utils/data/search_filter.rb +60 -0
- data/lib/dev_suite/utils/data/serialization.rb +29 -0
- data/lib/dev_suite/utils/data/transformations.rb +45 -0
- data/lib/dev_suite/utils/data.rb +9 -0
- data/lib/dev_suite/utils/dependency_loader.rb +2 -2
- data/lib/dev_suite/utils/emoji.rb +19 -0
- data/lib/dev_suite/utils/file_loader/file_loader.rb +1 -5
- data/lib/dev_suite/utils/file_loader/loader/json.rb +4 -1
- data/lib/dev_suite/utils/file_loader/loader/loader.rb +23 -19
- data/lib/dev_suite/utils/file_loader/loader.rb +0 -2
- data/lib/dev_suite/utils/file_writer/atomic_writer.rb +53 -0
- data/lib/dev_suite/utils/file_writer/backup_manager.rb +21 -0
- data/lib/dev_suite/utils/file_writer/file_writer.rb +24 -0
- data/lib/dev_suite/utils/file_writer/writer/base.rb +43 -0
- data/lib/dev_suite/utils/file_writer/writer/json.rb +24 -0
- data/lib/dev_suite/utils/file_writer/writer/text.rb +27 -0
- data/lib/dev_suite/utils/file_writer/writer/writer.rb +14 -0
- data/lib/dev_suite/utils/file_writer/writer/yaml.rb +44 -0
- data/lib/dev_suite/utils/file_writer/writer.rb +11 -0
- data/lib/dev_suite/utils/file_writer/writer_manager.rb +32 -0
- data/lib/dev_suite/utils/file_writer.rb +9 -0
- data/lib/dev_suite/utils/logger.rb +7 -5
- data/lib/dev_suite/utils/store/config/config.rb +13 -0
- data/lib/dev_suite/utils/store/config/configuration.rb +30 -0
- data/lib/dev_suite/utils/store/config.rb +11 -0
- data/lib/dev_suite/utils/store/driver/base.rb +35 -0
- data/lib/dev_suite/utils/store/driver/driver.rb +18 -0
- data/lib/dev_suite/utils/store/driver/file.rb +61 -0
- data/lib/dev_suite/utils/store/driver/memory.rb +42 -0
- data/lib/dev_suite/utils/store/driver.rb +11 -0
- data/lib/dev_suite/utils/store/store.rb +69 -0
- data/lib/dev_suite/utils/store.rb +9 -0
- data/lib/dev_suite/utils/utils.rb +17 -5
- data/lib/dev_suite/utils/warning_handler.rb +25 -0
- data/lib/dev_suite/version.rb +1 -1
- data/lib/dev_suite/workflow/engine.rb +27 -0
- data/lib/dev_suite/workflow/step/base.rb +56 -0
- data/lib/dev_suite/workflow/step/composite.rb +27 -0
- data/lib/dev_suite/workflow/step/conditional.rb +23 -0
- data/lib/dev_suite/workflow/step/loop.rb +21 -0
- data/lib/dev_suite/workflow/step/parallel.rb +18 -0
- data/lib/dev_suite/workflow/step/step.rb +21 -0
- data/lib/dev_suite/workflow/step.rb +9 -0
- data/lib/dev_suite/workflow/step_context.rb +46 -0
- data/lib/dev_suite/workflow/workflow.rb +39 -0
- data/lib/dev_suite/workflow.rb +7 -0
- metadata +101 -3
- data/lib/dev_suite/utils/construct/component/initializer.rb +0 -28
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
|
4
|
+
require "dev_suite"
|
5
|
+
|
6
|
+
# Create a workflow with a looping step
|
7
|
+
engine = DevSuite::Workflow::Engine.new(iteration_count: 0)
|
8
|
+
|
9
|
+
# Add a loop step
|
10
|
+
loop_step = DevSuite::Workflow.create_loop_step("Repeat Task", 3) do |context|
|
11
|
+
iteration = context.get(:iteration_count) + 1
|
12
|
+
context.update({ iteration_count: iteration })
|
13
|
+
puts "Iteration #{iteration}"
|
14
|
+
end
|
15
|
+
|
16
|
+
engine.step(loop_step)
|
17
|
+
engine.execute
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../helpers"
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
|
6
|
+
require "dev_suite"
|
7
|
+
|
8
|
+
# Constants
|
9
|
+
BASE_URL = "https://ecommerce.example.com"
|
10
|
+
NUMBER_OF_USERS = 500
|
11
|
+
CHUNK_SIZE = 50
|
12
|
+
DEFAULT_PASSWORD = "password123"
|
13
|
+
STORE_PATH = "tmp/order_store.json"
|
14
|
+
|
15
|
+
# Headers for HTTP requests
|
16
|
+
REQUEST_HEADERS = {
|
17
|
+
"accept" => "*/*",
|
18
|
+
"content-type" => "application/x-www-form-urlencoded",
|
19
|
+
"user-agent" => "Mozilla/5.0",
|
20
|
+
}
|
21
|
+
|
22
|
+
# Helper Functions
|
23
|
+
def register_user(username, phone, password)
|
24
|
+
endpoint = "#{BASE_URL}/api/v1/register"
|
25
|
+
body_data = { "username" => username, "phone" => phone, "password" => password }
|
26
|
+
APIHelper.make_post_request(endpoint: endpoint, body_data: body_data, success_criteria: ->(response) {
|
27
|
+
response["status"] == "success"
|
28
|
+
})
|
29
|
+
end
|
30
|
+
|
31
|
+
def login_user(username, password)
|
32
|
+
endpoint = "#{BASE_URL}/api/v1/login"
|
33
|
+
body_data = { "username" => username, "password" => password }
|
34
|
+
APIHelper.make_post_request(endpoint: endpoint, body_data: body_data, success_criteria: ->(response) {
|
35
|
+
response["token"].present?
|
36
|
+
})
|
37
|
+
end
|
38
|
+
|
39
|
+
def fetch_order(token, user_id)
|
40
|
+
endpoint = "#{BASE_URL}/api/v1/orders"
|
41
|
+
body_data = { "token" => token, "user_id" => user_id }
|
42
|
+
APIHelper.make_post_request(endpoint: endpoint, body_data: body_data, success_criteria: ->(response) {
|
43
|
+
response["order_id"].present?
|
44
|
+
})
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_payment(order_id, token, user_id)
|
48
|
+
endpoint = "#{BASE_URL}/api/v1/pay"
|
49
|
+
body_data = { "order_id" => order_id, "token" => token, "user_id" => user_id }
|
50
|
+
APIHelper.make_post_request(endpoint: endpoint, body_data: body_data, success_criteria: ->(response) {
|
51
|
+
response["status"] == "success"
|
52
|
+
})
|
53
|
+
end
|
54
|
+
|
55
|
+
# Workflow Steps
|
56
|
+
register_step = DevSuite::Workflow.create_step("Register Users") do |ctx|
|
57
|
+
users = []
|
58
|
+
password = ctx.get(:password)
|
59
|
+
|
60
|
+
# Generate fake users using Faker
|
61
|
+
user_tasks = Array.new(NUMBER_OF_USERS) do
|
62
|
+
{
|
63
|
+
username: DataHelper.generate_human_username,
|
64
|
+
phone: DataHelper.generate_phone_number,
|
65
|
+
password: password,
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
user_chunks = user_tasks.each_slice(CHUNK_SIZE).to_a
|
70
|
+
|
71
|
+
user_chunks.each do |chunk|
|
72
|
+
parallel_step = DevSuite::Workflow.create_parallel_step("Parallel Registration") do |ctx|
|
73
|
+
chunk.map do |user_data|
|
74
|
+
->(ctx) {
|
75
|
+
username = user_data[:username]
|
76
|
+
phone = user_data[:phone]
|
77
|
+
password = user_data[:password]
|
78
|
+
|
79
|
+
puts "Registering user #{username}..."
|
80
|
+
response = register_user(username, phone, password)
|
81
|
+
|
82
|
+
if response[:success]
|
83
|
+
puts "User #{username} registered successfully!"
|
84
|
+
users << user_data
|
85
|
+
else
|
86
|
+
puts "Failed to register #{username}: #{response&.dig(:response, "error") || "Unknown error"}"
|
87
|
+
end
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
parallel_step.run(ctx)
|
92
|
+
end
|
93
|
+
|
94
|
+
ctx.set(:users, users)
|
95
|
+
ctx.data
|
96
|
+
end
|
97
|
+
|
98
|
+
save_users_step = DevSuite::Workflow.create_conditional_step("Save Users to Store", ->(ctx) {
|
99
|
+
ctx.get(:users)&.any?
|
100
|
+
}) do |ctx|
|
101
|
+
ctx.store.set(:users, ctx.get(:users))
|
102
|
+
puts "Saved #{ctx.get(:users).size} users to the store."
|
103
|
+
ctx.data
|
104
|
+
end
|
105
|
+
|
106
|
+
login_step = DevSuite::Workflow.create_conditional_step("Login Users", ->(ctx) {
|
107
|
+
ctx.get(:username) && ctx.get(:password)
|
108
|
+
}) do |ctx|
|
109
|
+
response = login_user(ctx.get(:username), ctx.get(:password))
|
110
|
+
|
111
|
+
if response[:success]
|
112
|
+
ctx.set(:token, response[:response]["token"])
|
113
|
+
ctx.set(:user_id, response[:response]["user_id"])
|
114
|
+
puts "User #{ctx.get(:username)} logged in successfully!"
|
115
|
+
else
|
116
|
+
puts "Failed to log in user #{ctx.get(:username)}."
|
117
|
+
end
|
118
|
+
|
119
|
+
ctx.data
|
120
|
+
end
|
121
|
+
|
122
|
+
fetch_order_step = DevSuite::Workflow.create_conditional_step("Fetch Orders", ->(ctx) {
|
123
|
+
ctx.get(:token) && ctx.get(:user_id)
|
124
|
+
}) do |ctx|
|
125
|
+
response = fetch_order(ctx.get(:token), ctx.get(:user_id))
|
126
|
+
|
127
|
+
if response[:success]
|
128
|
+
ctx.set(:order_id, response[:response]["order_id"])
|
129
|
+
puts "Order fetched for user #{ctx.get(:username)}: Order ID #{response[:response]["order_id"]}"
|
130
|
+
else
|
131
|
+
puts "Failed to fetch order for user #{ctx.get(:username)}."
|
132
|
+
end
|
133
|
+
|
134
|
+
ctx.data
|
135
|
+
end
|
136
|
+
|
137
|
+
process_payment_step = DevSuite::Workflow.create_conditional_step("Process Payment", ->(ctx) {
|
138
|
+
ctx.get(:order_id) && ctx.get(:token) && ctx.get(:user_id)
|
139
|
+
}) do |ctx|
|
140
|
+
response = process_payment(ctx.get(:order_id), ctx.get(:token), ctx.get(:user_id))
|
141
|
+
|
142
|
+
if response[:success]
|
143
|
+
puts "Payment processed for order #{ctx.get(:order_id)}."
|
144
|
+
else
|
145
|
+
puts "Failed to process payment for order #{ctx.get(:order_id)}."
|
146
|
+
end
|
147
|
+
|
148
|
+
ctx.data
|
149
|
+
end
|
150
|
+
|
151
|
+
# Main Workflow Execution
|
152
|
+
workflow = DevSuite::Workflow.create_engine(
|
153
|
+
{ password: DEFAULT_PASSWORD },
|
154
|
+
driver: :file,
|
155
|
+
path: STORE_PATH,
|
156
|
+
)
|
157
|
+
|
158
|
+
workflow.step(register_step)
|
159
|
+
.step(save_users_step)
|
160
|
+
.step(login_step)
|
161
|
+
.step(fetch_order_step)
|
162
|
+
.step(process_payment_step)
|
163
|
+
.execute
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
|
4
|
+
require "dev_suite"
|
5
|
+
|
6
|
+
# Create a workflow with parallel tasks
|
7
|
+
engine = DevSuite::Workflow::Engine.new
|
8
|
+
|
9
|
+
parallel_step = DevSuite::Workflow.create_parallel_step("Parallel Task") do |context|
|
10
|
+
[
|
11
|
+
->(ctx) { puts "Task 1 executed" },
|
12
|
+
->(ctx) { puts "Task 2 executed" },
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
engine.step(parallel_step)
|
17
|
+
engine.execute
|
data/lib/dev_suite/dev_suite.rb
CHANGED
@@ -7,6 +7,9 @@ module DevSuite
|
|
7
7
|
require_relative "performance"
|
8
8
|
require_relative "directory_tree"
|
9
9
|
require_relative "request_logger"
|
10
|
+
require_relative "request_builder"
|
11
|
+
require_relative "workflow"
|
12
|
+
require_relative "method_tracer"
|
10
13
|
|
11
14
|
class Error < StandardError; end
|
12
15
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module MethodTracer
|
5
|
+
module Config
|
6
|
+
class Configuration < Utils::Construct::Config::Base
|
7
|
+
set_default_settings(
|
8
|
+
show_params: false,
|
9
|
+
show_results: false,
|
10
|
+
show_execution_time: false,
|
11
|
+
max_depth: nil,
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module MethodTracer
|
5
|
+
module Helpers
|
6
|
+
class << self
|
7
|
+
def internal_call?(tp)
|
8
|
+
tp.path&.include?("<internal:") || tp.defined_class.to_s.start_with?("TracePoint")
|
9
|
+
end
|
10
|
+
|
11
|
+
def format_method_name(tp)
|
12
|
+
"#{tp.defined_class}##{tp.method_id}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def format_params(tp)
|
16
|
+
param_values = tp.binding.local_variables.map do |var|
|
17
|
+
tp.binding.local_variable_get(var).inspect
|
18
|
+
end.join(", ")
|
19
|
+
"(#{param_values})"
|
20
|
+
end
|
21
|
+
|
22
|
+
def format_result(tp)
|
23
|
+
" #=> #{tp.return_value.inspect}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def format_execution_time(duration)
|
27
|
+
duration ? " in #{duration}ms" : ""
|
28
|
+
end
|
29
|
+
|
30
|
+
def calculate_duration(tp, start_times)
|
31
|
+
start_time = start_times.delete(tp.method_id)
|
32
|
+
start_time ? ((Time.now - start_time) * 1000.0).round(2) : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def calculate_indent(depth)
|
36
|
+
" " * [(depth - 1), 0].max
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module MethodTracer
|
5
|
+
module Logger
|
6
|
+
class << self
|
7
|
+
def log_method_call(tp, tracer)
|
8
|
+
tracer.depth += 1
|
9
|
+
|
10
|
+
method_name = Helpers.format_method_name(tp)
|
11
|
+
params_str = Helpers.format_params(tp) if tracer.show_params
|
12
|
+
indent = Helpers.calculate_indent(tracer.depth)
|
13
|
+
|
14
|
+
# Store the start time for execution time calculation
|
15
|
+
tracer.start_times[tp.method_id] = Time.now
|
16
|
+
|
17
|
+
message = "#{indent}#depth:#{tracer.depth} > #{method_name} at #{tp.path}:#{tp.lineno} #{params_str}"
|
18
|
+
Utils::Logger.log(
|
19
|
+
message,
|
20
|
+
emoji: :start,
|
21
|
+
color: :blue,
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def log_method_return(tp, tracer)
|
26
|
+
duration = Helpers.calculate_duration(tp, tracer.start_times)
|
27
|
+
|
28
|
+
method_name = Helpers.format_method_name(tp)
|
29
|
+
result_str = Helpers.format_result(tp) if tracer.show_results
|
30
|
+
exec_time_str = Helpers.format_execution_time(duration) if tracer.show_execution_time
|
31
|
+
indent = Helpers.calculate_indent(tracer.depth)
|
32
|
+
|
33
|
+
message = "#{indent}#depth:#{tracer.depth} < #{method_name}#{result_str} at #{tp.path}:#{tp.lineno}#{exec_time_str}"
|
34
|
+
Utils::Logger.log(
|
35
|
+
message,
|
36
|
+
emoji: :finish,
|
37
|
+
color: :cyan,
|
38
|
+
)
|
39
|
+
|
40
|
+
# Decrement depth safely
|
41
|
+
tracer.depth = [tracer.depth - 1, 0].max
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module MethodTracer
|
5
|
+
require_relative "tracer"
|
6
|
+
require_relative "logger"
|
7
|
+
require_relative "helpers"
|
8
|
+
require_relative "config"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def trace(options = {}, &block)
|
12
|
+
# Merge global configuration with options provided in the call
|
13
|
+
settings = Config.configuration.settings.merge(options)
|
14
|
+
|
15
|
+
# Use the merged settings to initialize the tracer
|
16
|
+
Tracer.new(**settings).trace(&block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module MethodTracer
|
5
|
+
class Tracer
|
6
|
+
attr_reader :show_params, :show_results, :show_execution_time, :max_depth
|
7
|
+
attr_accessor :depth, :trace_point, :start_times
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
show_params: false,
|
11
|
+
show_results: false,
|
12
|
+
show_execution_time: false,
|
13
|
+
max_depth: nil
|
14
|
+
)
|
15
|
+
@show_params = show_params
|
16
|
+
@show_results = show_results
|
17
|
+
@show_execution_time = show_execution_time
|
18
|
+
@max_depth = max_depth
|
19
|
+
@depth = 0
|
20
|
+
@start_times = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def trace(&block)
|
24
|
+
setup_trace_point
|
25
|
+
trace_point.enable
|
26
|
+
block.call
|
27
|
+
ensure
|
28
|
+
trace_point&.disable
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def setup_trace_point
|
34
|
+
self.trace_point = TracePoint.new(:call, :return) do |tp|
|
35
|
+
next if Helpers.internal_call?(tp)
|
36
|
+
|
37
|
+
handle_trace_point_event(tp)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_trace_point_event(tp)
|
42
|
+
case tp.event
|
43
|
+
when :call
|
44
|
+
handle_call_event(tp)
|
45
|
+
when :return
|
46
|
+
handle_return_event(tp)
|
47
|
+
else
|
48
|
+
raise "Unknown event type: #{tp.event}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle_call_event(tp)
|
53
|
+
Logger.log_method_call(tp, self) if depth_within_limit?
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_return_event(tp)
|
57
|
+
Logger.log_method_return(tp, self) if depth_within_limit?
|
58
|
+
end
|
59
|
+
|
60
|
+
def depth_within_limit?
|
61
|
+
max_depth.nil? || @depth < max_depth
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module RequestBuilder
|
5
|
+
module Builder
|
6
|
+
class Base
|
7
|
+
attr_reader :url, :headers, :tool
|
8
|
+
|
9
|
+
def initialize(url:, headers: {}, tool:)
|
10
|
+
@url = url
|
11
|
+
@headers = headers
|
12
|
+
@tool = tool
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_command
|
16
|
+
raise NotImplementedError, "Subclasses must implement the `build_command` method"
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def format_headers
|
22
|
+
headers.map { |key, value| "#{key}: #{value}" }.join("\n")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module RequestBuilder
|
5
|
+
module Builder
|
6
|
+
class Http < Base
|
7
|
+
attr_reader :http_method, :body
|
8
|
+
|
9
|
+
def initialize(url:, http_method: "GET", headers: {}, body: nil, tool:)
|
10
|
+
super(url: url, headers: headers, tool: tool)
|
11
|
+
@http_method = http_method.upcase
|
12
|
+
@body = body
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_command
|
16
|
+
case tool
|
17
|
+
when :curl
|
18
|
+
Tool::Curl.new.build_command(http_method: http_method, url: url, headers: headers, body: format_body(body))
|
19
|
+
else
|
20
|
+
raise ArgumentError, "Unknown tool: #{tool}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def format_body(body)
|
27
|
+
Formatter::Graphql.new.format_body(body)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module RequestBuilder
|
5
|
+
module Config
|
6
|
+
class Configuration < Utils::Construct::Config::Base
|
7
|
+
set_default_settings(
|
8
|
+
tool: {
|
9
|
+
curl: {
|
10
|
+
use_insecure: false,
|
11
|
+
raw_data: false,
|
12
|
+
verbose: false,
|
13
|
+
follow_redirects: true,
|
14
|
+
cookie: nil,
|
15
|
+
user_agent: "Mozilla/5.0 (compatible; RequestBuilder/1.0)",
|
16
|
+
max_time: nil,
|
17
|
+
connect_timeout: nil,
|
18
|
+
},
|
19
|
+
},
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module RequestBuilder
|
5
|
+
module Formatter
|
6
|
+
class Graphql < Base
|
7
|
+
def format_body(body)
|
8
|
+
if body.is_a?(Hash) && body[:query] && body[:variables]
|
9
|
+
{ query: body[:query], variables: body[:variables] }.to_json
|
10
|
+
elsif body.is_a?(String)
|
11
|
+
{ query: body, variables: {} }.to_json
|
12
|
+
else
|
13
|
+
raise ArgumentError, "Invalid GraphQL body format"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module RequestBuilder
|
5
|
+
require_relative "config"
|
6
|
+
require_relative "formatter"
|
7
|
+
require_relative "tool"
|
8
|
+
require_relative "builder"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def build(protocol:, tool:, **options)
|
12
|
+
case protocol
|
13
|
+
when :http
|
14
|
+
Builder::Http.new(tool: tool, **options)
|
15
|
+
else
|
16
|
+
raise ArgumentError, "Unknown protocol: #{protocol}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DevSuite
|
4
|
+
module RequestBuilder
|
5
|
+
module Tool
|
6
|
+
class Base < Utils::Construct::Component::Base
|
7
|
+
def build_command(http_method:, url:, headers:, body: nil)
|
8
|
+
raise NotImplementedError
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def fetch_setting(key, default: nil)
|
14
|
+
Config.configuration.settings.get(key, default: default)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|