Packages

Jq like thing for grabbing stuff out of json like objects

Current section

Files

Jump to
jqish lib jqish.ex
Raw

lib/jqish.ex

defmodule Jqish do
@moduledoc """
Documentation for Jqish.
"""
defmodule SyntaxError do
defstruct [:token, before: nil]
end
defmodule UnexpectedValueError do
defstruct [:target, :path]
end
defp lex(rule) do
rule
|> to_charlist
|> :jqish_lexer.string
|> case do
{:ok, tokens, _} ->
{:ok, tokens}
{:error, {_, _, {_, token}}, _} ->
{:error, %SyntaxError{token: :erlang.list_to_binary(token)}}
end
end
def parse(rule) do
with {:ok, tokens} <- lex(rule) do
case :jqish_parser.parse(tokens) do
{:ok, _} = ok ->
ok
{:error, {_, :jqish_parser, ['syntax error before: ', before]}} ->
{:error, %SyntaxError{before: :erlang.list_to_binary(before)}}
end
end
end
defp e(t, []), do: t
defp e(t, [{:optional, identifier} | rest]) when is_map(t), do: e(Map.get(t, identifier), rest)
defp e(_not_a_map, [{:optional, _identifier} | _rest]), do: nil
defp e(t, [{:slice, from, to} | rest]) when is_list(t) do
e(Enum.slice(t, from, to), rest)
end
defp e(t, [:iterator | rest]) when is_list(t) do
Enum.map(t, fn element -> e(element, rest) end)
end
defp e(t, [index | rest]) when is_list(t) and is_integer(index) do
e(Enum.at(t, index), rest)
end
defp e(t, [identifier | rest]) when is_map(t), do: e(Map.get(t, identifier), rest)
defp e(target, path) do
{:error, %UnexpectedValueError{target: target, path: path}}
end
def eval(target, path) do
IO.inspect {:target, target, :path, path}
case e(target, path) do
{:error, _} = err -> err
good -> {:ok, good}
end
end
@doc """
Run a rule on a target.
## Examples
iex> Jqish.run(%{"foo" => %{"bar" => [1, 2, 3, 4]}}, ".foo.bar.[2]")
{:ok, 3}
"""
def run(target, rule) do
with {:ok, path} <- parse(rule) do
eval(target, path)
end
end
end