Skip to content

Commit

Permalink
parse/1 accepts anything that implements the String.Chars protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
eahanson committed Mar 2, 2024
1 parent 9657507 commit 84deb4b
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
11 changes: 10 additions & 1 deletion lib/xml_query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule XmlQuery do
alias XmlQuery.Xmerl
require XmlQuery.Xmerl

@type xml() :: xml_binary() | xml_document() | xml_element() | XmlQuery.Element.t()
@type xml() :: xml_binary() | xml_document() | xml_element() | XmlQuery.Element.t() | String.Chars.t()
@type xml_attribute() :: Xmerl.xml_attribute()
@type xml_binary() :: binary()
@type xml_document() :: Xmerl.xml_document()
Expand Down Expand Up @@ -114,6 +114,9 @@ defmodule XmlQuery do
into(doc)
end

def parse(%_{} = xml),
do: xml |> implements!(String.Chars) |> to_string() |> parse()

@doc """
Returns `xml` as a prettified string.
Expand Down Expand Up @@ -190,4 +193,10 @@ defmodule XmlQuery do
#{hint}
"""
end

defp implements!(x, protocol) do
if protocol.impl_for(x) == nil,
do: raise("Expected #{inspect(x)} to implement protocol #{inspect(protocol)}"),
else: x
end
end
13 changes: 13 additions & 0 deletions test/support/etc/test_node.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule Test.Etc.TestNode do
@moduledoc """
A struct that implements `String.Chars`, for use in `XmlQueryTest`.
This needs to be in its own `.ex` file rather than defined inside a test,
because `defimpl` doesn't work in `.exs` files (see https://hexdocs.pm/elixir/Protocol.html#module-consolidation)
"""
defstruct [:contents]

defimpl String.Chars do
def to_string(test_node), do: "<test-node>#{test_node.contents}</test-node>"
end
end
14 changes: 14 additions & 0 deletions test/xml_query_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,20 @@ defmodule XmlQueryTest do
|> Xq.parse()
end

test "can parse any struct that implements String.Chars" do
%Test.Etc.TestNode{contents: "<foo>bar</foo>"}
|> Xq.parse()
|> Xq.pretty()
|> assert_eq(
"""
<test-node>
<foo>bar</foo>
</test-node>
""",
:squish
)
end

test "wrap XML element records in Xq.Element" do
xml =
{:xmlElement, :root, :root, [], {:xmlNamespace, [], []}, [], 1, [],
Expand Down

0 comments on commit 84deb4b

Please sign in to comment.