diff --git a/curlconverter/generators/ruby.py b/curlconverter/generators/ruby.py new file mode 100644 index 0000000..991e27b --- /dev/null +++ b/curlconverter/generators/ruby.py @@ -0,0 +1,96 @@ +"""Ruby code generator.""" + +import json +from curlconverter.parser import ParsedCurl +from curlconverter.generators import register_generator + + +def _detect_content_type(headers: dict, data: str) -> str: + """Detect content type from headers or data.""" + if "Content-Type" in headers: + return headers["Content-Type"] + if "content-type" in headers: + return headers["content-type"] + if data: + try: + json.loads(data) + return "application/json" + except (json.JSONDecodeError, TypeError): + pass + return "application/x-www-form-urlencoded" + + +@register_generator("ruby") +def generate_ruby(parsed: ParsedCurl) -> str: + """Generate Ruby Net::HTTP code from parsed curl data.""" + lines = [] + lines.append("require 'net/http'") + lines.append("require 'uri'") + lines.append("require 'json'") + lines.append("") + + lines.append("url = URI(" + repr(parsed.url) + ")") + lines.append("") + + lines.append("http = Net::HTTP.new(url.host, url.port)") + lines.append("http.use_ssl = true") + lines.append("") + + headers = dict(parsed.headers) if parsed.headers else {} + + if parsed.user_agent and "User-Agent" not in headers and "user-agent" not in headers: + headers["User-Agent"] = parsed.user_agent + + method_map = { + "GET": "Get", + "POST": "Post", + "PUT": "Put", + "DELETE": "Delete", + "PATCH": "Patch" + } + request_class = f"Net::HTTP::{method_map.get(parsed.method, parsed.method)}" + if parsed.data: + content_type = _detect_content_type(headers, parsed.data) + + if content_type == "application/json": + try: + json_data = json.loads(parsed.data) + lines.append("data = " + json.dumps(json_data)) + request_str = f"Net::HTTP::Post.new(url, {{'Content-Type' => 'application/json'}})" + except (json.JSONDecodeError, TypeError): + lines.append("data = " + repr(parsed.data)) + request_str = f"Net::HTTP::Post.new(url)" + else: + lines.append("data = " + repr(parsed.data)) + request_str = f"Net::HTTP::Post.new(url)" + + if "Content-Type" not in headers and "content-type" not in headers: + headers["Content-Type"] = content_type + else: + request_str = f"{request_class}.new(url)" + + lines.append(f"request = {request_str}") + lines.append("") + + if headers: + for k, v in headers.items(): + lines.append(f'request["{k}"] = "{v}"') + lines.append("") + + if parsed.auth: + lines.append(f'request.basic_auth "{parsed.auth[0]}", "{parsed.auth[1]}"') + lines.append("") + + if parsed.cookies: + lines.append(f'request["Cookie"] = "{parsed.cookies}"') + lines.append("") + + if parsed.data: + lines.append("request.body = data") + lines.append("") + + lines.append("response = http.request(request)") + lines.append("puts response.code") + lines.append("puts response.body") + + return "\n".join(lines)