Browse Source

mix format

tags/microformats2-0.1.0
Christian Kruse 2 years ago
parent
commit
6481ebc506
8 changed files with 645 additions and 434 deletions
  1. +5
    -0
      .formatter.exs
  2. +83
    -61
      lib/implied.ex
  3. +93
    -61
      lib/items.ex
  4. +24
    -20
      lib/microformats2.ex
  5. +30
    -37
      lib/rels.ex
  6. +17
    -15
      mix.exs
  7. +244
    -133
      test/items_test.exs
  8. +149
    -107
      test/rels_test.exs

+ 5
- 0
.formatter.exs View File

@@ -0,0 +1,5 @@
[
inputs: ["lib/**/*.{ex,exs}", "mix.exs", "config/*.exs", "test/**/*.{ex,exs}"],
line_length: 120,
rename_deprecated_at: "1.4.5"
]

+ 83
- 61
lib/implied.ex View File

@@ -1,19 +1,21 @@
defmodule Microformats2.Items.ImpliedProperties do
def parse(entry, root, url, doc) do
implied_name_property(entry, root) |>
implied_photo_property(root) |>
implied_url_property(root, url, doc)
implied_name_property(entry, root)
|> implied_photo_property(root)
|> implied_url_property(root, url, doc)
end

defp implied_url_property(entry, root, doc_url, doc) do
if entry[:properties][:url] == nil do
val = implied_url_attrval(root)

url = if Microformats2.blank?(val) do
implied_url_deep(root)
else
val
end |> Microformats2.stripped_or_nil
url =
if Microformats2.blank?(val) do
implied_url_deep(root)
else
val
end
|> Microformats2.stripped_or_nil()

if Microformats2.blank?(url) do
entry
@@ -29,11 +31,13 @@ defmodule Microformats2.Items.ImpliedProperties do
if entry[:properties][:photo] == nil do
val = implied_photo_attrval(root)

url = if Microformats2.blank?(val) do
implied_photo_deep(root)
else
val
end |> Microformats2.stripped_or_nil
url =
if Microformats2.blank?(val) do
implied_photo_deep(root)
else
val
end
|> Microformats2.stripped_or_nil()

if Microformats2.blank?(url) do
entry
@@ -45,24 +49,26 @@ defmodule Microformats2.Items.ImpliedProperties do
end
end


defp implied_name_property(entry, root = {elem, _, _}) do
if entry[:properties][:name] == nil do
nam = cond do
elem == "img" or elem == "area" ->
Floki.attribute(root, "alt") |> List.first
elem == "abbr" ->
Floki.attribute(root, "title") |> List.first
true ->
val = implied_name_deep(root)

if Microformats2.blank?(val) do
Microformats2.Items.text_content(root)
else
val
end

end |> Microformats2.stripped_or_nil
nam =
cond do
elem == "img" or elem == "area" ->
Floki.attribute(root, "alt") |> List.first()

elem == "abbr" ->
Floki.attribute(root, "title") |> List.first()

true ->
val = implied_name_deep(root)

if Microformats2.blank?(val) do
Microformats2.Items.text_content(root)
else
val
end
end
|> Microformats2.stripped_or_nil()

Map.put(entry, :properties, Map.put(entry[:properties], :name, [nam]))
else
@@ -71,9 +77,11 @@ defmodule Microformats2.Items.ImpliedProperties do
end

defp implied_name_deep({_, _, children}) do
only_nodes = Enum.filter(children,
fn(el) when is_bitstring(el) -> false
(_) -> true end)
only_nodes =
Enum.filter(children, fn
el when is_bitstring(el) -> false
_ -> true
end)

if Enum.count(only_nodes) == 1 do
sec_node = List.first(only_nodes)
@@ -81,12 +89,14 @@ defmodule Microformats2.Items.ImpliedProperties do
attrval = implied_name_attrval(sec_node)

if Microformats2.blank?(attrval) do
sec_only_nodes = Enum.filter(sec_node_children,
fn(el) when is_bitstring(el) -> false
(_) -> true end)
sec_only_nodes =
Enum.filter(sec_node_children, fn
el when is_bitstring(el) -> false
_ -> true
end)

if Enum.count(sec_only_nodes) == 1 do
third_node = sec_only_nodes |> List.first
third_node = sec_only_nodes |> List.first()
implied_name_attrval(third_node)
end
else
@@ -96,35 +106,40 @@ defmodule Microformats2.Items.ImpliedProperties do
end

defp implied_name_attrval(node = {"img", _, _}) do
Floki.attribute(node, "alt") |> List.first
Floki.attribute(node, "alt") |> List.first()
end

defp implied_name_attrval(node = {"area", _, _}) do
Floki.attribute(node, "alt") |> List.first
Floki.attribute(node, "alt") |> List.first()
end

defp implied_name_attrval(node = {"abbr", _, _}) do
Floki.attribute(node, "title") |> List.first
Floki.attribute(node, "title") |> List.first()
end

defp implied_name_attrval(_) do
nil
end



defp implied_photo_deep(root) do
imgs = direct_not_h_children_with_attr(root, "img", "src")
objects = direct_not_h_children_with_attr(root, "object", "data")

cond do
Enum.count(imgs) == 1 ->
List.first(imgs) |> Floki.attribute("src") |> List.first
List.first(imgs) |> Floki.attribute("src") |> List.first()

Enum.count(objects) == 1 ->
List.first(objects) |> Floki.attribute("data") |> List.first
List.first(objects) |> Floki.attribute("data") |> List.first()

true ->
{_, _, children} = root
only_nodes = Enum.filter(children,
fn(el) when is_bitstring(el) -> false
(_) -> true end)

only_nodes =
Enum.filter(children, fn
el when is_bitstring(el) -> false
_ -> true
end)

if Enum.count(only_nodes) == 1 do
child = List.first(children)
@@ -133,9 +148,11 @@ defmodule Microformats2.Items.ImpliedProperties do

