Skip to content

Commit

Permalink
Merge pull request #1 from abshierjoel/update-for-elixir-16-otp-26
Browse files Browse the repository at this point in the history
chore: Upgrade to Elixir 1.16 and Remove `espec` dependency
  • Loading branch information
abshierjoel committed Jan 24, 2024
2 parents 04b1f4b + aca8d9a commit db412e9
Show file tree
Hide file tree
Showing 7 changed files with 479 additions and 63 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
language:
elixir
language: elixir

matrix:
include:
- otp_release: 19.2
elixir: 1.4.5
- otp_release: 20.0
elixir: 1.5.0
- otp_release: 26.2.1
elixir: 1.16.0

script:
- mix espec --trace
- mix test
98 changes: 62 additions & 36 deletions lib/shorter_maps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ defmodule ShorterMaps do
"""
defmacro sigil_m(term, modifiers)

defmacro sigil_m({:<<>>, [line: line], [string]}, modifiers) do
do_sigil_m(string, line, modifier(modifiers, @default_modifier_m))
defmacro sigil_m({:<<>>, fields, [string]}, modifiers) do
case Keyword.get(fields, :line) do
nil -> raise ArgumentError, "interpolation is not supported with the ~m sigil"
line -> do_sigil_m(string, line, modifier(modifiers, @default_modifier_m))
end
end

defmacro sigil_m({:<<>>, _, _}, _modifiers) do
Expand Down Expand Up @@ -61,10 +64,16 @@ defmodule ShorterMaps do
%Person{id: 100, other_key: :default_val}
"""

defmacro sigil_M(term, modifiers)
defmacro sigil_M({:<<>>, [line: line], [string]}, modifiers) do
do_sigil_m(string, line, modifier(modifiers, @default_modifier_M))

defmacro sigil_M({:<<>>, fields, [string]}, modifiers) do
case Keyword.get(fields, :line) do
nil -> raise ArgumentError, "interpolation is not supported with the ~M sigil"
line -> do_sigil_m(string, line, modifier(modifiers, @default_modifier_M))
end
end

defmacro sigil_M({:<<>>, _, _}, _modifiers) do
raise ArgumentError, "interpolation is not supported with the ~M sigil"
end
Expand All @@ -73,12 +82,13 @@ defmodule ShorterMaps do
defp do_sigil_m("%" <> _rest, _line, ?s) do
raise(ArgumentError, "structs can only consist of atom keys")
end

defp do_sigil_m(raw_string, line, modifier) do
with {:ok, struct_name, rest} <- get_struct(raw_string),
{:ok, old_map, rest} <- get_old_map(rest),
{:ok, keys_and_values} <- expand_variables(rest, modifier) do
final_string = "%#{struct_name}{#{old_map}#{keys_and_values}}"
#IO.puts("#{raw_string} => #{final_string}") # For debugging expansions gone wrong.
# IO.puts("#{raw_string} => #{final_string}") # For debugging expansions gone wrong.
Code.string_to_quoted!(final_string, file: __ENV__.file, line: line)
else
{:error, step, reason} ->
Expand All @@ -90,23 +100,28 @@ defmodule ShorterMaps do
# expecting something like: '%StructName key1, key2' -or- '%StructName oldmap|key1, key2'
# returns {:ok, old_map, keys_and_vars} | {:ok, "", keys_and_vars}
defp get_struct("%" <> rest) do
[struct_name|others] = String.split(rest, " ")
[struct_name | others] = String.split(rest, " ")
body = Enum.join(others, " ")
{:ok, struct_name, body}
end

defp get_struct(no_struct), do: {:ok, "", no_struct}

@re_prefix "[_^]"
@re_varname ~S"[a-zA-Z0-9_]\w*[?!]?" # use ~S to get a real \
# use ~S to get a real \
@re_varname ~S"[a-zA-Z0-9_]\w*[?!]?"
@doc false
# expecting something like "old_map|key1, key2" -or- "key1, key2"
# returns {:ok, "#{old_map}|", keys_and_vars} | {:ok, "", keys_and_vars}
defp get_old_map(string) do
cond do
string =~ ~r/\A\s*#{@re_varname}\s*\|/ -> # make sure this is a map update pipe
[old_map|rest] = String.split(string, "|")
new_body = Enum.join(rest, "|") # put back together unintentionally split things
# make sure this is a map update pipe
string =~ ~r/\A\s*#{@re_varname}\s*\|/ ->
[old_map | rest] = String.split(string, "|")
# put back together unintentionally split things
new_body = Enum.join(rest, "|")
{:ok, "#{old_map}|", new_body}

true ->
{:ok, "", string}
end
Expand All @@ -121,77 +136,88 @@ defmodule ShorterMaps do
# commas.

defp expand_variables(string, modifier) do
result = string
|> String.split(",")
|> identify_entries()
|> Enum.map(fn s ->
cond do
s =~ ~r/\A\s*#{@re_prefix}?#{@re_varname}(\(\s*\))?\s*\Z/ ->
s
|> String.trim
|> expand_variable(modifier)
true -> s
end
end)
|> Enum.join(",")
{:ok, result}
result =
string
|> String.split(",")
|> identify_entries()
|> Enum.map(fn s ->
cond do
s =~ ~r/\A\s*#{@re_prefix}?#{@re_varname}(\(\s*\))?\s*\Z/ ->
s
|> String.trim()
|> expand_variable(modifier)

true ->
s
end
end)
|> Enum.join(",")

