From a026167b8d39059cf5d07f72aad48b36489f5e40 Mon Sep 17 00:00:00 2001 From: Kevin Schweikert Date: Thu, 2 Jan 2025 22:25:17 +0100 Subject: [PATCH 1/6] add test modules for curl and req modules --- test/curl_req/curl_test.exs | 4 ++++ test/curl_req/req_test.exs | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 test/curl_req/curl_test.exs create mode 100644 test/curl_req/req_test.exs diff --git a/test/curl_req/curl_test.exs b/test/curl_req/curl_test.exs new file mode 100644 index 0000000..aacedb4 --- /dev/null +++ b/test/curl_req/curl_test.exs @@ -0,0 +1,4 @@ +defmodule CurlReq.CurlTest do + use ExUnit.Case, async: true + doctest CurlReq.Curl +end diff --git a/test/curl_req/req_test.exs b/test/curl_req/req_test.exs new file mode 100644 index 0000000..7602032 --- /dev/null +++ b/test/curl_req/req_test.exs @@ -0,0 +1,4 @@ +defmodule CurlReq.ReqTest do + use ExUnit.Case, async: true + doctest CurlReq.Req +end From 56ad650282737f597c069dd4cb26c0916abac28c Mon Sep 17 00:00:00 2001 From: Kevin Schweikert Date: Thu, 2 Jan 2025 22:25:57 +0100 Subject: [PATCH 2/6] make option parser options available at compile time --- lib/curl_req/curl.ex | 101 ++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 34 deletions(-) diff --git a/lib/curl_req/curl.ex b/lib/curl_req/curl.ex index 601b423..82acc73 100644 --- a/lib/curl_req/curl.ex +++ b/lib/curl_req/curl.ex @@ -5,6 +5,71 @@ defmodule CurlReq.Curl do @behaviour CurlReq.Request + @flags [ + header: :keep, + request: :string, + data: :keep, + data_raw: :keep, + data_ascii: :keep, + cookie: :string, + head: :boolean, + form: :keep, + location: :boolean, + user: :string, + compressed: :boolean, + proxy: :string, + proxy_user: :string, + netrc: :boolean, + netrc_file: :string, + insecure: :boolean, + user_agent: :string + ] + + @aliases [ + H: :header, + X: :request, + d: :data, + b: :cookie, + I: :head, + F: :form, + L: :location, + u: :user, + x: :proxy, + U: :proxy_user, + n: :netrc, + k: :insecure, + A: :user_agent + ] + + @doc """ + Lists supported flags for the cURL command + + ## Examples + + iex> flags = CurlReq.Curl.flags() + iex> {:header, :H} in flags + true + + iex> flags = CurlReq.Curl.flags() + iex> {:compressed, nil} in flags + true + + iex> flags = CurlReq.Curl.flags() + iex> {:foo, nil} in flags + false + """ + @spec flags() :: [{atom(), atom() | nil}] + def flags do + long = Keyword.keys(@flags) + + short_lookup = + Enum.map(@aliases, fn {short, long} -> {long, short} end) |> Enum.into(%{}) + + Enum.map(long, fn flag -> + {flag, short_lookup[flag]} + end) + end + @impl CurlReq.Request @spec decode(String.t()) :: CurlReq.Request.t() def decode(command, _opts \\ []) when is_binary(command) do @@ -18,40 +83,8 @@ defmodule CurlReq.Curl do command |> OptionParser.split() |> OptionParser.parse( - strict: [ - header: :keep, - request: :string, - data: :keep, - data_raw: :keep, - data_ascii: :keep, - cookie: :string, - head: :boolean, - form: :keep, - location: :boolean, - user: :string, - compressed: :boolean, - proxy: :string, - proxy_user: :string, - netrc: :boolean, - netrc_file: :string, - insecure: :boolean, - user_agent: :string - ], - aliases: [ - H: :header, - X: :request, - d: :data, - b: :cookie, - I: :head, - F: :form, - L: :location, - u: :user, - x: :proxy, - U: :proxy_user, - n: :netrc, - k: :insecure, - A: :user_agent - ] + strict: @flags, + aliases: @aliases ) if invalid != [] do From fe281943463de372a2dec734dab70a00988b82c6 Mon Sep 17 00:00:00 2001 From: Kevin Schweikert Date: Thu, 2 Jan 2025 22:26:45 +0100 Subject: [PATCH 3/6] streamline docs --- README.md | 7 +++-- lib/curl_req.ex | 61 ++++++++++++++---------------------------- mix.exs | 2 +- test/curl_req_test.exs | 2 +- 4 files changed, 25 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 09266e6..3750090 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# 🥌 🥌 🥌 CurlReq 🥌 🥌 🥌 +# CurlReq 🥌 - +🥌 🥌 🥌 🥌 🥌 🥌 Req is awesome, but the world speaks curl. @@ -61,7 +61,6 @@ iex> Req.new(url: "/fact", base_url: "https://example.com/") ``` - ## Installation @@ -71,7 +70,7 @@ by adding `curl_req` to your list of dependencies in `mix.exs`: ```elixir def deps do [ - {:curl_req, "~> 0.98.0"} + {:curl_req, "~> 0.100.0"} ] end ``` diff --git a/lib/curl_req.ex b/lib/curl_req.ex index 7321c0f..98caea4 100644 --- a/lib/curl_req.ex +++ b/lib/curl_req.ex @@ -1,10 +1,4 @@ defmodule CurlReq do - @external_resource "README.md" - @moduledoc @external_resource - |> File.read!() - |> String.split("") - |> Enum.fetch!(1) - @req_version :application.get_key(:req, :vsn) |> elem(1) @doc false @@ -73,19 +67,10 @@ defmodule CurlReq do Supported curl flags are: - * `-b`/`--cookie` - * `-H`/`--header` - * `-X`/`--request` - * `-L`/`--location` - * `-I`/`--head` - * `-d`/`--data`/`--data-ascii` - * `--data-raw` - * `-x`/`--proxy` - * `-U`/`--proxy-user` - * `-u`/`--user` - * `-n`/`--netrc` - * `--netrc-file` - * `--compressed` + #{Enum.map(CurlReq.Curl.flags(), fn + {long, nil} -> "* `#{long}`\n" + {long, short} -> "* `#{long}`/`#{short}`\n" + end)} Options: @@ -143,19 +128,10 @@ defmodule CurlReq do Supported curl command line flags are supported: - * `-H`/`--header` - * `-X`/`--request` - * `-d`/`--data` - * `-b`/`--cookie` - * `-I`/`--head` - * `-F`/`--form` - * `-L`/`--location` - * `-u`/`--user` - * `-x`/`--proxy` - * `-U`/`--proxy-user` - * `-n`/`--netrc` - * `--netrc_file` - * `--compressed` + #{Enum.map(CurlReq.Curl.flags(), fn + {long, nil} -> "* `#{long}`\n" + {long, short} -> "* `#{long}`/`#{short}`\n" + end)} The `curl` command prefix is optional @@ -187,24 +163,27 @@ defmodule CurlReq do end @doc """ - Same as `from_curl/1` but as a sigil. The benefit here is, that the Req.Request struct will be created at compile time and you don't need to escape the string + Same as `from_curl/1` but as a sigil. The benefit here is, that the Req.Request struct will be created at compile time and you don't need to escape the string. + Remember to + + ```elixir + import CurlReq + ``` + + to use the custom sigil. ## Examples - iex> import CurlReq - ...> ~CURL(curl "https://www.example.com") + iex> ~CURL(curl "https://www.example.com") %Req.Request{method: :get, url: URI.parse("https://www.example.com")} - iex> import CurlReq - ...> ~CURL(curl -d "some data" "https://example.com") + iex> ~CURL(curl -d "some data" "https://example.com") %Req.Request{method: :get, body: "some data", url: URI.parse("https://example.com")} - iex> import CurlReq - ...> ~CURL(curl -I "https://example.com") + iex> ~CURL(curl -I "https://example.com") %Req.Request{method: :head, url: URI.parse("https://example.com")} - iex> import CurlReq - ...> ~CURL(curl -b "cookie_key=cookie_val" "https://example.com") + iex> ~CURL(curl -b "cookie_key=cookie_val" "https://example.com") %Req.Request{method: :get, headers: %{"cookie" => ["cookie_key=cookie_val"]}, url: URI.parse("https://example.com")} """ defmacro sigil_CURL(curl_command, modifiers) diff --git a/mix.exs b/mix.exs index f00531e..9c3de90 100644 --- a/mix.exs +++ b/mix.exs @@ -36,7 +36,7 @@ defmodule CurlReq.MixProject do [main: "CurlReq", extras: extras()] end - defp extras, do: [] + defp extras, do: ["README.md"] defp package() do [ diff --git a/test/curl_req_test.exs b/test/curl_req_test.exs index ae02686..5d0b4e4 100644 --- a/test/curl_req_test.exs +++ b/test/curl_req_test.exs @@ -1,7 +1,7 @@ defmodule CurlReqTest do use ExUnit.Case, async: true - doctest CurlReq + doctest CurlReq, import: true import CurlReq import ExUnit.CaptureIO From e317dde36a50746deb123f4f27ad2817a556a4da Mon Sep 17 00:00:00 2001 From: Kevin Schweikert Date: Thu, 2 Jan 2025 22:26:55 +0100 Subject: [PATCH 4/6] document flags in readme --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 3750090..622d2bc 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,35 @@ iex> Req.new(url: "/fact", base_url: "https://example.com/") ``` +## Supported Features + +CurlReq parses a bunch of cURL flags and translates them to Req.Request structs and vice versa. To get an up to date list you can call + +```elixir +CurlReq.Curl.flags() +``` + +### Supported Flags + +| Long | Short | Comment | +| --- | --- | --- | +| --header | -H | | +| --request | -X | | +| --data | -d | No file interpolation with `@`| +| --data_raw | | No file interpolation with `@`| +| --data_ascii | | No file interpolation with `@`| +| --cookie | -b | | +| --head | -I | | +| --form | -F | | +| --location | -L | | +| --user | -u | | Only as basic auth +| --compressed | | | +| --proxy | -x | | +| --proxy_user | -U | | Only as basic auth +| --netrc | -n | | +| --netrc_file | | | +| --insecure | -k | | +| --user_agent | -A | | ## Installation From 6b518694d0e2da4bad043674f1c2d332b2f6f5dd Mon Sep 17 00:00:00 2001 From: Kevin Schweikert Date: Thu, 2 Jan 2025 23:01:44 +0100 Subject: [PATCH 5/6] further improve docs --- CHANGELOG.md | 1 + README.md | 42 +++++++++++++++++++----------------------- lib/curl_req.ex | 25 +++++++++++++------------ lib/curl_req/curl.ex | 2 +- lib/curl_req/req.ex | 2 +- mix.exs | 8 ++++---- 6 files changed, 39 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9723762..781834a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [BREAKING]: User Agent is encoded in the user agent flag (`--user-agent`/`-A`) instead of a generic header ([#32](https://github.com/derekkraan/curl_req/pull/32)) - New `CurlReq.Request` module for an internal representation of the HTTP request ([#29](https://github.com/derekkraan/curl_req/pull/29)) - Add new supported flag: `--insecure`/`-k` ([#31](https://github.com/derekkraan/curl_req/pull/31)) +- Improved documentation ## 0.99.0 diff --git a/README.md b/README.md index 622d2bc..c507a8e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CurlReq 🥌 +# 🥌 CurlReq 🥌 🥌 🥌 🥌 🥌 🥌 @@ -63,33 +63,29 @@ iex> Req.new(url: "/fact", base_url: "https://example.com/") ## Supported Features -CurlReq parses a bunch of cURL flags and translates them to Req.Request structs and vice versa. To get an up to date list you can call - -```elixir -CurlReq.Curl.flags() -``` +CurlReq parses a bunch of cURL flags and translates them to Req.Request structs and vice versa. To get an up to date list you can call `CurlReq.Curl.flags/0` ### Supported Flags | Long | Short | Comment | | --- | --- | --- | -| --header | -H | | -| --request | -X | | -| --data | -d | No file interpolation with `@`| -| --data_raw | | No file interpolation with `@`| -| --data_ascii | | No file interpolation with `@`| -| --cookie | -b | | -| --head | -I | | -| --form | -F | | -| --location | -L | | -| --user | -u | | Only as basic auth -| --compressed | | | -| --proxy | -x | | -| --proxy_user | -U | | Only as basic auth -| --netrc | -n | | -| --netrc_file | | | -| --insecure | -k | | -| --user_agent | -A | | +| `--header` | `-H` | | +| `--request` | `-X` | | +| `--data` | `-d` | No file interpolation with `@`| +| `--data_raw` | | No file interpolation with `@`| +| `--data_ascii` | | No file interpolation with `@`| +| `--cookie` | `-b` | | +| `--head` | `-I` | | +| `--form` | `-F` | | +| `--location` | `-L` | | +| `--user` | `-u` | Only as basic auth | +| `--compressed` | | | +| `--proxy` | `-x` | | +| `--proxy_user` | `-U` | Only as basic auth | +| `--netrc` | `-n` | | +| `--netrc_file` | | | +| `--insecure` | `-k` | | +| `--user_agent` | `-A` | | ## Installation diff --git a/lib/curl_req.ex b/lib/curl_req.ex index 98caea4..d71a433 100644 --- a/lib/curl_req.ex +++ b/lib/curl_req.ex @@ -1,6 +1,13 @@ defmodule CurlReq do @req_version :application.get_key(:req, :vsn) |> elem(1) + @flag_docs CurlReq.Curl.flags() + |> Enum.map(fn + {long, nil} -> "* `--#{long}`" + {long, short} -> "* `--#{long}`/`-#{short}`" + end) + |> Enum.join("\n") + @doc false def req_version(), do: @req_version @@ -65,12 +72,9 @@ defmodule CurlReq do @doc """ Transforms a Req request into a curl command. - Supported curl flags are: + The following flags are supported: - #{Enum.map(CurlReq.Curl.flags(), fn - {long, nil} -> "* `#{long}`\n" - {long, short} -> "* `#{long}`/`#{short}`\n" - end)} + #{@flag_docs} Options: @@ -126,12 +130,9 @@ defmodule CurlReq do @doc """ Transforms a curl command into a Req request. - Supported curl command line flags are supported: + The following flags are supported: - #{Enum.map(CurlReq.Curl.flags(), fn - {long, nil} -> "* `#{long}`\n" - {long, short} -> "* `#{long}`/`#{short}`\n" - end)} + #{@flag_docs} The `curl` command prefix is optional @@ -144,7 +145,7 @@ defmodule CurlReq do iex> CurlReq.from_curl("curl https://www.example.com") %Req.Request{method: :get, url: URI.parse("https://www.example.com")} - iex> ~S(curl -d "some data" https://example.com) |> CurlReq.from_curl() + iex> CurlReq.from_curl(~s|curl -d "some data" https://example.com|) %Req.Request{method: :get, body: "some data", url: URI.parse("https://example.com")} iex> CurlReq.from_curl("curl -I https://example.com") @@ -163,7 +164,7 @@ defmodule CurlReq do end @doc """ - Same as `from_curl/1` but as a sigil. The benefit here is, that the Req.Request struct will be created at compile time and you don't need to escape the string. + Same as `from_curl/1` but as a sigil. The benefit here is, that the `Req.Request` struct will be created at compile time and you don't need to escape the string. Remember to ```elixir diff --git a/lib/curl_req/curl.ex b/lib/curl_req/curl.ex index 82acc73..7acbcef 100644 --- a/lib/curl_req/curl.ex +++ b/lib/curl_req/curl.ex @@ -1,6 +1,6 @@ defmodule CurlReq.Curl do @moduledoc """ - Implements the CurlReq.Request behaviour for a cURL command string + Implements the `CurlReq.Request` behaviour for a cURL command string """ @behaviour CurlReq.Request diff --git a/lib/curl_req/req.ex b/lib/curl_req/req.ex index 92f6b49..b93ec4c 100644 --- a/lib/curl_req/req.ex +++ b/lib/curl_req/req.ex @@ -1,6 +1,6 @@ defmodule CurlReq.Req do @moduledoc """ - Implements the CurlReq.Request behaviour for a Req.Request struct + Implements the `CurlReq.Request` behaviour for a `Req.Request` struct """ @behaviour CurlReq.Request diff --git a/mix.exs b/mix.exs index 9c3de90..28383ac 100644 --- a/mix.exs +++ b/mix.exs @@ -27,23 +27,23 @@ defmodule CurlReq.MixProject do [ {:req, "~> 0.4.0 or ~> 0.5.0"}, {:jason, "~> 1.4"}, - {:ex_doc, ">= 0.0.0", only: :dev}, + {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, {:blend, "~> 0.4.1", only: :dev} ] end defp docs do - [main: "CurlReq", extras: extras()] + [main: "README", extras: extras()] end - defp extras, do: ["README.md"] + defp extras, do: ["README.md", "CHANGELOG.md"] defp package() do [ description: "Req 💗 curl", licenses: ["MIT"], links: %{GitHub: "https://github.com/derekkraan/curl_req"}, - maintainers: ["Derek Kraan"] + maintainers: ["Derek Kraan", "Kevin Schweikert"] ] end end From 25b62bcfc1a6fff541aff1e67849305a14bd75a0 Mon Sep 17 00:00:00 2001 From: Kevin Schweikert Date: Fri, 10 Jan 2025 16:54:36 +0100 Subject: [PATCH 6/6] improve README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c507a8e..4b46e9c 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,9 @@ CurlReq parses a bunch of cURL flags and translates them to Req.Request structs ### Supported Flags -| Long | Short | Comment | +The follwing flags are supported in all directions (from Req, from cURL, to Req, to cURL) + +| Long | Short | Limitation | | --- | --- | --- | | `--header` | `-H` | | | `--request` | `-X` | |