cond do
Enum.count(sec_imgs) == 1 ->
List.first(sec_imgs) |> Floki.attribute("src") |> List.first
List.first(sec_imgs) |> Floki.attribute("src") |> List.first()

Enum.count(sec_objs) == 1 ->
List.first(sec_objs) |> Floki.attribute("data") |> List.first
List.first(sec_objs) |> Floki.attribute("data") |> List.first()

true ->
nil
end
@@ -151,40 +168,45 @@ defmodule Microformats2.Items.ImpliedProperties do

cond do
Enum.count(as) == 1 ->
List.first(as) |> Floki.attribute("href") |> List.first
List.first(as) |> Floki.attribute("href") |> List.first()

Enum.count(areas) == 1 ->
List.first(areas) |> Floki.attribute("href") |> List.first
List.first(areas) |> Floki.attribute("href") |> List.first()

true ->
nil
end
end


defp implied_photo_attrval(node = {"img", _, _}) do
Floki.attribute(node, "src") |> List.first
Floki.attribute(node, "src") |> List.first()
end

defp implied_photo_attrval(node = {"object", _, _}) do
Floki.attribute(node, "data") |> List.first
Floki.attribute(node, "data") |> List.first()
end

defp implied_photo_attrval(_) do
nil
end

defp direct_not_h_children_with_attr({_, _, children}, name, attr) do
Enum.filter(children,
fn({el, _, _}) -> el == name
(v) when is_bitstring(v) -> false
end) |>
Enum.filter(fn(el) -> not Microformats2.is_rootlevel?(el) end) |>
Enum.filter(fn(el) -> Enum.count(Floki.attribute(el, attr)) > 0 end)
Enum.filter(children, fn
{el, _, _} -> el == name
v when is_bitstring(v) -> false
end)
|> Enum.filter(fn el -> not Microformats2.is_rootlevel?(el) end)
|> Enum.filter(fn el -> Enum.count(Floki.attribute(el, attr)) > 0 end)
end

defp implied_url_attrval(node = {"a", _, _}) do
Floki.attribute(node, "href") |> List.first
Floki.attribute(node, "href") |> List.first()
end

defp implied_url_attrval(node = {"area", _, _}) do
Floki.attribute(node, "href") |> List.first
Floki.attribute(node, "href") |> List.first()
end

defp implied_url_attrval(_) do
nil
end


+ 93
- 61
lib/items.ex View File

@@ -5,16 +5,17 @@ defmodule Microformats2.Items do
def parse([], _, _, items), do: items

def parse(root, doc, url, items) do
root_classes = Microformats2.attr_list(root) |>
Enum.filter(fn(class_name) -> Microformats2.is_rootlevel?(class_name) end) |>
Enum.sort
root_classes =
Microformats2.attr_list(root)
|> Enum.filter(fn class_name -> Microformats2.is_rootlevel?(class_name) end)
|> Enum.sort()

{_, _, children} = root

if not Enum.empty?(root_classes) do
entry = parse_sub(children, doc, url,
%{type: root_classes,
properties: %{}}) |> Microformats2.Items.ImpliedProperties.parse(root, url, doc)
entry =
parse_sub(children, doc, url, %{type: root_classes, properties: %{}})
|> Microformats2.Items.ImpliedProperties.parse(root, url, doc)

items ++ [entry]
else
@@ -24,19 +25,24 @@ defmodule Microformats2.Items do

defp parse_sub([], _, _, item), do: item
defp parse_sub([child | children], doc, url, item) when is_bitstring(child), do: parse_sub(children, doc, url, item)
defp parse_sub([child = {_, _, child_children} | children], doc, url, item) do
p = if Microformats2.has_a?(child, "h-") do
parse(child, doc, url, []) |> List.first
else
[]
end

classes = Microformats2.attr_list(child) |>
Enum.filter(fn("p-" <> _) -> true
("u-" <> _) -> true
("dt-" <> _) -> true
("e-" <> _) -> true
(_) -> false end)
defp parse_sub([child = {_, _, child_children} | children], doc, url, item) do
p =
if Microformats2.has_a?(child, "h-") do
parse(child, doc, url, []) |> List.first()
else
[]
end

classes =
Microformats2.attr_list(child)
|> Enum.filter(fn
"p-" <> _ -> true
"u-" <> _ -> true
"dt-" <> _ -> true
"e-" <> _ -> true
_ -> false
end)

props = gen_prop(child, classes, item, p, doc, url)
n_item = if Microformats2.is_rootlevel?(child), do: props, else: parse_sub(child_children, doc, url, props)
@@ -47,45 +53,53 @@ defmodule Microformats2.Items do
defp parse_prop("p-" <> _, child, _, _) do
# TODO value pattern parsing
{elem, _, _} = child
title = Floki.attribute(child, "title") |> List.first
alt = Floki.attribute(child, "alt") |> List.first
title = Floki.attribute(child, "title") |> List.first()
alt = Floki.attribute(child, "alt") |> List.first()

cond do
elem == "abbr" and not Microformats2.blank?(title) ->
title

elem == "img" and not Microformats2.blank?(alt) ->
alt

true ->
text_content(child) |> String.trim
text_content(child) |> String.trim()
end
end


defp parse_prop("u-" <> _, child = {elem, _, _}, doc, url) do
href = Floki.attribute(child, "href") |> List.first
src = Floki.attribute(child, "src") |> List.first
data = Floki.attribute(child, "data") |> List.first
poster = Floki.attribute(child, "poster") |> List.first
title = Floki.attribute(child, "title") |> List.first
value = Floki.attribute(child, "value") |> List.first
href = Floki.attribute(child, "href") |> List.first()
src = Floki.attribute(child, "src") |> List.first()
data = Floki.attribute(child, "data") |> List.first()
poster = Floki.attribute(child, "poster") |> List.first()
title = Floki.attribute(child, "title") |> List.first()
value = Floki.attribute(child, "value") |> List.first()

