Created
July 31, 2019 20:10
-
-
Save jfeaver/ce77a64998984868ac1a1f6281c008d8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Isbn do | |
require Record | |
Record.defrecord(:isbn, raw: "", gs1: "", group: "", publisher: "", title: "", check_digit: "") | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Isbn.Parser do | |
import Isbn | |
def parse(isbn) do | |
record = | |
isbn | |
|> String.graphemes | |
|> Enum.map(&lexeme/1) | |
|> join | |
|> parse_structure | |
end | |
defp lexeme(l) do | |
if String.match?(l, ~r/[\d -X]/) do | |
l | |
else | |
raise ArgumentError, "ISBN contains an invalid character: " <> l <> ". Valid characters are: 0-9, X, (space), -." | |
end | |
end | |
defp join(lexemes) do | |
Enum.reduce(lexemes, "", fn(my_lx, isbn) -> isbn <> my_lx end) | |
end | |
defp parse_structure(isbn) do | |
isbn | |
|> String.split([" ", "-"], trim: true) | |
|> record_from(isbn) | |
end | |
defp record_from(parts, raw) when length(parts) == 4 do | |
attrs = [:group, :publisher, :title, :check_digit] | |
|> Enum.zip(parts) | |
|> Kernel.++([raw: raw]) | |
|> isbn | |
end | |
defp record_from([gs1 | parts], raw) when length(parts) == 4 do | |
record_from(parts, raw) | |
|> isbn(gs1: gs1) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule IsbnParserTest do | |
use ExUnit.Case | |
require Record | |
import Isbn | |
test "parsing stores various parts of the isbn separately" do | |
record = Isbn.Parser.parse("3-598-21508-8") | |
assert(isbn(record, :group)) == "3" | |
assert(isbn(record, :publisher)) == "598" | |
assert(isbn(record, :title)) == "21508" | |
assert(isbn(record, :check_digit)) == "8" | |
assert(isbn(record, :raw)) == "3-598-21508-8" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment