From dd3d13561164b55a98596a30793d2b2ae16ac016 Mon Sep 17 00:00:00 2001 From: "Stephen M. Pallen" Date: Wed, 29 Mar 2017 10:11:22 -0400 Subject: [PATCH] create project and some linker impl --- .gitignore | 20 +++++++++++ README.md | 19 ++++++++++ config/config.exs | 30 ++++++++++++++++ lib/auto_linker.ex | 73 +++++++++++++++++++++++++++++++++++++++ mix.exs | 33 ++++++++++++++++++ test/auto_linker_test.exs | 8 +++++ test/test_helper.exs | 1 + 7 files changed, 184 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 config/config.exs create mode 100644 lib/auto_linker.ex create mode 100644 mix.exs create mode 100644 test/auto_linker_test.exs create mode 100644 test/test_helper.exs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6012c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# The directory Mix will write compiled artifacts to. +/_build + +# If you run "mix test --cover", coverage assets end up here. +/cover + +# The directory Mix downloads your dependencies sources to. +/deps + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez diff --git a/README.md b/README.md new file mode 100644 index 0000000..7b37982 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# AutoLinker + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `auto_linker` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [{:auto_linker, "~> 0.1.0"}] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at [https://hexdocs.pm/auto_linker](https://hexdocs.pm/auto_linker). + diff --git a/config/config.exs b/config/config.exs new file mode 100644 index 0000000..78be4ed --- /dev/null +++ b/config/config.exs @@ -0,0 +1,30 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Mix.Config module. +use Mix.Config + +# This configuration is loaded before any dependency and is restricted +# to this project. If another project depends on this project, this +# file won't be loaded nor affect the parent project. For this reason, +# if you want to provide default values for your application for +# 3rd-party users, it should be done in your "mix.exs" file. + +# You can configure for your application as: +# +# config :auto_linker, key: :value +# +# And access this configuration in your application as: +# +# Application.get_env(:auto_linker, :key) +# +# Or configure a 3rd-party app: +# +# config :logger, level: :info +# + +# It is also possible to import configuration files, relative to this +# directory. For example, you can emulate configuration per environment +# by uncommenting the line below and defining dev.exs, test.exs and such. +# Configuration from the imported file will override the ones defined +# here (which is why it is important to import them last). +# +# import_config "#{Mix.env}.exs" diff --git a/lib/auto_linker.ex b/lib/auto_linker.ex new file mode 100644 index 0000000..7cf24fb --- /dev/null +++ b/lib/auto_linker.ex @@ -0,0 +1,73 @@ +defmodule AutoLinker do + @moduledoc """ + Documentation for AutoLinker. + """ + + def link(text, opts \\ []) do + opts = + :url_linker + |> Application.get_all_env() + |> Keyword.merge(opts) + + # rel = opts[:rel] || "noopener noreferrer" + # new_window if opts[:target] + end + + # state = {buffer, acc, state} + defp parse(text, opts) do + parse(text, Keyword.get(opts, :scheme, false), {"", "", false}) + end + + defp parse("", _scheme, opts ,{_, acc, _}), do: acc + + defp parse(text, scheme, opts, {buffer, acc, state}) do + acc <> create_link(text, opts) + parse("", scheme, opts, {buffer, acc, state}) + end + + defp create_link(url, opts) do + [] + |> build_attrs(url, opts, :rel) + |> build_attrs(url, opts, :target) + |> build_attrs(url, opts, :scheme) + |> build_url(url, opts) + end + + defp build_attrs(attrs, _, opts, :rel) do + if rel = Keyword.get(opts, :rel, "noopener noreferrer"), + do: [{:rel, rel} | attrs], else: attrs + end + defp build_attrs(attrs, _, opts, :target) do + if Keyword.get(opts, :new_window, true), + do: [{:target, :_blank} | attrs], else: attrs + end + defp build_attrs(attrs, url, opts, :scheme) do + if String.starts_with?(url, ["http://", "https://"]), + do: [{:href, url} | attrs], else: [{:href, "http://" <> url} | attrs] + end + + defp format_url(attrs, url, opts) do + url = + url + |> strip_prefix(Keyword.get(opts, :strip_prefix, true)) + |> truncate(Keyword.get(opts, :truncate, false)) + attrs = + attrs + |> Enum.map(fn {key, value} -> ~s(#{key}='#{value}') end) + |> Enum.join(" ") + "" <> url <> "" + end + + defp truncate(url, false), do: url + defp truncate(url, len) when len < 3, do: url + defp truncate(url, len) do + if String.length(url) > len, do: String.slice(url, 0, len - 2) <> "..", else: url + end + + defp strip_prefix(url, true) do + url + |> String.replace(~r/^https?:\/\//, "") + |> String.replace(~r/^www\./, "") + end + defp strip_prefix(url, _), do: url +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..df878bd --- /dev/null +++ b/mix.exs @@ -0,0 +1,33 @@ +defmodule AutoLinker.Mixfile do + use Mix.Project + + def project do + [app: :auto_linker, + version: "0.1.0", + elixir: "~> 1.4", + build_embedded: Mix.env == :prod, + start_permanent: Mix.env == :prod, + deps: deps()] + end + + # Configuration for the OTP application + # + # Type "mix help compile.app" for more information + def application do + # Specify extra applications you'll use from Erlang/Elixir + [extra_applications: [:logger]] + end + + # Dependencies can be Hex packages: + # + # {:my_dep, "~> 0.3.0"} + # + # Or git/path repositories: + # + # {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} + # + # Type "mix help deps" for more examples and options + defp deps do + [] + end +end diff --git a/test/auto_linker_test.exs b/test/auto_linker_test.exs new file mode 100644 index 0000000..c4928c3 --- /dev/null +++ b/test/auto_linker_test.exs @@ -0,0 +1,8 @@ +defmodule AutoLinkerTest do + use ExUnit.Case + doctest AutoLinker + + test "the truth" do + assert 1 + 1 == 2 + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start()