cond do
Enum.member?(["a", "area"], elem) and not Microformats2.blank?(href) ->
href

Enum.member?(["img", "audio", "video", "source"], elem) and not Microformats2.blank?(src) ->
src

elem == "object" and not Microformats2.blank?(data) ->
data

elem == "video" and not Microformats2.blank?(poster) ->
poster
# TODO value-class-pattern at this position

# TODO value-class-pattern at this position
elem == "abbr" and not Microformats2.blank?(title) ->
title

Enum.member?(["data", "input"], elem) and not Microformats2.blank?(value) ->
value

true ->
text_content(child) |> String.trim
end |> Microformats2.abs_uri(url, doc)
text_content(child) |> String.trim()
end
|> Microformats2.abs_uri(url, doc)
end

defp parse_prop("dt-" <> _, child = {elem, _, _}, _, _) do
@@ -95,33 +109,41 @@ defmodule Microformats2.Items do

cond do
Enum.member?(["time", "ins", "del"], elem) and not Microformats2.blank?(dt) ->
dt |> List.first
dt |> List.first()

elem == "abbr" and not Microformats2.blank?(title) ->
title |> List.first
title |> List.first()

Enum.member?(["data", "input"], elem) and not Microformats2.blank?(value) ->
value |> List.first
value |> List.first()

true ->
text_content(child) |> String.trim
text_content(child) |> String.trim()
end
end

defp parse_prop("e-" <> _, child = {_, _, children}, _, _) do
%{html: Microformats2.stripped_or_nil(Floki.raw_html(children)),
text: Microformats2.stripped_or_nil(Floki.text(child))}
%{
html: Microformats2.stripped_or_nil(Floki.raw_html(children)),
text: Microformats2.stripped_or_nil(Floki.text(child))
}
end

defp parse_prop(_, _, _, _), do: nil


defp get_value(class, p) do
cond do
Microformats2.is_a?(class, "p") and p[:properties][:name] != nil ->
List.first(p[:properties][:name])

Microformats2.is_a?(class, "u") and p[:properties][:url] != nil ->
List.first(p[:properties][:url])
Microformats2.is_a?(class, "e") -> #and p[:properties][:url] != nil ->

# and p[:properties][:url] != nil ->
Microformats2.is_a?(class, "e") ->
# TODO handle
nil

true ->
# TODO handle
nil
@@ -129,17 +151,19 @@ defmodule Microformats2.Items do
end

defp gen_prop(child, classes, item, p, doc, url) do
props = Enum.reduce(classes, item[:properties], fn(class, acc) ->
prop = if Microformats2.is_rootlevel?(child) do
Map.put(p, :value, get_value(class, p))
else
parse_prop(class, child, doc, url)
end

key = strip_prefix(class) |> to_key |> String.to_atom
val = if acc[key] != nil, do: acc[key], else: []
Map.put(acc, key, val ++ [prop])
end)
props =
Enum.reduce(classes, item[:properties], fn class, acc ->
prop =
if Microformats2.is_rootlevel?(child) do
Map.put(p, :value, get_value(class, p))
else
parse_prop(class, child, doc, url)
end

key = strip_prefix(class) |> to_key |> String.to_atom()
val = if acc[key] != nil, do: acc[key], else: []
Map.put(acc, key, val ++ [prop])
end)

if Microformats2.blank?(classes) and not Microformats2.blank?(p) and Microformats2.is_rootlevel?(child) do
Map.put(item, :children, (item[:children] || []) ++ [p])
@@ -148,40 +172,48 @@ defmodule Microformats2.Items do
end
end


defp strip_prefix("p-" <> rest) do
rest
end

defp strip_prefix("u-" <> rest) do
rest
end

defp strip_prefix("dt-" <> rest) do
rest
end

defp strip_prefix("e-" <> rest) do
rest
end

defp strip_prefix(rest) do
rest
end

def text_content(child, text \\ "")

def text_content(child = {elem, _, children}, text) do
txt = if elem == "img" do
alt = Floki.attribute(child, "alt")
if alt != nil and alt != "" do
alt
txt =
if elem == "img" do
alt = Floki.attribute(child, "alt")

if alt != nil and alt != "" do
alt
else
Floki.attribute(child, "src")
end
|> List.first()
else
Floki.attribute(child, "src")
end |> List.first
else
""
end
""
end

