From ea2c53dfe966e4b758e6aa2811e9d3db89abcdd7 Mon Sep 17 00:00:00 2001 From: Milton Mazzarri Date: Tue, 1 Aug 2023 12:33:58 -0500 Subject: [PATCH 1/4] Improve Date/DateTime interactions This PR includes some improvements when we interact with `Date` or `DateTime`. * Elixir v1.15 introduced `{Date,DateTime,NaiveDateTime,Time}.{after?/2,before?/2}`. This means that we could improve the readability on some Date/Time comparisons. * I also took the chance to transform some `Timex` `defdelegate` to their native equivalent. Finally, most of these additions only apply if we're running on Elixir v1.15, that's why I decided to add new entries for Elixir and OTP matrix for CI purposes. --- .github/workflows/ci.yml | 4 ++-- lib/style/single_node.ex | 23 +++++++++++++++++++++++ test/style/single_node_test.exs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2b3bb5d..d5588fb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,8 @@ jobs: name: Ex${{matrix.elixir}}/OTP${{matrix.otp}} strategy: matrix: - elixir: ['1.14.2'] - otp: ['25.1.2'] + elixir: ['1.14.2', '1.15.0'] + otp: ['25.1.2', '26.0'] steps: - uses: actions/checkout@v3 - uses: erlef/setup-beam@v1 diff --git a/lib/style/single_node.ex b/lib/style/single_node.ex index 713043f9..e3680f35 100644 --- a/lib/style/single_node.ex +++ b/lib/style/single_node.ex @@ -95,6 +95,29 @@ defmodule Styler.Style.SingleNode do defp style({{:., dm, [{:__aliases__, am, [:Logger]}, :warn]}, funm, args}), do: {{:., dm, [{:__aliases__, am, [:Logger]}, :warning]}, funm, args} + # Transform Timex defdelegates + defp style({{:., dm, [{:__aliases__, am, [:Timex]}, :today]}, funm, args}), + do: {{:., dm, [{:__aliases__, am, [:Date]}, :utc_today]}, funm, args} + + defp style({{:., dm, [{:__aliases__, am, [:Timex]}, :now]}, funm, args}), + do: {{:., dm, [{:__aliases__, am, [:DateTime]}, :utc_now]}, funm, args} + + if Version.match?(System.version(), ">= 1.15.0-dev") do + # Timex.{before?,after?} -> DateTime.{before?,after?} + defp style({{:., dm, [{:__aliases__, am, [:Timex]}, fun]}, funm, args}) when fun in [:before?, :after?], + do: {{:., dm, [{:__aliases__, am, [:DateTime]}, fun]}, funm, args} + + # {DateTime,NaiveDateTime,Time,Date}.compare(a, b) == :lt -> {DateTime,NaiveDateTime,Time,Date}.before?(a, b) + defp style({:==, _, [{{:., dm, [{:__aliases__, am, [mod]}, :compare]}, funm, args}, {:__block__, _, [:lt]}]}) + when mod in ~w[DateTime NaiveDateTime Time Date]a, + do: {{:., dm, [{:__aliases__, am, [mod]}, :before?]}, funm, args} + + # {DateTime,NaiveDateTime,Time,Date}.compare(a, b) == :gt -> {DateTime,NaiveDateTime,Time,Date}.after?(a, b) + defp style({:==, _, [{{:., dm, [{:__aliases__, am, [mod]}, :compare]}, funm, args}, {:__block__, _, [:gt]}]}) + when mod in ~w[DateTime NaiveDateTime Time Date]a, + do: {{:., dm, [{:__aliases__, am, [mod]}, :after?]}, funm, args} + end + # Remove parens from 0 arity funs (Credo.Check.Readability.ParenthesesOnZeroArityDefs) defp style({def, dm, [{fun, funm, []} | rest]}) when def in ~w(def defp)a and is_atom(fun), do: style({def, dm, [{fun, Keyword.delete(funm, :closing), nil} | rest]}) diff --git a/test/style/single_node_test.exs b/test/style/single_node_test.exs index c231dcc0..357ce226 100644 --- a/test/style/single_node_test.exs +++ b/test/style/single_node_test.exs @@ -21,6 +21,38 @@ defmodule Styler.Style.SingleNodeTest do assert_style("Logger.warn(foo, bar)", "Logger.warning(foo, bar)") end + test "Timex.now -> DateTime.utc_now" do + assert_style("Timex.now()", "DateTime.utc_now()") + end + + test "Timex.today -> Date.utc_today" do + assert_style("Timex.today()", "Date.utc_today()") + end + + if Version.match?(System.version(), ">= 1.15.0-dev") do + test "Timex.before?(a, b) -> DateTime.before?(a, b)" do + assert_style("Timex.before?(a, b)", "DateTime.before?(a, b)") + end + + test "Timex.after?(a, b) -> DateTime.after?(a, b)" do + assert_style("Timex.after?(a, b)", "DateTime.after?(a, b)") + end + + test "DateTime.compare to DateTime.before?" do + assert_style("DateTime.compare(foo, bar) == :lt", "DateTime.before?(foo, bar)") + assert_style("NaiveDateTime.compare(foo, bar) == :lt", "NaiveDateTime.before?(foo, bar)") + assert_style("Time.compare(foo, bar) == :lt", "Time.before?(foo, bar)") + assert_style("Date.compare(foo, bar) == :lt", "Date.before?(foo, bar)") + end + + test "DateTime.compare to DateTime.after" do + assert_style("DateTime.compare(foo, bar) == :gt", "DateTime.after?(foo, bar)") + assert_style("NaiveDateTime.compare(foo, bar) == :gt", "NaiveDateTime.after?(foo, bar)") + assert_style("Time.compare(foo, bar) == :gt", "Time.after?(foo, bar)") + assert_style("Time.compare(foo, bar) == :gt", "Time.after?(foo, bar)") + end + end + describe "def / defp" do test "0-arity functions have parens removed" do assert_style("def foo(), do: :ok", "def foo, do: :ok") From e221da8ceb943cc56288d45706f525eeed64e7fc Mon Sep 17 00:00:00 2001 From: Milton Mazzarri Date: Tue, 1 Aug 2023 13:06:05 -0500 Subject: [PATCH 2/4] remove otp 26.0 for now from ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5588fb7..93df1096 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: elixir: ['1.14.2', '1.15.0'] - otp: ['25.1.2', '26.0'] + otp: ['25.1.2'] steps: - uses: actions/checkout@v3 - uses: erlef/setup-beam@v1 From f46ae19a5fe74c32308188c5f756e8c4af3684b8 Mon Sep 17 00:00:00 2001 From: Milton Mazzarri Date: Tue, 1 Aug 2023 13:12:22 -0500 Subject: [PATCH 3/4] update test names --- test/style/single_node_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/style/single_node_test.exs b/test/style/single_node_test.exs index 357ce226..16ac5f50 100644 --- a/test/style/single_node_test.exs +++ b/test/style/single_node_test.exs @@ -38,14 +38,14 @@ defmodule Styler.Style.SingleNodeTest do assert_style("Timex.after?(a, b)", "DateTime.after?(a, b)") end - test "DateTime.compare to DateTime.before?" do + test "{DateTime,NaiveDateTime,Time,Date}.compare to {DateTime,NaiveDateTime,Time,Date}.before?" do assert_style("DateTime.compare(foo, bar) == :lt", "DateTime.before?(foo, bar)") assert_style("NaiveDateTime.compare(foo, bar) == :lt", "NaiveDateTime.before?(foo, bar)") assert_style("Time.compare(foo, bar) == :lt", "Time.before?(foo, bar)") assert_style("Date.compare(foo, bar) == :lt", "Date.before?(foo, bar)") end - test "DateTime.compare to DateTime.after" do + test "{DateTime,NaiveDateTime,Time,Date}.compare to {DateTime,NaiveDateTime,Time,Date}.after?" do assert_style("DateTime.compare(foo, bar) == :gt", "DateTime.after?(foo, bar)") assert_style("NaiveDateTime.compare(foo, bar) == :gt", "NaiveDateTime.after?(foo, bar)") assert_style("Time.compare(foo, bar) == :gt", "Time.after?(foo, bar)") From cd4a52087c6e1da68cd9e8350be13539d96837f1 Mon Sep 17 00:00:00 2001 From: Milton Mazzarri Date: Tue, 1 Aug 2023 13:55:15 -0500 Subject: [PATCH 4/4] pr feedback --- lib/style/single_node.ex | 16 +++++----------- test/style/single_node_test.exs | 8 -------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/lib/style/single_node.ex b/lib/style/single_node.ex index e3680f35..3447a0cb 100644 --- a/lib/style/single_node.ex +++ b/lib/style/single_node.ex @@ -103,19 +103,13 @@ defmodule Styler.Style.SingleNode do do: {{:., dm, [{:__aliases__, am, [:DateTime]}, :utc_now]}, funm, args} if Version.match?(System.version(), ">= 1.15.0-dev") do - # Timex.{before?,after?} -> DateTime.{before?,after?} - defp style({{:., dm, [{:__aliases__, am, [:Timex]}, fun]}, funm, args}) when fun in [:before?, :after?], - do: {{:., dm, [{:__aliases__, am, [:DateTime]}, fun]}, funm, args} - # {DateTime,NaiveDateTime,Time,Date}.compare(a, b) == :lt -> {DateTime,NaiveDateTime,Time,Date}.before?(a, b) - defp style({:==, _, [{{:., dm, [{:__aliases__, am, [mod]}, :compare]}, funm, args}, {:__block__, _, [:lt]}]}) - when mod in ~w[DateTime NaiveDateTime Time Date]a, - do: {{:., dm, [{:__aliases__, am, [mod]}, :before?]}, funm, args} - # {DateTime,NaiveDateTime,Time,Date}.compare(a, b) == :gt -> {DateTime,NaiveDateTime,Time,Date}.after?(a, b) - defp style({:==, _, [{{:., dm, [{:__aliases__, am, [mod]}, :compare]}, funm, args}, {:__block__, _, [:gt]}]}) - when mod in ~w[DateTime NaiveDateTime Time Date]a, - do: {{:., dm, [{:__aliases__, am, [mod]}, :after?]}, funm, args} + defp style({:==, _, [{{:., dm, [{:__aliases__, am, [mod]}, :compare]}, funm, args}, {:__block__, _, [result]}]}) + when mod in ~w[DateTime NaiveDateTime Time Date]a and result in [:lt, :gt] do + fun = if result == :lt, do: :before?, else: :after? + {{:., dm, [{:__aliases__, am, [mod]}, fun]}, funm, args} + end end # Remove parens from 0 arity funs (Credo.Check.Readability.ParenthesesOnZeroArityDefs) diff --git a/test/style/single_node_test.exs b/test/style/single_node_test.exs index 16ac5f50..a3d8c237 100644 --- a/test/style/single_node_test.exs +++ b/test/style/single_node_test.exs @@ -30,14 +30,6 @@ defmodule Styler.Style.SingleNodeTest do end if Version.match?(System.version(), ">= 1.15.0-dev") do - test "Timex.before?(a, b) -> DateTime.before?(a, b)" do - assert_style("Timex.before?(a, b)", "DateTime.before?(a, b)") - end - - test "Timex.after?(a, b) -> DateTime.after?(a, b)" do - assert_style("Timex.after?(a, b)", "DateTime.after?(a, b)") - end - test "{DateTime,NaiveDateTime,Time,Date}.compare to {DateTime,NaiveDateTime,Time,Date}.before?" do assert_style("DateTime.compare(foo, bar) == :lt", "DateTime.before?(foo, bar)") assert_style("NaiveDateTime.compare(foo, bar) == :lt", "NaiveDateTime.before?(foo, bar)")