Initial commit

This commit is contained in:
Danil Negrienko 2021-07-12 14:29:27 +03:00
parent 6c7cd5aee2
commit b48a9f5c58
28 changed files with 472 additions and 13 deletions

4
.formatter.exs Normal file
View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

39
.gitignore vendored
View File

@ -1,12 +1,29 @@
# ---> Elixir # The directory Mix will write compiled artifacts to.
/_build /_build/
/cover /.elixir_ls/
/deps
/doc
/.fetch
erl_crash.dump
*.ez
*.beam
/config/*.secret.exs
.elixir_ls/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-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
# Ignore package tarball (built via "mix hex.build").
ex_datagovua-*.tar
# Temporary files, for example, from tests.
/tmp/
.DS_Store

3
.iex.exs Normal file
View File

@ -0,0 +1,3 @@
alias ExDataGovUA.Package
alias ExDataGovUA.Package.Meta
alias ExDataGovUA.Package.Meta.Fetcher

View File

@ -1,3 +1,21 @@
# ex_data.gov.ua # ExDatagovua
**TODO: Add description**
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `ex_datagovua` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:ex_datagovua, "~> 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/ex_datagovua](https://hexdocs.pm/ex_datagovua).
data.gov.ua universal fetcher

20
config/config.exs Normal file
View File

@ -0,0 +1,20 @@
use Mix.Config
config :ex_datagovua,
default_fetcher: ExDataGovUA.Fetchers.FinchFetcher,
default_decoder: ExDataGovUA.Decoders.JasonDecoder,
file_formats: [
"json"
],
container_formats: [
"gz"
],
packages: %{
"cf37fc56-2eb5-4b6c-81d2-d790e3264111": %{
# schedule: "0 0 1 * *",
# file: :all
# mode: :rewrite
}
}
import_config "#{Mix.env()}.exs"

1
config/dev.exs Normal file
View File

@ -0,0 +1 @@
import Config

1
config/prod.exs Normal file
View File

@ -0,0 +1 @@
import Config

1
config/test.exs Normal file
View File

@ -0,0 +1 @@
import Config

View File

@ -0,0 +1,18 @@
defmodule ExDataGovUA.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false
use Application
def start(_type, _args) do
children = [
# {Finch, name: ExDataGovUA.Finch}
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: ExDataGovUA.Supervisor]
Supervisor.start_link(children, opts)
end
end

View File

@ -0,0 +1,7 @@
defmodule ExDataGovUA.Archivers.Base do
@type stream :: Stream.t()
@callback deflate(stream) :: stream
@callback inflate(stream) :: stream
end

View File

@ -0,0 +1,19 @@
defmodule ExDataGovUA.Archivers.Gz do
@behaviour ExDataGovUA.Archivers.Base
@type input :: Stream.t()
@type output :: Stream.t()
@spec deflate(input) :: output
@doc """
Pack data to archive
"""
def deflate(stream), do: stream |> StreamGzip.gzip
@spec inflate(input) :: output
@doc """
Extract data from archive
"""
def inflate(stream), do: stream |> StreamGzip.gunzip
end

View File

@ -0,0 +1,93 @@
defmodule ExDataGovUA.Commons.HttpStream do
def get(url,emit_end\\false) do
Stream.resource(
fn -> start_fun(url) end,
# next_fun (multi caluses)
fn
%HTTPoison.AsyncResponse{}=resp ->
handle_async_resp(resp,emit_end)
#last accumulator when emitting :end
{:end, resp}->
{:halt, resp}
end,
fn %HTTPoison.AsyncResponse{id: id} ->
IO.puts("END_FUN")
:hackney.stop_async(id)
end
)
end
defp start_fun(url) do
HTTPoison.get!(url,%{}, [stream_to: self(), async: :once])
end
defp handle_async_resp(%HTTPoison.AsyncResponse{id: id}=resp,emit_end) do
receive do
%HTTPoison.AsyncStatus{id: ^id, code: code}->
IO.inspect(code, label: "STATUS: ")
HTTPoison.stream_next(resp)
{[], resp}
%HTTPoison.AsyncHeaders{id: ^id, headers: headers}->
IO.inspect(headers, label: "HEADERS: ")
HTTPoison.stream_next(resp)
{[], resp}
%HTTPoison.AsyncChunk{id: ^id, chunk: chunk}->
HTTPoison.stream_next(resp)
# :erlang.garbage_collect()
{[chunk], resp}
%HTTPoison.AsyncEnd{id: ^id}->
if emit_end do
{[:end], {:end, resp}}
else
{:halt, resp}
end
after
5_000 -> raise "receive timeout"
end
end
def lines(enum), do: lines(enum, :string_split)
def lines(enum, :next_lines) do
enum
|> Stream.transform("",&next_lines/2)
end
def lines(enum, :string_split) do
enum
|> Stream.transform("",fn
:end, acc ->
{[acc],""}
chunk, acc ->
[last_line | lines] =
String.split(acc <> chunk,"\n")
|> Enum.reverse()
{Enum.reverse(lines),last_line}
end)
end
defp next_lines(:end,prev), do: {[prev], ""}
defp next_lines(chunk,current_line) do
# :erlang.garbage_collect()
next_lines(chunk,current_line,[])
end
defp next_lines(<<"\n"::utf8, rest::binary>>,current_line,lines) do
next_lines(rest,"",[<<current_line::binary,"\n"::utf8>> | lines])
end
defp next_lines(<<c::utf8, rest::binary>>,current_line,lines) do
next_lines(rest,<<current_line::binary, c::utf8>>,lines)
end
defp next_lines(<<>>,current_line,lines) do
{Enum.reverse(lines), current_line}
end
end

View File

@ -0,0 +1,9 @@
defmodule ExDataGovUA.Decoders.Base do
@type data :: map()
@type status :: Atom.t()
@type async_response :: Stream.t()
@type sync_response :: {status, data}
@type body :: String.t() | Stream.t()
@callback decode(body) :: async_response | sync_response
end

View File

@ -0,0 +1,8 @@
defmodule ExDataGovUA.Decoders.JasonDecoder do
@behaviour ExDataGovUA.Decoders.Base
@impl true
def decode(data) do
Jason.decode(data, [keys: :atoms])
end
end

View File

@ -0,0 +1,9 @@
defmodule ExDataGovUA.Decoders.JaxonDecoder do
@behaviour ExDataGovUA.Decoders.Base
@impl true
def decode(stream) do
stream
|> Jaxon.Stream.from_enumerable()
end
end

View File

@ -0,0 +1,8 @@
defmodule ExDataGovUA.Fetchers.Base do
@type data :: map()
@type status :: Atom.t()
@type url :: String.t()
@type method :: Atom.t()
@callback fetch(method, url) :: {status, data}
end

View File

@ -0,0 +1,19 @@
defmodule ExDataGovUA.Fetchers.FinchFetcher do
@behaviour ExDataGovUA.Fetchers.Base
@impl true
def fetch(method, url) do
start()
with request <- Finch.build(method, url),
{:ok, %Finch.Response{body: body}} <- Finch.request(request, MyFinchFetcher) do
{:ok, body}
end
end
defp start() do
case Finch.start_link(name: MyFinchFetcher) do
{:ok, pid} -> pid
{:error, {:already_started, pid}} -> pid
end
end
end

View File

@ -0,0 +1,3 @@
defmodule ExDataGovUA.Package.Base do
defstruct [:id, :meta]
end

View File

@ -0,0 +1,33 @@
defmodule ExDataGovUA.Package.Meta.Base do
defstruct [
:profile,
:name,
:contributors,
:created,
:title,
:keywords,
:version,
:licenses,
:homepage,
:id,
:resources,
:description
]
@type t :: %__MODULE__{
profile: String.t(),
name: String.t(),
contributors: List.t(),
created: String.t(),
title: String.t(),
keywords: List.t(),
version: String.t(),
licenses: List.t(),
homepage: String.t(),
id: String.t(),
resources: List.t(),
description: String.t()
}
use ExConstructor
end

View File

@ -0,0 +1,30 @@
defmodule ExDataGovUA.Package.Meta.Parser do
@default_fetcher Application.get_env(:ex_datagovua, :default_fetcher)
@default_decoder Application.get_env(:ex_datagovua, :default_decoder)
@type result :: %ExDataGovUA.Package.Meta.Base{}
@type id :: String.t()
@type url :: String.t()
@type fetcher :: Atom.t()
@type decoder :: Atom.t()
@doc """
Return meta information URL by data package ID
"""
@spec url(id) :: url
def url(id) do
"https://data.gov.ua/api/3/action/package_show?id=#{id}"
end
@doc """
Return meta information (ExDataGovUA.Package.Meta.Base) by data package ID
"""
@spec parse(id, fetcher, decoder) :: %ExDataGovUA.Package.Meta.Base{}
def parse(id, fetcher \\ @default_fetcher, decoder \\ @default_decoder) do
with {:ok, body} <- fetcher.fetch(:get, url(id)),
{:ok, map} <- decoder.decode(body),
result <- ExDataGovUA.Package.Meta.Base.new(map.result) do
result
end
end
end

View File

@ -0,0 +1,11 @@
defmodule ExDataGovUA.Resource.Base do
def download(url, _filename) do
url
|> ExDataGovUA.Streamers.HttpStreamer.get()
|> ExDataGovUA.Archivers.Gz.inflate()
|> ExDataGovUA.Decoders.JaxonDecoder.decode()
|> Enum.to_list()
# |> Stream.run()
# |> ExDataGovUA.Streamers.FileStreamer.export(filename)
end
end

View File

@ -0,0 +1,14 @@
defmodule ExDataGovUA.Streamers.FileStreamer do
@chunk_size 2048
@spec export(Stream.t(), String.t()) :: Atom.t()
def export(stream, filename) do
stream
|> Stream.into(File.stream!(filename, [], @chunk_size))
end
@spec import(String.t()) :: File.Stream.t()
def import(filename) do
filename
|> File.stream!([], @chunk_size)
end
end

View File

@ -0,0 +1,8 @@
defmodule ExDataGovUA.Streamers.HttpStreamer do
alias ExDataGovUA.Commons.HttpStream
def get(url) do
url
|> HttpStream.get()
end
end

18
lib/ex_datagovua.ex Normal file
View File

@ -0,0 +1,18 @@
defmodule ExDataGovUA do
@moduledoc """
Documentation for `ExDatagovua`.
"""
@doc """
Hello world.
## Examples
iex> ExDatagovua.hello()
:world
"""
def hello do
:world
end
end

42
mix.exs Normal file
View File

@ -0,0 +1,42 @@
defmodule ExDataGovUA.MixProject do
use Mix.Project
def project do
[
app: :ex_datagovua,
version: "0.1.0",
elixir: "~> 1.12",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: applications(Mix.env()),
mod: {ExDataGovUA.Application, []}
]
end
defp applications(:dev), do: applications(:all) ++ ~w(remix)a
defp applications(_all), do: ~w(logger)a
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:jason, "~> 1.2.2"},
{:jaxon, "~> 2.0.8"},
{:finch, "~> 0.8.0"},
{:httpoison, "~> 1.8.0"},
{:stream_gzip, "~> 0.4.1"},
{:exconstructor, "~> 1.2.2"},
{:ex_doc, "~> 0.24.2", only: :dev, runtime: false},
{:observer_cli, "~> 1.6.2", only: :dev, runtime: false},
{:credo, "~> 1.5.6", only: :dev, runtime: false},
{:dialyxir, "~> 1.1.0", only: :dev, runtime: false},
# Remix for autorestart
{:remix, "~> 0.0.2", only: :dev}
]
end
end

36
mix.lock Normal file
View File

@ -0,0 +1,36 @@
%{
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"castore": {:hex, :castore, "0.1.11", "c0665858e0e1c3e8c27178e73dffea699a5b28eb72239a3b2642d208e8594914", [:mix], [], "hexpm", "91b009ba61973b532b84f7c09ce441cba7aa15cb8b006cf06c6f4bba18220081"},
"certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"},
"credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"},
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
"elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"},
"exconstructor": {:hex, :exconstructor, "1.2.3", "1f40baf7669aef0ac66325eb02cb119e708d24b490ace05a27bc1b42e30113b2", [:mix], [], "hexpm", "c7f549596308e6ba66aa66a108ddd1048d5654c4f0aa49d55d15df3989554f34"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"finch": {:hex, :finch, "0.8.0", "9fe1b7b1613f4f0f43ac4be94462a0f3eb13264e5e9a624005da5670e452a1d1", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.3.5", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "07650fd74da3fb51984b9f62bf4db3ef720f3c06d914d716cceeb13a2bc2542d"},
"hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"},
"httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
"jaxon": {:hex, :jaxon, "2.0.8", "00951a79d354260e28d7e36f956c3de94818124768a4b22e0fc55559d1b3bfe7", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "74532853b1126609615ea98f0ceb5009e70465ca98027afbbd8ed314d887e82d"},
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
"makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mint": {:hex, :mint, "1.3.0", "396b3301102f7b775e103da5a20494b25753aed818d6d6f0ad222a3a018c3600", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "a9aac960562e43ca69a77e5176576abfa78b8398cec5543dd4fb4ab0131d5c1e"},
"nimble_options": {:hex, :nimble_options, "0.3.5", "a4f6820cdcb4ee444afd78635f323e58e8a5ddf2fbbe9b9d283a99f972034bae", [:mix], [], "hexpm", "f5507cc90033a8d12769522009c80aa9164af6bab245dbd4ad421d008455f1e1"},
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
"nimble_pool": {:hex, :nimble_pool, "0.2.4", "1db8e9f8a53d967d595e0b32a17030cdb6c0dc4a451b8ac787bf601d3f7704c3", [:mix], [], "hexpm", "367e8071e137b787764e6a9992ccb57b276dc2282535f767a07d881951ebeac6"},
"observer_cli": {:hex, :observer_cli, "1.6.2", "016588e9a966247401bcbf02976d468f1e6f06891dde44f873c9259c6496cca1", [:mix, :rebar3], [{:recon, "~>2.5.1", [hex: :recon, repo: "hexpm", optional: false]}], "hexpm", "c23db9e4cca0e849adc42b0a099affb9e6267c5f23a871fc6f144348b249341f"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"recon": {:hex, :recon, "2.5.2", "cba53fa8db83ad968c9a652e09c3ed7ddcc4da434f27c3eaa9ca47ffb2b1ff03", [:mix, :rebar3], [], "hexpm", "2c7523c8dee91dff41f6b3d63cba2bd49eb6d2fe5bf1eec0df7f87eb5e230e1c"},
"remix": {:hex, :remix, "0.0.2", "f06115659d8ede8d725fae1708920ef73353a1b39efe6a232d2a38b1f2902109", [:mix], [], "hexpm", "5f5555646ed4fca83fab8620735150aa0bc408c5a17a70d28cfa7086bc6f497c"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"stream_gzip": {:hex, :stream_gzip, "0.4.1", "d5f611b3fa8f5c9d928db4c8446edb7e22bebdf38d9914b4017a6fff44887b26", [:mix], [], "hexpm", "343dee3cc30dc78562bb524e8ea802a13d6377fc6ef1c05ac4c9d9fb1f58044b"},
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
}

View File

@ -0,0 +1,8 @@
defmodule ExDataGovUATest do
use ExUnit.Case
doctest ExDataGovUA
test "greets the world" do
assert ExDataGovUA.hello() == :world
end
end

1
test/test_helper.exs Normal file
View File

@ -0,0 +1 @@
ExUnit.start()