Enum.reduce(children, text <> txt, fn(child, acc) ->
Enum.reduce(children, text <> txt, fn child, acc ->
text_content(child, acc)
end)
end

def text_content(child, text) when is_bitstring(child) do
text <> child
end


+ 24
- 20
lib/microformats2.ex View File

@@ -1,7 +1,6 @@

defmodule Microformats2 do
def parse(url) do
response = HTTPotion.get url, [ follow_redirects: true ]
response = HTTPotion.get(url, follow_redirects: true)

if HTTPotion.Response.success?(response) do
parse(response.body, url)
@@ -11,11 +10,12 @@ defmodule Microformats2 do
end

def parse(content, url) do
doc = Floki.parse(content) |>
Floki.filter_out("template") |>
Floki.filter_out("style") |>
Floki.filter_out("script") |>
Floki.filter_out(:comment)
doc =
Floki.parse(content)
|> Floki.filter_out("template")
|> Floki.filter_out("style")
|> Floki.filter_out("script")
|> Floki.filter_out(:comment)

rels = Microformats2.Rels.parse(doc, url)
items = Microformats2.Items.parse(doc, doc, url)
@@ -24,7 +24,7 @@ defmodule Microformats2 do
end

def attr_list(node, attr \\ "class") do
Floki.attribute(node, attr) |> List.first |> to_string |> String.split(" ", trim: true)
Floki.attribute(node, attr) |> List.first() |> to_string |> String.split(" ", trim: true)
end

def blank?(nil), do: true
@@ -36,14 +36,14 @@ defmodule Microformats2 do
def stripped_or_nil(val), do: String.trim(val)

def is_rootlevel?(node) when is_tuple(node) do
attr_list(node, "class") |>
Enum.any?(fn(cls) -> is_a?(cls, "h") end)
attr_list(node, "class")
|> Enum.any?(fn cls -> is_a?(cls, "h") end)
end

def is_rootlevel?(class_name) when is_bitstring(class_name) do
is_a?(class_name, "h")
end


def is_a?("h-" <> _, wanted), do: wanted == "h"
def is_a?("p-" <> _, wanted), do: wanted == "p"
def is_a?("e-" <> _, wanted), do: wanted == "e"
@@ -52,7 +52,7 @@ defmodule Microformats2 do
def is_a?(_, _), do: false

def has_a?(node, wanted) do
attr_list(node) |> Enum.filter(fn(class) -> is_a?(class, wanted) end) |> blank?
attr_list(node) |> Enum.filter(fn class -> is_a?(class, wanted) end) |> blank?
end

def abs_uri(url, base_url, doc) do
@@ -60,19 +60,23 @@ defmodule Microformats2 do
parsed_base = URI.parse(base_url)

cond do
not Microformats2.blank?(parsed.scheme) -> # absolute URI
# absolute URI
not Microformats2.blank?(parsed.scheme) ->
url
Microformats2.blank?(parsed.scheme) and not Microformats2.blank?(parsed.host) -> # protocol relative URI

# protocol relative URI
Microformats2.blank?(parsed.scheme) and not Microformats2.blank?(parsed.host) ->
URI.to_string(%{parsed | scheme: parsed_base.scheme})

true ->
base_element = Floki.find(doc, "base")

new_base = if base_element == nil or Microformats2.blank?(Floki.attribute(base_element, "href")) do
base_url
else
abs_uri(Floki.attribute(base_element, "href") |> List.first,
base_url, [])
end
new_base =
if base_element == nil or Microformats2.blank?(Floki.attribute(base_element, "href")) do
base_url
else
abs_uri(Floki.attribute(base_element, "href") |> List.first(), base_url, [])
end

parsed_new_base = URI.parse(new_base)
new_path = Path.expand(parsed.path || "/", Path.dirname(parsed_new_base.path || "/"))


+ 30
- 37
lib/rels.ex View File

@@ -1,46 +1,45 @@
defmodule Microformats2.Rels do
def parse(doc, base_url) do
link_rels = Floki.find(doc, "[rel][href]") |>
Enum.filter(fn(element) ->
rel = Floki.attribute(element, "rel") |> List.first
href = Floki.attribute(element, "href") |> List.first
link_rels =
Floki.find(doc, "[rel][href]")
|> Enum.filter(fn element ->
rel = Floki.attribute(element, "rel") |> List.first()
href = Floki.attribute(element, "href") |> List.first()

String.trim(to_string(rel)) != "" and String.trim(to_string(href)) != ""
end) |>
Enum.reduce(%{rels: %{}, rel_urls: %{}}, fn(element, acc) ->
end)
|> Enum.reduce(%{rels: %{}, rel_urls: %{}}, fn element, acc ->
rel = Microformats2.attr_list(element, "rel")
url = Floki.attribute(element, "href") |> List.first |> Microformats2.abs_uri(base_url, doc)
url = Floki.attribute(element, "href") |> List.first() |> Microformats2.abs_uri(base_url, doc)

acc |>
save_urls_by_rels(rel, url) |>
save_rels_by_urls(rel, url) |>
save_attributes(element, url)
acc
|> save_urls_by_rels(rel, url)
|> save_rels_by_urls(rel, url)
|> save_attributes(element, url)
end)

link_rels
end

defp save_urls_by_rels(map, rel, url) do
Enum.reduce(rel, map, fn(rel, nmap) ->
Enum.reduce(rel, map, fn rel, nmap ->
if nmap[:rels][rel] == nil do
Map.put(nmap, :rels,
Map.put(nmap[:rels], rel, [url]))
Map.put(nmap, :rels, Map.put(nmap[:rels], rel, [url]))
else
Map.put(nmap, :rels,
Map.put(nmap[:rels], rel,
Enum.uniq(nmap[:rels][rel] ++ [url])))
Map.put(nmap, :rels, Map.put(nmap[:rels], rel, Enum.uniq(nmap[:rels][rel] ++ [url])))
end
end)
end

defp save_rels_by_urls(map, rel, url) do
if map[:rel_urls][url] == nil do
Map.put(map, :rel_urls,
Map.put(map[:rel_urls], url, %{rels: rel}))
Map.put(map, :rel_urls, Map.put(map[:rel_urls], url, %{rels: rel}))
else
Map.put(map, :rel_urls,
Map.put(map[:rel_urls], url,
Map.put(map[:rel_urls][url], :rels, Enum.uniq(map[:rel_urls][url][:rels] ++ rel))))
Map.put(
map,
:rel_urls,
Map.put(map[:rel_urls], url, Map.put(map[:rel_urls][url], :rels, Enum.uniq(map[:rel_urls][url][:rels] ++ rel)))
)
end
end

@@ -50,25 +49,19 @@ defmodule Microformats2.Rels do
if String.trim(to_string(text)) == "" or map[:rel_urls][url][:text] != nil do
map
else
Map.put(map, :rel_urls,
Map.put(map[:rel_urls], url,
Map.put(map[:rel_urls][url], :text, text)))
Map.put(map, :rel_urls, Map.put(map[:rel_urls], url, Map.put(map[:rel_urls][url], :text, text)))
end
end

defp save_attributes(map, element, url) do
Enum.reduce(["hreflang", "media", "title", "type"],
save_text(map, element, url),
fn(att, nmap) ->
val = Floki.attribute(element, att) |> List.first
Enum.reduce(["hreflang", "media", "title", "type"], save_text(map, element, url), fn att, nmap ->
val = Floki.attribute(element, att) |> List.first()

if String.trim(to_string(val)) == "" or nmap[:rel_urls][url][String.to_atom(att)] != nil do
nmap
else
Map.put(nmap, :rel_urls,
Map.put(nmap[:rel_urls], url,
Map.put(nmap[:rel_urls][url], String.to_atom(att), val)))
end
end)
if String.trim(to_string(val)) == "" or nmap[:rel_urls][url][String.to_atom(att)] != nil do
nmap
else
Map.put(nmap, :rel_urls, Map.put(nmap[:rel_urls], url, Map.put(nmap[:rel_urls][url], String.to_atom(att), val)))
end
end)
end
end

+ 17
- 15
mix.exs View File

@@ -2,14 +2,16 @@ defmodule Microformats2.Mixfile do
use Mix.Project

def project do
[app: :microformats2,
version: "0.0.8",
elixir: "~> 1.3",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
description: description(),
package: package(),
deps: deps()]
[
app: :microformats2,
version: "0.0.8",
elixir: "~> 1.3",
build_embedded: Mix.env() == :prod,
start_permanent: Mix.env() == :prod,
description: description(),
package: package(),
deps: deps()
]
end

# Configuration for the OTP application
@@ -26,10 +28,12 @@ defmodule Microformats2.Mixfile do
end

def package do
[files: ["lib", "mix.exs", "README.md", "LICENSE"],
maintainers: ["Christian Kruse"],
licenses: ["AGPL 3.0"],
links: %{"GitHub" => "https://github.com/ckruse/microformats2-elixir"}]
[
files: ["lib", "mix.exs", "README.md", "LICENSE"],
maintainers: ["Christian Kruse"],
licenses: ["AGPL 3.0"],
links: %{"GitHub" => "https://github.com/ckruse/microformats2-elixir"}
]
end

# Dependencies can be Hex packages:
@@ -42,8 +46,6 @@ defmodule Microformats2.Mixfile do
#
# Type "mix help deps" for more examples and options
defp deps do
[{:floki, "~> 0.7"},
{:httpotion, "~> 3.0"},
{:ex_doc, ">= 0.0.0", only: :dev}]
[{:floki, "~> 0.7"}, {:httpotion, "~> 3.0"}, {:ex_doc, ">= 0.0.0", only: :dev}]
end
end

+ 244
- 133
test/items_test.exs View File

@@ -4,169 +4,280 @@ defmodule Microformats2ItemsTest do

test "successfully parses a whole document" do
str = """
<!DOCTYPE html>
<html>
<head>
<title>Blub</title>
</head>
<body>
<h1>Blah</h1>
<article class="h-card">
<span class="p-name">Luke <span>lulu</span></span>
<a href="blub" class="u-url">blah</a>
</article>
</body>
</html>
"""
<!DOCTYPE html>
<html>
<head>
<title>Blub</title>
</head>
<body>
<h1>Blah</h1>
<article class="h-card">
<span class="p-name">Luke <span>lulu</span></span>
<a href="blub" class="u-url">blah</a>
</article>
</body>
</html>
"""

ret = Microformats2.parse(str, "http://localhost")
assert not Enum.empty?(ret[:items])
end

test "minimal h-card" do
assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Frances Berriman"]}}]} =
Microformats2.parse("<span class=\"h-card\">Frances Berriman</span>",
"http://localhost")

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Ben Ward"],
url: ["http://benward.me"]}}]} =
Microformats2.parse("<a class=\"h-card\" href=\"http://benward.me\">Ben Ward</a>",
"http://localhost")

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Rohit Khare"],
url: ["http://rohit.khare.org/"],
photo: ["https://s3.amazonaws.com/twitter_production/profile_images/53307499/180px-Rohit-sq_bigger.jpg"]}}]} =
Microformats2.parse("""
<a class="h-card" href="http://rohit.khare.org/">
<img alt="Rohit Khare"
src="https://s3.amazonaws.com/twitter_production/profile_images/53307499/180px-Rohit-sq_bigger.jpg">
</a>
""",
"http://localhost")
assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{name: ["Frances Berriman"]}}]} =
Microformats2.parse("<span class=\"h-card\">Frances Berriman</span>", "http://localhost")

assert %{
rels: _,
rel_urls: _,
items: [%{type: ["h-card"], properties: %{name: ["Ben Ward"], url: ["http://benward.me"]}}]
} = Microformats2.parse("<a class=\"h-card\" href=\"http://benward.me\">Ben Ward</a>", "http://localhost")

assert %{
rels: _,
rel_urls: _,
items: [
%{
type: ["h-card"],
properties: %{
name: ["Rohit Khare"],
url: ["http://rohit.khare.org/"],
photo: [
"https://s3.amazonaws.com/twitter_production/profile_images/53307499/180px-Rohit-sq_bigger.jpg"
]
}
}
]
} =
Microformats2.parse(
"""
<a class="h-card" href="http://rohit.khare.org/">
<img alt="Rohit Khare"
src="https://s3.amazonaws.com/twitter_production/profile_images/53307499/180px-Rohit-sq_bigger.jpg">
</a>
""",
"http://localhost"
)
end

test "successfully parses a h-card with author name" do
{:ok, str} = File.read "./test/documents/h_card_with_author.html"

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
photo: ["https://webfwd.org/content/about-experts/300.mitchellbaker/mentor_mbaker.jpg"],
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/",
"https://twitter.com/MitchellBaker"],
org: ["Mozilla Foundation"],
note: ["Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities."],
category: ["Strategy",
"Leadership"]}}]} = Microformats2.parse(str, "http://localhost")
{:ok, str} = File.read("./test/documents/h_card_with_author.html")

assert %{
rels: _,
rel_urls: _,
items: [
%{
type: ["h-card"],
properties: %{
photo: ["https://webfwd.org/content/about-experts/300.mitchellbaker/mentor_mbaker.jpg"],
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/", "https://twitter.com/MitchellBaker"],
org: ["Mozilla Foundation"],
note: [
"Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities."
],
category: ["Strategy", "Leadership"]
}
}
]
} = Microformats2.parse(str, "http://localhost")
end

test "successfully parses a h-event combined with h-card" do
{:ok, str} = File.read "./test/documents/h_event_combined_h_card.html"

assert %{rels: _, rel_urls: _, items: [%{type: ["h-event"], properties: %{
name: ["IndieWebCamp 2012"],
url: ["http://indiewebcamp.com/2012"],
start: ["2012-06-30"],
end: ["2012-07-01"],
location: [%{value: "Geoloqi",
type: ["h-card"],
properties: %{name: ["Geoloqi"],
org: ["Geoloqi"],
url: ["http://geoloqi.com/"],
street_address: ["920 SW 3rd Ave. Suite 400"],
locality: ["Portland"],
region: ["Oregon"]}}]}}]} = Microformats2.parse(str, "http://localhost")
{:ok, str} = File.read("./test/documents/h_event_combined_h_card.html")

assert %{
rels: _,
rel_urls: _,
items: [
%{
type: ["h-event"],
properties: %{
name: ["IndieWebCamp 2012"],
url: ["http://indiewebcamp.com/2012"],
start: ["2012-06-30"],
end: ["2012-07-01"],
location: [
%{
value: "Geoloqi",
type: ["h-card"],
properties: %{
name: ["Geoloqi"],
org: ["Geoloqi"],
url: ["http://geoloqi.com/"],
street_address: ["920 SW 3rd Ave. Suite 400"],
locality: ["Portland"],
region: ["Oregon"]
}
}
]
}
}
]
} = Microformats2.parse(str, "http://localhost")
end

test "successfully parses a h-card with org" do
{:ok, str} = File.read "./test/documents/h_card_org.html"
{:ok, str} = File.read("./test/documents/h_card_org.html")

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/"],
org: ["Mozilla Foundation"]}}]} = Microformats2.parse(str, "http://localhost")
assert %{
rels: _,
rel_urls: _,
items: [
%{
type: ["h-card"],
properties: %{
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/"],
org: ["Mozilla Foundation"]
}
}
]
} = Microformats2.parse(str, "http://localhost")
end

test "successfully parses a h-card with h-card and org" do
{:ok, str} = File.read "./test/documents/h_card_with_h_card_org.html"

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/"],
org: [%{value: "Mozilla Foundation",
type: ["h-card"],
properties: %{
name: ["Mozilla Foundation"],
url: ["http://mozilla.org/"]}}]}}]} = Microformats2.parse(str, "http://localhost")
{:ok, str} = File.read("./test/documents/h_card_with_h_card_org.html")

assert %{
rels: _,
rel_urls: _,
items: [
%{
type: ["h-card"],
properties: %{
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/"],
org: [
%{
value: "Mozilla Foundation",
type: ["h-card"],
properties: %{name: ["Mozilla Foundation"], url: ["http://mozilla.org/"]}
}
]
}
}
]
} = Microformats2.parse(str, "http://localhost")
end

test "successfully parses a nested h-card h-org h-card" do
{:ok, str} = File.read "./test/documents/nested_h_card_h_org_h_card.html"

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/"],
org: [%{
value: "Mozilla Foundation",
type: ["h-card", "h-org"],
properties: %{
name: ["Mozilla Foundation"],
url: ["http://mozilla.org/"]}}]}}]} = Microformats2.parse(str, "http://localhost")
{:ok, str} = File.read("./test/documents/nested_h_card_h_org_h_card.html")

assert %{
rels: _,
rel_urls: _,
items: [
%{
type: ["h-card"],
properties: %{
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/"],
org: [
%{
value: "Mozilla Foundation",
type: ["h-card", "h-org"],
properties: %{name: ["Mozilla Foundation"], url: ["http://mozilla.org/"]}
}
]
}
}
]
} = Microformats2.parse(str, "http://localhost")
end

test "successfully parses a nested h-card w/o attached property" do
{:ok, str} = File.read "./test/documents/h_card_org_h_card.html"

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Mitchell Baker"],
url: ["http://blog.lizardwrangler.com/"]},
children: [%{type: ["h-card"], properties: %{
name: ["Mozilla Foundation"],
url: ["http://mozilla.org/"]}}]}]} =
Microformats2.parse(str, "http://localhost")
{:ok, str} = File.read("./test/documents/h_card_org_h_card.html")

assert %{
rels: _,
rel_urls: _,
items: [
%{
type: ["h-card"],
properties: %{name: ["Mitchell Baker"], url: ["http://blog.lizardwrangler.com/"]},
children: [
%{type: ["h-card"], properties: %{name: ["Mozilla Foundation"], url: ["http://mozilla.org/"]}}
]
}
]
} = Microformats2.parse(str, "http://localhost")
end

test "resolves explicit url to absolute URL" do
assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Ben Ward"],
url: ["http://benward.me/foo"]}}]} =
Microformats2.parse("<div class=\"h-card\"><a class=\"u-url\" href=\"/foo\">Ben Ward</a></div>",
"http://benward.me")

assert %{rels: _, rel_urls: _, items: [%{type: ["h-card"], properties: %{
name: ["Ben Ward"],
url: ["http://benward.me/foo"]}}]} =
Microformats2.parse("<div class=\"h-card\"><a href=\"/foo\">Ben Ward</a></div>",
"http://benward.me")
assert %{
rels: _,
rel_urls: _,
items: [%{type: ["h-card"], properties: %{name: ["Ben Ward"], url: ["http://benward.me/foo"]}}]
} =
Microformats2.parse(
"<div class=\"h-card\"><a class=\"u-url\" href=\"/foo\">Ben Ward</a></div>",
"http://benward.me"
)

assert %{
rels: _,
rel_urls: _,
items: [%{type: ["h-card"], properties: %{name: ["Ben Ward"], url: ["http://benward.me/foo"]}}]
} = Microformats2.parse("<div class=\"h-card\"><a href=\"/foo\">Ben Ward</a></div>", "http://benward.me")
end

test "jeena entry" do
{:ok, str} = File.read "./test/documents/real_world_note.html"

assert %{rels: _, rel_urls: _,
items: [%{properties:
%{author: [%{properties: %{name: ["Jeena"],
photo: ["http://localhost/avatar.jpg"],
url: ["http://localhost/"]},
type: ["h-card"], value: "Jeena"}],
comment: [%{properties: %{
author: [%{properties: %{name: ["Christian Kruse"],
photo: ["http://localhost/cache?size=40x40>&url=https%3A%2F%2Fwwwtech.de%2Fimages%2Fchristian-kruse-242470c34a3671da4cab3e3b0d941729.jpg%3Fvsn%3Dd"],
url: ["https://wwwtech.de/notes/132"]},
type: ["h-card"],
value: "Christian Kruse"}],
content: [%{html: "Of course he is!",
text: "Of course he is!"}],
name: ["Christian Kruse,\n\t\t 4 days ago\n\t\t Of course he is!"],
published: ["2016-02-19T10:50:17Z"],
url: ["https://wwwtech.de/notes/132"]}, type: ["h-cite"],
value: "Christian Kruse,\n\t\t 4 days ago\n\t\t Of course he is!"}],
content: [%{html: "<p>He's right, you know?</p>",
text: "He's right, you know?"}],
in_reply_to: ["https://wwwtech.de/pictures/51"], name: ["Note #587"],
published: ["2016-02-18T19:33:25Z"], updated: ["2016-02-18T19:33:25Z"],
url: ["http://localhost/comments/587"]}, type: ["h-as-note", "h-entry"]}]} = Microformats2.parse(str, "http://localhost")
{:ok, str} = File.read("./test/documents/real_world_note.html")

assert %{
rels: _,
rel_urls: _,
items: [
%{
properties: %{
author: [
%{
properties: %{
name: ["Jeena"],
photo: ["http://localhost/avatar.jpg"],
url: ["http://localhost/"]
},
type: ["h-card"],
value: "Jeena"
}
],
comment: [
%{
properties: %{
author: [
%{
properties: %{
name: ["Christian Kruse"],
photo: [
"http://localhost/cache?size=40x40>&url=https%3A%2F%2Fwwwtech.de%2Fimages%2Fchristian-kruse-242470c34a3671da4cab3e3b0d941729.jpg%3Fvsn%3Dd"
],
url: ["https://wwwtech.de/notes/132"]
},
type: ["h-card"],
value: "Christian Kruse"
}
],
content: [%{html: "Of course he is!", text: "Of course he is!"}],
name: ["Christian Kruse,\n\t\t 4 days ago\n\t\t Of course he is!"],
published: ["2016-02-19T10:50:17Z"],
url: ["https://wwwtech.de/notes/132"]
},
type: ["h-cite"],
value: "Christian Kruse,\n\t\t 4 days ago\n\t\t Of course he is!"
}
],
content: [%{html: "<p>He's right, you know?</p>", text: "He's right, you know?"}],
in_reply_to: ["https://wwwtech.de/pictures/51"],
name: ["Note #587"],
published: ["2016-02-18T19:33:25Z"],
updated: ["2016-02-18T19:33:25Z"],
url: ["http://localhost/comments/587"]
},
type: ["h-as-note", "h-entry"]
}
]
} = Microformats2.parse(str, "http://localhost")
end
end

+ 149
- 107
test/rels_test.exs View File

@@ -3,133 +3,175 @@ defmodule Microformats2RelsTest do
doctest Microformats2.Rels

test "parse successfully parses rels" do
assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me"], text: "blub" }},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("<a rel=\"me\" href=\"http://blub\">blub</a>",
"http://localhost"))
assert(
%{items: _, rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub"}}, rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("<a rel=\"me\" href=\"http://blub\">blub</a>", "http://localhost")
)
end

test "parse successfully parses multiple rels" do
assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me"], text: "blub" },
"http://blah" => %{ rels: ["me"], text: "blub" }},
rels: %{"me" => ["http://blub", "http://blah"]}} =
Microformats2.parse("""
<a rel=\"me\" href=\"http://blub\">blub</a>
<a rel=\"me\" href=\"http://blah\">blub</a>
""",
"http://localhost"))
assert(
%{
items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub"}, "http://blah" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://blub", "http://blah"]}
} =
Microformats2.parse(
"""
<a rel=\"me\" href=\"http://blub\">blub</a>
<a rel=\"me\" href=\"http://blah\">blub</a>
""",
"http://localhost"
)
)
end

test "parse only saves one URL" do
assert(%{items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("""
<a rel=\"me\" href=\"http://blub\">blub</a>
<a rel=\"me\" href=\"http://blub\">blub</a>
""",
"http://localhost"))
assert(
%{items: _, rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub"}}, rels: %{"me" => ["http://blub"]}} =
Microformats2.parse(
"""
<a rel=\"me\" href=\"http://blub\">blub</a>
<a rel=\"me\" href=\"http://blub\">blub</a>
""",
"http://localhost"
)
)
end

test "parse saves all rels" do
assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me", "moo"], text: "blub" }},
rels: %{"me" => ["http://blub"],
"moo" => ["http://blub"]}} =
Microformats2.parse("""
<a rel=\"me\" href=\"http://blub\">blub</a>
<a rel=\"moo\" href=\"http://blub\">blub</a>
""",
"http://localhost"))
assert(
%{
items: _,
rel_urls: %{"http://blub" => %{rels: ["me", "moo"], text: "blub"}},
rels: %{"me" => ["http://blub"], "moo" => ["http://blub"]}
} =
Microformats2.parse(
"""
<a rel=\"me\" href=\"http://blub\">blub</a>
<a rel=\"moo\" href=\"http://blub\">blub</a>
""",
"http://localhost"
)
)
end

test "parse successfully parses rels with attributes" do
assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me"], media: "video", text: "blub" }},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("<a rel=\"me\" media=\"video\" href=\"http://blub\">blub</a>",
"http://localhost"))

assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me"], hreflang: "de", text: "blub" }},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("<a rel=\"me\" hreflang=\"de\" href=\"http://blub\">blub</a>",
"http://localhost"))

assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me"], title: "blub", text: "blub" }},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("<a rel=\"me\" title=\"blub\" href=\"http://blub\">blub</a>",
"http://localhost"))

assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me"], type: "text/html", text: "blub" }},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("<a rel=\"me\" type=\"text/html\" href=\"http://blub\">blub</a>",
"http://localhost"))

assert(%{items: _,
rel_urls: %{"http://blub" => %{ rels: ["me"],
media: "video",
title: "blub",
hreflang: "de",
type: "text/html",
text: "blub" }},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("<a rel=\"me\" hreflang=\"de\" media=\"video\" title=\"blub\" type=\"text/html\" href=\"http://blub\">blub</a>",
"http://localhost"))
assert(
%{
items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], media: "video", text: "blub"}},
rels: %{"me" => ["http://blub"]}
} = Microformats2.parse("<a rel=\"me\" media=\"video\" href=\"http://blub\">blub</a>", "http://localhost")
)

assert(
%{
items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], hreflang: "de", text: "blub"}},
rels: %{"me" => ["http://blub"]}
} = Microformats2.parse("<a rel=\"me\" hreflang=\"de\" href=\"http://blub\">blub</a>", "http://localhost")
)

assert(
%{
items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], title: "blub", text: "blub"}},
rels: %{"me" => ["http://blub"]}
} = Microformats2.parse("<a rel=\"me\" title=\"blub\" href=\"http://blub\">blub</a>", "http://localhost")
)

assert(
%{
items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], type: "text/html", text: "blub"}},
rels: %{"me" => ["http://blub"]}
} = Microformats2.parse("<a rel=\"me\" type=\"text/html\" href=\"http://blub\">blub</a>", "http://localhost")
)

assert(
%{
items: _,
rel_urls: %{
"http://blub" => %{
rels: ["me"],
media: "video",
title: "blub",
hreflang: "de",
type: "text/html",
text: "blub"
}
},
rels: %{"me" => ["http://blub"]}
} =
Microformats2.parse(
"<a rel=\"me\" hreflang=\"de\" media=\"video\" title=\"blub\" type=\"text/html\" href=\"http://blub\">blub</a>",
"http://localhost"
)
)
end

test "duplicate value doesn't overwrite the first one" do
assert(%{items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub", hreflang: "de"}},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("""
<a rel="me" hreflang="de" href="http://blub">blub</a>
<a rel="me" hreflang="en" href="http://blub">blah</a>
""",
"http://localhost"))

assert(
%{
items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub", hreflang: "de"}},
rels: %{"me" => ["http://blub"]}
} =
Microformats2.parse(
"""
<a rel="me" hreflang="de" href="http://blub">blub</a>
<a rel="me" hreflang="en" href="http://blub">blah</a>
""",
"http://localhost"
)
)
end

test "parse ignores template elements" do
assert(%{items: _,
rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://blub"]}} =
Microformats2.parse("""
<a rel="me" href="http://blub">blub</a>
<template><a rel="moo" href="http://blub">blub</a></template>
""",
"http://localhost"))
assert(
%{items: _, rel_urls: %{"http://blub" => %{rels: ["me"], text: "blub"}}, rels: %{"me" => ["http://blub"]}} =
Microformats2.parse(
"""
<a rel="me" href="http://blub">blub</a>
<template><a rel="moo" href="http://blub">blub</a></template>
""",
"http://localhost"
)
)
end

test "parse generates an absolute URL" do
assert(%{items: _,
rel_urls: %{"http://localhost/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blub"]}} =
Microformats2.parse("<a rel=\"me\" href=\"/blub\">blub</a>",
"http://localhost"))

assert(%{items: _,
rel_urls: %{"http://localhost/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blub"]}} =
Microformats2.parse("<a rel=\"me\" href=\"blub\">blub</a>",
"http://localhost"))

assert(%{items: _,
rel_urls: %{"http://localhost/blah/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blah/blub"]}} =
Microformats2.parse("<a rel=\"me\" href=\"blub\">blub</a>",
"http://localhost/blah/foo"))

assert(%{items: _,
rel_urls: %{"http://localhost/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blub"]}} =
Microformats2.parse("<a rel=\"me\" href=\"/blub\">blub</a>",
"http://localhost/blah/foo"))

assert(
%{
items: _,
rel_urls: %{"http://localhost/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blub"]}
} = Microformats2.parse("<a rel=\"me\" href=\"/blub\">blub</a>", "http://localhost")
)

assert(
%{
items: _,
rel_urls: %{"http://localhost/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blub"]}
} = Microformats2.parse("<a rel=\"me\" href=\"blub\">blub</a>", "http://localhost")
)

assert(
%{
items: _,
rel_urls: %{"http://localhost/blah/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blah/blub"]}
} = Microformats2.parse("<a rel=\"me\" href=\"blub\">blub</a>", "http://localhost/blah/foo")
)

assert(
%{
items: _,
rel_urls: %{"http://localhost/blub" => %{rels: ["me"], text: "blub"}},
rels: %{"me" => ["http://localhost/blub"]}
} = Microformats2.parse("<a rel=\"me\" href=\"/blub\">blub</a>", "http://localhost/blah/foo")
)
end

end

Loading…
Cancel
Save