Skip to content

Commit

Permalink
Merge pull request #33 from kevinschweikert/feature/feature-matrix
Browse files Browse the repository at this point in the history
Docs and feature matrix
  • Loading branch information
kevinschweikert authored Jan 10, 2025
2 parents 6784ea1 + 25b62bc commit dab1f5e
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 91 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
34 changes: 30 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 🥌 🥌 🥌 CurlReq 🥌 🥌 🥌
# 🥌 CurlReq

<!-- MDOC !-->
🥌 🥌 🥌 🥌 🥌 🥌

Req is awesome, but the world speaks curl.

Expand Down Expand Up @@ -61,7 +61,33 @@ iex> Req.new(url: "/fact", base_url: "https://example.com/")

```

<!-- MDOC !-->
## 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 `CurlReq.Curl.flags/0`

### Supported Flags

The follwing flags are supported in all directions (from Req, from cURL, to Req, to cURL)

| Long | Short | Limitation |
| --- | --- | --- |
| `--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

Expand All @@ -71,7 +97,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
```
Expand Down
72 changes: 26 additions & 46 deletions lib/curl_req.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
defmodule CurlReq do
@external_resource "README.md"
@moduledoc @external_resource
|> File.read!()
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)

@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

Expand Down Expand Up @@ -71,21 +72,9 @@ defmodule CurlReq do
@doc """
Transforms a Req request into a curl command.
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`
The following flags are supported:
#{@flag_docs}
Options:
Expand Down Expand Up @@ -141,21 +130,9 @@ defmodule CurlReq do
@doc """
Transforms a curl command into a Req request.
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`
The following flags are supported:
#{@flag_docs}
The `curl` command prefix is optional
Expand All @@ -168,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")
Expand All @@ -187,24 +164,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)
Expand Down
103 changes: 68 additions & 35 deletions lib/curl_req/curl.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,75 @@
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

@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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/curl_req/req.ex
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 4 additions & 4 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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: []
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
4 changes: 4 additions & 0 deletions test/curl_req/curl_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule CurlReq.CurlTest do
use ExUnit.Case, async: true
doctest CurlReq.Curl
end
4 changes: 4 additions & 0 deletions test/curl_req/req_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule CurlReq.ReqTest do
use ExUnit.Case, async: true
doctest CurlReq.Req
end
2 changes: 1 addition & 1 deletion test/curl_req_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule CurlReqTest do
use ExUnit.Case, async: true

doctest CurlReq
doctest CurlReq, import: true

import CurlReq
import ExUnit.CaptureIO
Expand Down

0 comments on commit dab1f5e

Please sign in to comment.