{:ok, result}
end

@doc false
defp identify_entries(candidates, partial \\ "", acc \\ [])
defp identify_entries([], "", acc), do: acc |> Enum.reverse
defp identify_entries([], "", acc), do: acc |> Enum.reverse()

defp identify_entries([], remainder, _acc) do
# we failed, use code module to raise a syntax error:
Code.string_to_quoted!(remainder)
end
defp identify_entries([h|t], partial, acc) do
entry = case partial do
"" -> h
_ -> partial <> "," <> h
end

defp identify_entries([h | t], partial, acc) do
entry =
case partial do
"" -> h
_ -> partial <> "," <> h
end

if check_entry(entry, [:map, :list]) do
identify_entries(t, "", [entry|acc])
identify_entries(t, "", [entry | acc])
else
identify_entries(t, entry, acc)
end
end

@doc false
defp check_entry(_entry, []), do: false
defp check_entry(entry, [:map|rest]) do

defp check_entry(entry, [:map | rest]) do
case Code.string_to_quoted("%{#{entry}}") do
{:ok, _} -> true
{:error, _} -> check_entry(entry, rest)
end
end
defp check_entry(entry, [:list|rest]) do

defp check_entry(entry, [:list | rest]) do
case Code.string_to_quoted("[#{entry}]") do
{:ok, _} -> true
{:error, _} -> check_entry(entry, rest)
end
end


@doc false
defp expand_variable(var, ?s) do
"\"#{fix_key(var)}\" => #{var}"
end

defp expand_variable(var, ?a) do
"#{fix_key(var)}: #{var}"
end

@doc false
defp fix_key("_" <> name), do: name
defp fix_key("^" <> name), do: name

defp fix_key(name) do
String.replace_suffix(name, "()", "")
end

@doc false
defp modifier([], default), do: default
defp modifier([mod], _default) when mod in 'as', do: mod
defp modifier([mod], _default) when mod in ~c"as", do: mod

defp modifier(_, _default) do
raise(ArgumentError, "only these modifiers are supported: s, a")
end

end
15 changes: 5 additions & 10 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ defmodule ShorterMaps.Mixfile do
app: :shorter_maps,
version: @version,
elixir: "~> 1.0",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
build_embedded: Mix.env() == :prod,
start_permanent: Mix.env() == :prod,
deps: deps(),
# Hex
package: hex_package(),
description: "~M sigil for map shorthand. `~M{id, name} ~> %{id: id, name: name}`",
# Docs
name: "ShorterMaps",
# Testing
preferred_cli_env: [espec: :test],
name: "ShorterMaps"
]
end

Expand All @@ -27,16 +25,13 @@ defmodule ShorterMaps.Mixfile do
end

defp hex_package do
[maintainers: ["Chris Meyer"],
licenses: ["MIT"],
links: %{"GitHub" => @repo_url}]
[maintainers: ["Chris Meyer"], licenses: ["MIT"], links: %{"GitHub" => @repo_url}]
end

defp deps do
[
{:ex_doc, ">= 0.0.0", only: :dev},
{:earmark, ">= 0.0.0", only: :dev},
{:espec, "~> 1.2", only: [:dev, :test]},
{:earmark, ">= 0.0.0", only: :dev}
]
end
end
11 changes: 6 additions & 5 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
%{"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []},
"espec": {:hex, :espec, "1.4.2", "7dda1a2369ca597d5d28614b2dc69f1b19c67e76e01b2a74b04a462d832a6e1d", [:mix], [{:meck, "0.8.4", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
"meck": {:hex, :meck, "0.8.4", "59ca1cd971372aa223138efcf9b29475bde299e1953046a0c727184790ab1520", [:make, :rebar], []},
"pavlov": {:hex, :pavlov, "0.2.3", "9072029af61301463a6e273e2829e9eab14bd1e7a5c381886d5166e6739e6fcf", [:mix], [{:meck, "~> 0.8.2", [hex: :meck, optional: false]}]}}
%{
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], [], "hexpm", "0fdcd651f9689e81cda24c8e5d06947c5aca69dbd8ce3d836b02bcd0c6004592"},
"ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm", "5c30e436a5acfdc2fd8fe6866585fcaf30f434c611d8119d4f3390ced2a550f3"},
"meck": {:hex, :meck, "0.8.4", "59ca1cd971372aa223138efcf9b29475bde299e1953046a0c727184790ab1520", [:make, :rebar], [], "hexpm", "2cdfbd0edd8f62b3d2061efc03c0e490282dd2ea6de44e15d2006e83f4f8eead"},
"pavlov": {:hex, :pavlov, "0.2.3", "9072029af61301463a6e273e2829e9eab14bd1e7a5c381886d5166e6739e6fcf", [:mix], [{:meck, "~> 0.8.2", [hex: :meck, optional: false]}]},
}
9 changes: 0 additions & 9 deletions spec/spec_helper.exs

This file was deleted.

Loading

0 comments on commit db412e9

Please sign in to comment.