README.md

# Fuzzyurl

Non-strict parsing, manipulation, and fuzzy matching of URLs in Elixir.

[![Build Status](https://travis-ci.org/gamache/fuzzyurl.ex.svg?branch=master)](https://travis-ci.org/gamache/fuzzyurl.ex)
[![Hex.pm Version](http://img.shields.io/hexpm/v/fuzzyurl.svg?style=flat)](https://hex.pm/packages/fuzzyurl)
[![Coverage Status](https://coveralls.io/repos/gamache/fuzzyurl.ex/badge.svg?branch=master&service=github)](https://coveralls.io/github/gamache/fuzzyurl.ex?branch=master)


[The full documentation for Fuzzyurl is
here.](http://hexdocs.pm/fuzzyurl/Fuzzyurl.html)


## Adding Fuzzyurl to Your Project

To use Fuzzyurl with your projects, edit your `mix.exs` file and
add it as a dependency:

```elixir
defp deps do
  [{:fuzzyurl, "~> 0.8.0"}]
end
```


## Introduction

Fuzzyurl provides two related functions: non-strict parsing of URLs or
URL-like strings into their component pieces (protocol, username, password,
hostname, port, path, query, and fragment), and fuzzy matching of URLs
and URL patterns.

Specifically, URLs that look like this:

    [protocol ://] [username [: password] @] [hostname] [: port] [/ path] [? query] [# fragment]

Fuzzyurls can be constructed using some or all of the above
fields, optionally replacing some or all of those fields with a `*`
wildcard if you wish to use the Fuzzyurl as a URL mask.


## Parsing URLs

    iex> f = Fuzzyurl.from_string("https://api.example.com/users/123?full=true")
    %Fuzzyurl{fragment: nil, hostname: "api.example.com", password: nil, path: "/users/123", port: nil, protocol: "https", query: "full=true", username: nil}
    iex> f.protocol
    "https"
    iex> f.hostname
    "api.example.com"
    iex> f.query
    "full=true"


## Constructing URLs

    iex> f = Fuzzyurl.new(hostname: "example.com", protocol: "http", port: "8080")
    %Fuzzyurl{fragment: nil, hostname: "example.com", password: nil, path: nil, port: "8080", protocol: "http", query: nil, username: nil}
    iex> Fuzzyurl.to_string(f)
    "http://example.com:8080"


## Matching URLs

Fuzzyurl supports wildcard matching:

* `*` matches anything, including `nil`.
* `foo*` matches `foo`, `foobar`, `foo/bar`, etc.
* `*bar` matches `bar`, `foobar`, `foo/bar`, etc.

Path and hostname matching allows the use of a greedier wildcard `**` in
addition to the naive wildcard `*`:

* `*.example.com` matches `filsrv-01.corp.example.com` but not `example.com`.
* `**.example.com` matches `filsrv-01.corp.example.com` and `example.com`.
* `/some/path/*` matches `/some/path/foo/bar` and `/some/path/`
   but not `/some/path`
* `/some/path/**` matches `/some/path/foo/bar` and `/some/path/`
   and `/some/path`

The `Fuzzyurl.mask/0` and `Fuzzyurl.mask/1` functions aid in the
creation of URL masks.

    iex> m = Fuzzyurl.mask
    %Fuzzyurl{fragment: "*", hostname: "*", password: "*", path: "*", port: "*", protocol: "*", query: "*", username: "*"}
    iex> Fuzzyurl.matches?(m, "http://example.com/a/b/c")
    true

    iex> m2 = Fuzzyurl.mask(path: "/a/b/**")
    %Fuzzyurl{fragment: "*", hostname: "*", password: "*", path: "/a/b/**", port: "*", protocol: "*", query: "*", username: "*"}
    iex> Fuzzyurl.matches?(m2, "https://example.com/a/b/")
    true
    iex> Fuzzyurl.matches?(m2, "git+ssh://jen@example.com/a/b")
    true
    iex> Fuzzyurl.matches?(m2, "https://example.com/a/bar")
    false

`Fuzzyurl.best_match`, given a list of URL masks and a URL, will return
the mask which most closely matches the URL:

    iex> masks = ["/foo/*", "/foo/bar", Fuzzyurl.mask]
    iex> Fuzzyurl.best_match(masks, "http://example.com/foo/bar")
    "/foo/bar"

If you'd prefer the list index of the best-matching URL mask, use
`Fuzzyurl.best_match_index` instead:

    iex> masks = ["/foo/*", "/foo/bar", Fuzzyurl.mask]
    iex> Fuzzyurl.best_match_index(masks, "http://example.com/foo/bar")
    1

## Authorship and License

Fuzzyurl is copyright 2014-2016, Pete Gamache.

Fuzzyurl is released under the MIT License, available at LICENSE.txt.