dev_suite 0.2.7 → 0.2.10

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +12 -0
  3. data/.github/workflows/ci.yml +1 -1
  4. data/.sonarcloud.properties +23 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +17 -33
  7. data/README.md +216 -0
  8. data/dev_suite.gemspec +1 -0
  9. data/examples/helpers/api_helper.rb +51 -0
  10. data/examples/helpers/data_helper.rb +72 -0
  11. data/examples/helpers/helpers.rb +4 -0
  12. data/examples/workflow/basic_workflow.rb +15 -0
  13. data/examples/workflow/composite_workflow.rb +21 -0
  14. data/examples/workflow/conditional_workflow.rb +17 -0
  15. data/examples/workflow/full_workflow.rb +79 -0
  16. data/examples/workflow/loop_workflow.rb +17 -0
  17. data/examples/workflow/order_processing_workflow.rb +163 -0
  18. data/examples/workflow/parallel_workflow.rb +17 -0
  19. data/lib/dev_suite/dev_suite.rb +3 -0
  20. data/lib/dev_suite/method_tracer/config/config.rb +11 -0
  21. data/lib/dev_suite/method_tracer/config/configuration.rb +16 -0
  22. data/lib/dev_suite/method_tracer/config.rb +9 -0
  23. data/lib/dev_suite/method_tracer/helpers.rb +41 -0
  24. data/lib/dev_suite/method_tracer/logger.rb +46 -0
  25. data/lib/dev_suite/method_tracer/method_tracer.rb +20 -0
  26. data/lib/dev_suite/method_tracer/tracer.rb +65 -0
  27. data/lib/dev_suite/method_tracer.rb +7 -0
  28. data/lib/dev_suite/request_builder/builder/base.rb +27 -0
  29. data/lib/dev_suite/request_builder/builder/builder.rb +10 -0
  30. data/lib/dev_suite/request_builder/builder/http.rb +32 -0
  31. data/lib/dev_suite/request_builder/builder.rb +9 -0
  32. data/lib/dev_suite/request_builder/config/config.rb +11 -0
  33. data/lib/dev_suite/request_builder/config/configuration.rb +24 -0
  34. data/lib/dev_suite/request_builder/config.rb +9 -0
  35. data/lib/dev_suite/request_builder/formatter/base.rb +13 -0
  36. data/lib/dev_suite/request_builder/formatter/formatter.rb +10 -0
  37. data/lib/dev_suite/request_builder/formatter/graphql.rb +19 -0
  38. data/lib/dev_suite/request_builder/formatter.rb +9 -0
  39. data/lib/dev_suite/request_builder/request_builder.rb +21 -0
  40. data/lib/dev_suite/request_builder/tool/base.rb +19 -0
  41. data/lib/dev_suite/request_builder/tool/curl.rb +91 -0
  42. data/lib/dev_suite/request_builder/tool/tool.rb +11 -0
  43. data/lib/dev_suite/request_builder/tool/validator/curl.rb +38 -0
  44. data/lib/dev_suite/request_builder/tool/validator/validator.rb +11 -0
  45. data/lib/dev_suite/request_builder/tool/validator.rb +11 -0
  46. data/lib/dev_suite/request_builder/tool.rb +9 -0
  47. data/lib/dev_suite/request_builder.rb +7 -0
  48. data/lib/dev_suite/request_logger/adapter/adapter.rb +11 -9
  49. data/lib/dev_suite/request_logger/adapter/faraday.rb +12 -1
  50. data/lib/dev_suite/request_logger/adapter/middleware/faraday.rb +3 -3
  51. data/lib/dev_suite/request_logger/adapter/net_http.rb +15 -6
  52. data/lib/dev_suite/request_logger/config/configuration.rb +1 -0
  53. data/lib/dev_suite/request_logger/extractor/base.rb +8 -2
  54. data/lib/dev_suite/request_logger/extractor/extractor.rb +5 -6
  55. data/lib/dev_suite/request_logger/extractor/faraday.rb +32 -14
  56. data/lib/dev_suite/request_logger/extractor/net_http.rb +53 -12
  57. data/lib/dev_suite/request_logger/logger.rb +9 -3
  58. data/lib/dev_suite/request_logger/request.rb +12 -0
  59. data/lib/dev_suite/request_logger/response.rb +34 -9
  60. data/lib/dev_suite/utils/construct/component/base.rb +13 -0
  61. data/lib/dev_suite/utils/construct/component/component.rb +1 -0
  62. data/lib/dev_suite/utils/construct/component/manager.rb +27 -10
  63. data/lib/dev_suite/utils/construct/component/validator/base.rb +25 -0
  64. data/lib/dev_suite/utils/construct/component/validator/validation_error.rb +21 -0
  65. data/lib/dev_suite/utils/construct/component/validator/validation_rule.rb +68 -0
  66. data/lib/dev_suite/utils/construct/component/validator/validator.rb +15 -0
  67. data/lib/dev_suite/utils/construct/component/validator.rb +13 -0
  68. data/lib/dev_suite/utils/construct/config/dependency_handler.rb +25 -34
  69. data/lib/dev_suite/utils/construct/config/settings/base.rb +43 -26
  70. data/lib/dev_suite/utils/data/base_operations.rb +61 -0
  71. data/lib/dev_suite/utils/data/data.rb +19 -0
  72. data/lib/dev_suite/utils/data/path_access.rb +172 -0
  73. data/lib/dev_suite/utils/data/search_filter.rb +60 -0
  74. data/lib/dev_suite/utils/data/serialization.rb +29 -0
  75. data/lib/dev_suite/utils/data/transformations.rb +45 -0
  76. data/lib/dev_suite/utils/data.rb +9 -0
  77. data/lib/dev_suite/utils/dependency_loader.rb +2 -2
  78. data/lib/dev_suite/utils/emoji.rb +19 -0
  79. data/lib/dev_suite/utils/file_loader/file_loader.rb +1 -5
  80. data/lib/dev_suite/utils/file_loader/loader/json.rb +4 -1
  81. data/lib/dev_suite/utils/file_loader/loader/loader.rb +23 -19
  82. data/lib/dev_suite/utils/file_loader/loader.rb +0 -2
  83. data/lib/dev_suite/utils/file_writer/atomic_writer.rb +53 -0
  84. data/lib/dev_suite/utils/file_writer/backup_manager.rb +21 -0
  85. data/lib/dev_suite/utils/file_writer/file_writer.rb +24 -0
  86. data/lib/dev_suite/utils/file_writer/writer/base.rb +43 -0
  87. data/lib/dev_suite/utils/file_writer/writer/json.rb +24 -0
  88. data/lib/dev_suite/utils/file_writer/writer/text.rb +27 -0
  89. data/lib/dev_suite/utils/file_writer/writer/writer.rb +14 -0
  90. data/lib/dev_suite/utils/file_writer/writer/yaml.rb +44 -0
  91. data/lib/dev_suite/utils/file_writer/writer.rb +11 -0
  92. data/lib/dev_suite/utils/file_writer/writer_manager.rb +32 -0
  93. data/lib/dev_suite/utils/file_writer.rb +9 -0
  94. data/lib/dev_suite/utils/logger.rb +7 -5
  95. data/lib/dev_suite/utils/store/config/config.rb +13 -0
  96. data/lib/dev_suite/utils/store/config/configuration.rb +30 -0
  97. data/lib/dev_suite/utils/store/config.rb +11 -0
  98. data/lib/dev_suite/utils/store/driver/base.rb +35 -0
  99. data/lib/dev_suite/utils/store/driver/driver.rb +18 -0
  100. data/lib/dev_suite/utils/store/driver/file.rb +61 -0
  101. data/lib/dev_suite/utils/store/driver/memory.rb +42 -0
  102. data/lib/dev_suite/utils/store/driver.rb +11 -0
  103. data/lib/dev_suite/utils/store/store.rb +69 -0
  104. data/lib/dev_suite/utils/store.rb +9 -0
  105. data/lib/dev_suite/utils/utils.rb +17 -5
  106. data/lib/dev_suite/utils/warning_handler.rb +25 -0
  107. data/lib/dev_suite/version.rb +1 -1
  108. data/lib/dev_suite/workflow/engine.rb +27 -0
  109. data/lib/dev_suite/workflow/step/base.rb +56 -0
  110. data/lib/dev_suite/workflow/step/composite.rb +27 -0
  111. data/lib/dev_suite/workflow/step/conditional.rb +23 -0
  112. data/lib/dev_suite/workflow/step/loop.rb +21 -0
  113. data/lib/dev_suite/workflow/step/parallel.rb +18 -0
  114. data/lib/dev_suite/workflow/step/step.rb +21 -0
  115. data/lib/dev_suite/workflow/step.rb +9 -0
  116. data/lib/dev_suite/workflow/step_context.rb +46 -0
  117. data/lib/dev_suite/workflow/workflow.rb +39 -0
  118. data/lib/dev_suite/workflow.rb +7 -0
  119. metadata +101 -3
  120. 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
