# Qx

[![Hex.pm](https://img.shields.io/hexpm/v/qx.svg)](https://hex.pm/packages/qx)
[![Docs](https://img.shields.io/badge/hex-docs-blue.svg)](https://hexdocs.pm/qx)

Qx is a small, dependency-free collection of utilities and helpers for everyday
Elixir work — the handful of functions that otherwise get re-written in every
project.

## Installation

Add `qx` to your dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:qx, "~> 0.2.0"}
  ]
end
```

## What's in the box

### `Qx.String`

Presence checks, URL-safe slugs and display truncation.

```elixir
Qx.String.blank?("   ")                    #=> true
Qx.String.present?("hi")                   #=> true
Qx.String.slugify("Crème Brûlée")          #=> "creme-brulee"
Qx.String.slugify("Elixir Rocks", separator: "_")
                                           #=> "elixir_rocks"
Qx.String.truncate("Hello, World!", 8)     #=> "Hello..."
```

### `Qx.Map`

Reshaping nested data — recursive merging, key conversion and pruning.

```elixir
Qx.Map.deep_merge(%{a: %{b: 1, c: 2}}, %{a: %{c: 3}})
#=> %{a: %{b: 1, c: 3}}

Qx.Map.atomize_keys(%{"a" => %{"b" => 1}})
#=> %{a: %{b: 1}}

Qx.Map.stringify_keys(%{a: %{b: 1}})
#=> %{"a" => %{"b" => 1}}

Qx.Map.compact(%{a: %{b: nil, c: 2}, d: nil}, recursive: true)
#=> %{a: %{c: 2}}
```

`atomize_keys/1` only ever uses *existing* atoms — a key with no matching atom
is left as a string, so untrusted input cannot exhaust the atom table.

### `Qx.Result`

Pipelines over the `{:ok, value}` / `{:error, reason}` tuples Elixir uses
everywhere, so a chain of fallible calls reads top-to-bottom instead of nesting.

```elixir
Qx.Result.ok(2)
|> Qx.Result.map(&(&1 * 5))
|> Qx.Result.and_then(&validate/1)
|> Qx.Result.unwrap(:default)

Qx.Result.collect([{:ok, 1}, {:ok, 2}])            #=> {:ok, [1, 2]}
Qx.Result.collect([{:ok, 1}, {:error, :nope}])     #=> {:error, :nope}
```

### `Qx`

The most frequently reached-for string and map helpers are delegated to the
top-level `Qx` module, so a single `alias Qx` is often enough:

```elixir
Qx.slugify("Hello, World!")                #=> "hello-world"
Qx.deep_merge(%{a: %{b: 1}}, %{a: %{c: 2}})
#=> %{a: %{b: 1, c: 2}}
```

## Documentation

Full API docs are published on [HexDocs](https://hexdocs.pm/qx).

## License

MIT — see [LICENSE](LICENSE).
