Page MenuHomePhorge

No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/auto_linker/parser.ex b/lib/auto_linker/parser.ex
index 7cef83f..88ecd7a 100644
--- a/lib/auto_linker/parser.ex
+++ b/lib/auto_linker/parser.ex
@@ -1,96 +1,107 @@
defmodule AutoLinker.Parser do
@moduledoc """
Module to handle parsing the the input string.
"""
alias AutoLinker.Builder
@doc """
Parse the given string.
Parses the string, replacing the matching urls with an html link.
## Examples
iex> AutoLinker.Parser.parse("Check out google.com")
"Check out <a href='http://google.com' class='auto-linker' target='_blank' rel='noopener noreferrer'>google.com</a>"
"""
+ @match_dots ~r/\.\.+/
+
+ @match_url ~r{^[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$}
+ @match_scheme ~r{^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$}
+
def parse(text, opts \\ %{})
def parse(text, list) when is_list(list), do: parse(text, Enum.into(list, %{}))
def parse(text, opts) do
if (exclude = Map.get(opts, :exclude_pattern, false)) && String.starts_with?(text, exclude) do
text
else
parse(text, Map.get(opts, :scheme, false), opts, {"", "", :parsing})
end
end
# state = {buffer, acc, state}
defp parse("", _scheme, _opts ,{"", acc, _}),
do: acc
defp parse("", scheme, opts ,{buffer, acc, _}),
do: acc <> check_and_link(buffer, scheme, opts)
defp parse("<" <> text, scheme, opts, {"", acc, :parsing}),
do: parse(text, scheme, opts, {"<", acc, {:open, 1}})
defp parse(">" <> text, scheme, opts, {buffer, acc, {:attrs, level}}),
do: parse(text, scheme, opts, {"", acc <> buffer <> ">", {:html, level}})
defp parse(<<ch::8>> <> text, scheme, opts, {"", acc, {:attrs, level}}),
do: parse(text, scheme, opts, {"", acc <> <<ch::8>>, {:attrs, level}})
defp parse("</" <> text, scheme, opts, {buffer, acc, {:html, level}}),
do: parse(text, scheme, opts,
{"", acc <> check_and_link(buffer, scheme, opts) <> "</", {:close, level}})
defp parse(">" <> text, scheme, opts, {buffer, acc, {:close, 1}}),
do: parse(text, scheme, opts, {"", acc <> buffer <> ">", :parsing})
defp parse(">" <> text, scheme, opts, {buffer, acc, {:close, level}}),
do: parse(text, scheme, opts, {"", acc <> buffer <> ">", {:html, level - 1}})
defp parse(" " <> text, scheme, opts, {buffer, acc, {:open, level}}),
do: parse(text, scheme, opts, {"", acc <> buffer <> " ", {:attrs, level}})
defp parse("\n" <> text, scheme, opts, {buffer, acc, {:open, level}}),
do: parse(text, scheme, opts, {"", acc <> buffer <> "\n", {:attrs, level}})
# default cases where state is not important
defp parse(" " <> text, scheme, opts, {buffer, acc, state}),
do: parse(text, scheme, opts,
{"", acc <> check_and_link(buffer, scheme, opts) <> " ", state})
defp parse("\n" <> text, scheme, opts, {buffer, acc, state}),
do: parse(text, scheme, opts,
{"", acc <> check_and_link(buffer, scheme, opts) <> "\n", state})
defp parse(<<ch::8>> <> text, scheme, opts, {buffer, acc, state}),
do: parse(text, scheme, opts, {buffer <> <<ch::8>>, acc, state})
defp check_and_link(buffer, scheme, opts) do
buffer
|> is_url?(scheme)
|> link_url(buffer, opts)
end
@doc false
def is_url?(buffer, true) do
- re = ~r{^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$}
- Regex.match? re, buffer
+ if Regex.match? @match_dots, buffer do
+ false
+ else
+ Regex.match? @match_scheme, buffer
+ end
end
def is_url?(buffer, _) do
- re = ~r{^[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$}
- Regex.match? re, buffer
+ if Regex.match? @match_dots, buffer do
+ false
+ else
+ Regex.match? @match_url, buffer
+ end
end
@doc false
def link_url(true, buffer, opts) do
Builder.create_link(buffer, opts)
end
def link_url(_, buffer, _opts), do: buffer
end
diff --git a/mix.exs b/mix.exs
index 3a3bbeb..5954486 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,43 +1,43 @@
defmodule AutoLinker.Mixfile do
use Mix.Project
- @version "0.1.0"
+ @version "0.1.1"
def project do
[
app: :auto_linker,
version: @version,
elixir: "~> 1.4",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps(),
docs: [extras: ["README.md"]],
package: package(),
name: "AutoLinker",
description: """
AutoLinker is a basic package for turning website names into links.
"""
]
end
# Configuration for the OTP application
def application do
# Specify extra applications you'll use from Erlang/Elixir
[extra_applications: [:logger]]
end
# Dependencies can be Hex packages:
defp deps do
[
{:ex_doc, "~> 0.15", only: :dev},
{:earmark, "~> 1.2", only: :dev, override: true},
]
end
defp package do
[ maintainers: ["Stephen Pallen"],
licenses: ["MIT"],
links: %{ "Github" => "https://github.com/smpallen99/auto_linker" },
files: ~w(lib README.md mix.exs LICENSE)]
end
end
diff --git a/test/parser_test.exs b/test/parser_test.exs
index 3553ddb..5c43a10 100644
--- a/test/parser_test.exs
+++ b/test/parser_test.exs
@@ -1,92 +1,93 @@
defmodule AutoLinker.ParserTest do
use ExUnit.Case
doctest AutoLinker.Parser
import AutoLinker.Parser
describe "is_url" do
test "valid scheme true" do
valid_scheme_urls()
|> Enum.each(fn url ->
assert is_url?(url, true)
end)
end
test "invalid scheme true" do
invalid_scheme_urls()
|> Enum.each(fn url ->
refute is_url?(url, true)
end)
end
test "valid scheme false" do
valid_non_scheme_urls()
|> Enum.each(fn url ->
assert is_url?(url, false)
end)
end
test "invalid scheme false" do
invalid_non_scheme_urls()
|> Enum.each(fn url ->
refute is_url?(url, false)
end)
end
end
describe "parse" do
test "does not link attributes" do
text = "Check out <a href='google.com'>google</a>"
assert parse(text) == text
text = "Check out <img src='google.com' alt='google.com'/>"
assert parse(text) == text
text = "Check out <span><img src='google.com' alt='google.com'/></span>"
assert parse(text) == text
end
test "links url inside html" do
text = "Check out <div class='section'>google.com</div>"
expected = "Check out <div class='section'><a href='http://google.com'>google.com</a></div>"
assert parse(text, class: false, rel: false, new_window: false) == expected
end
test "excludes html with specified class" do
text = "```Check out <div class='section'>google.com</div>```"
assert parse(text, exclude_pattern: "```") == text
end
end
def valid_scheme_urls, do: [
"https://www.example.com",
"http://www2.example.com",
"http://home.example-site.com",
"http://blog.example.com",
"http://www.example.com/product",
"http://www.example.com/products?id=1&page=2",
"http://www.example.com#up",
"http://255.255.255.255",
"http://www.site.com:8008"
]
def invalid_scheme_urls, do: [
"http://invalid.com/perl.cgi?key= | http://web-site.com/cgi-bin/perl.cgi?key1=value1&key2",
]
def valid_non_scheme_urls, do: [
"www.example.com",
"www2.example.com",
"www.example.com:2000",
"www.example.com?abc=1",
"example.example-site.com",
"example.com",
"example.ca",
"example.tv",
"example.com:999?one=one",
"255.255.255.255",
"255.255.255.255:3000?one=1&two=2",
]
def invalid_non_scheme_urls, do: [
"invalid.com/perl.cgi?key= | web-site.com/cgi-bin/perl.cgi?key1=value1&key2",
- "invalid."
+ "invalid.",
+ "hi..there"
]
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 30, 1:41 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41436
Default Alt Text
(7 KB)

Event Timeline