@@ -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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module MethodTracer
5
+ module Config
6
+ include Utils::Construct::Config::Manager
7
+
8
+ require_relative "configuration"
9
+ end
10
+ end
11
+ 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,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module MethodTracer
5
+ module Config
6
+ require_relative "config/config"
7
+ end
8
+ end
9
+ 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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module MethodTracer
5
+ require_relative "method_tracer/method_tracer"
6
+ end
7
+ 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,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module RequestBuilder
5
+ module Builder
6
+ require_relative "base"
7
+ require_relative "http"
8
+ end
9
+ end
10
+ 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,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module RequestBuilder
5
+ module Builder
6
+ require_relative "builder/builder"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module RequestBuilder
5
+ module Config
6
+ include Utils::Construct::Config::Manager
7
+
8
+ require_relative "configuration"
9
+ end
10
+ end
11
+ 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,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module RequestBuilder
5
+ module Config
6
+ require_relative "config/config"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module RequestBuilder
5
+ module Formatter
6
+ class Base
7
+ def format_body(body)
8
+ raise NotImplementedError, "Subclasses must implement the `format_body` method"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module RequestBuilder
5
+ module Formatter
6
+ require_relative "base"
7
+ require_relative "graphql"
8
+ end
9
+ end
10
+ 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,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DevSuite
4
+ module RequestBuilder
5
+ module Formatter
6
+ require_relative "formatter/formatter"
7
+ end
8
+ end
9
+ 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