Skip to content

Instantly share code, notes, and snippets.

@seivan
Created April 6, 2018 12:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seivan/f3b7ef2792ffc0024f76f7e0e1ae91c3 to your computer and use it in GitHub Desktop.
Save seivan/f3b7ef2792ffc0024f76f7e0e1ae91c3 to your computer and use it in GitHub Desktop.
defmodule Tiled.Utils.Decoder do
@moduledoc false
defmodule InternalDecoder do
@moduledoc false
defmacro __before_compile__(_env) do
quote do
@spec decode_key_value({:type, String.t()}) :: atom() | nil
defp decode_key_value({:type, ""}), do: nil
defp decode_key_value({:type, type}) when is_binary(type), do: type |> String.to_atom()
@spec decode_key_value({:name, String.t()}) :: atom() | nil
defp decode_key_value({:name, ""}), do: nil
defp decode_key_value({:name, name}) when is_binary(name), do: name |> String.to_atom()
@spec decode_key_value({:properties, map() | nil}) :: Tiled.property_values()
defp decode_key_value({:properties, properties}), do: properties || %{}
@spec decode_key_value({:property_types, map() | nil}) :: Tiled.property_types()
defp decode_key_value({:property_types, types}), do: types || %{}
defp decode_key_value({key, _} = key_value) when is_atom(key), do: key_value
end
end
end
defmacro __using__(_) do
quote do
@before_compile InternalDecoder
@spec decode(map(), ({atom(), term()} -> {atom(), term()} | term())) :: struct()
defp decode(map, transformer \\ & &1) when is_map(map) and is_function(transformer, 1) do
module = __MODULE__
module
|> struct
|> Map.from_struct()
|> Map.keys()
|> Enum.reduce(%{}, fn key, memo ->
json_key = downcase_key(key)
case transformer.({key, map[json_key]}) do
{new_key, value} -> Map.put(memo, new_key, value)
value -> Map.put(memo, key, value)
end
end)
|> (fn map -> struct(module, map) end).()
end
@spec downcase_key(atom() | String.t()) :: atom()
defp downcase_key(key) when is_atom(key),
do: key |> Atom.to_string() |> Macro.camelize() |> String.downcase() |> String.to_atom()
defp downcase_key(key) when is_binary(key),
do: key |> Macro.camelize() |> String.downcase() |> String.to_atom()
end
end
end
defmodule Tiled.TileMap do
alias Tiled.Utils.{Decoder, TypedStruct}
use Decoder
use TypedStruct,
background_color: String.t() | nil,
height: integer,
infinite: boolean,
layers: list(Tiled.Layer.TileLayer),
next_object_id: integer,
orientation: :orthogonal | :isometric,
properties: Tiled.property_values(),
property_types: Tiled.property_types(),
render_order: :left_up | :right_up | :right_down | :left_down,
tiled_version: String.t(),
tile_height: integer,
tile_sets: list(Tiled.TileSet.File | Tiled.TileSet.Embedded | Tiled.TileSet.ImageLayer),
tile_width: integer,
type: :map,
version: integer,
width: integer
@spec new(map()) :: t()
def new(raw_map) when is_map(raw_map), do: raw_map |> decode(&decode_key_value/1)
defp decode_key_value({:tile_sets, tilesets}) when is_list(tilesets),
do: tilesets |> Enum.map(&Tiled.TileSet.new/1)
defp decode_key_value({:layers, layers}) when is_list(layers),
do: layers |> Enum.map(&Tiled.Layer.new/1)
defp decode_key_value({:orientation, orientation}) when is_binary(orientation),
do: orientation |> String.to_atom()
defp decode_key_value({:render_order, render_order}) when is_binary(render_order),
do: render_order |> String.replace("-", "_") |> String.to_atom()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment