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.
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