Skip to content

Commit d7f96d8

Browse files
lukaszsamsonjosevalim
authored andcommitted
Keep backwards compatibility on Range and Date.Range (#11117)
1 parent 010efd8 commit d7f96d8

File tree

4 files changed

+177
-24
lines changed

4 files changed

+177
-24
lines changed

lib/elixir/lib/calendar/date_range.ex

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ defmodule Date.Range do
2626
defstruct [:first, :last, :first_in_iso_days, :last_in_iso_days, :step]
2727

2828
defimpl Enumerable do
29-
def member?(%{first: %{calendar: calendar}} = range, %Date{calendar: calendar} = date) do
30-
%{
31-
first_in_iso_days: first_days,
32-
last_in_iso_days: last_days,
33-
step: step
34-
} = range
35-
29+
def member?(
30+
%Date.Range{
31+
first: %{calendar: calendar},
32+
first_in_iso_days: first_days,
33+
last_in_iso_days: last_days,
34+
step: step
35+
} = range,
36+
%Date{calendar: calendar} = date
37+
) do
3638
{days, _} = Date.to_iso_days(date)
3739

3840
cond do
@@ -47,24 +49,43 @@ defmodule Date.Range do
4749
end
4850
end
4951

50-
def member?(_, _) do
52+
def member?(%Date.Range{step: _}, _) do
5153
{:ok, false}
5254
end
5355

56+
# TODO: Remove me on v2.0
57+
def member?(
58+
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
59+
date_range,
60+
date
61+
) do
62+
step = if first_days <= last_days, do: 1, else: -1
63+
member?(Map.put(date_range, :step, step), date)
64+
end
65+
5466
def count(range) do
5567
{:ok, size(range)}
5668
end
5769

58-
def slice(range) do
59-
%{
60-
first_in_iso_days: first,
61-
first: %{calendar: calendar},
62-
step: step
63-
} = range
64-
70+
def slice(
71+
%Date.Range{
72+
first_in_iso_days: first,
73+
first: %{calendar: calendar},
74+
step: step
75+
} = range
76+
) do
6577
{:ok, size(range), &slice(first + &1 * step, step, &2, calendar)}
6678
end
6779

80+
# TODO: Remove me on v2.0
81+
def slice(
82+
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
83+
date_range
84+
) do
85+
step = if first_days <= last_days, do: 1, else: -1
86+
slice(Map.put(date_range, :step, step))
87+
end
88+
6889
defp slice(current, _step, 1, calendar) do
6990
[date_from_iso_days(current, calendar)]
7091
end
@@ -76,17 +97,30 @@ defmodule Date.Range do
7697
]
7798
end
7899

79-
def reduce(range, acc, fun) do
80-
%{
81-
first_in_iso_days: first_days,
82-
last_in_iso_days: last_days,
83-
first: %{calendar: calendar},
84-
step: step
85-
} = range
86-
100+
def reduce(
101+
%Date.Range{
102+
first_in_iso_days: first_days,
103+
last_in_iso_days: last_days,
104+
first: %{calendar: calendar},
105+
step: step
106+
},
107+
acc,
108+
fun
109+
) do
87110
reduce(first_days, last_days, acc, fun, step, calendar)
88111
end
89112

113+
# TODO: Remove me on v2.0
114+
def reduce(
115+
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
116+
date_range,
117+
acc,
118+
fun
119+
) do
120+
step = if first_days <= last_days, do: 1, else: -1
121+
reduce(Map.put(date_range, :step, step), acc, fun)
122+
end
123+
90124
defp reduce(_first_days, _last_days, {:halt, acc}, _fun, _step, _calendar) do
91125
{:halted, acc}
92126
end
@@ -135,6 +169,15 @@ defmodule Date.Range do
135169
defp size(%Date.Range{first_in_iso_days: first_days, last_in_iso_days: last_days, step: step}),
136170
do: abs(div(last_days - first_days, step)) + 1
137171

172+
# TODO: Remove me on v2.0
173+
defp size(
174+
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
175+
date_range
176+
) do
177+
step = if first_days <= last_days, do: 1, else: -1
178+
size(Map.put(date_range, :step, step))
179+
end
180+
138181
defp empty?(%Date.Range{
139182
first_in_iso_days: first_days,
140183
last_in_iso_days: last_days,
@@ -151,16 +194,33 @@ defmodule Date.Range do
151194
when step < 0 and first_days < last_days,
152195
do: true
153196

154-
defp empty?(%Date.Range{}), do: false
197+
defp empty?(%Date.Range{step: _}), do: false
198+
199+
# TODO: Remove me on v2.0
200+
defp empty?(
201+
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
202+
date_range
203+
) do
204+
step = if first_days <= last_days, do: 1, else: -1
205+
empty?(Map.put(date_range, :step, step))
206+
end
155207
end
156208

157209
defimpl Inspect do
210+
import Kernel, except: [inspect: 2]
211+
158212
def inspect(%Date.Range{first: first, last: last, step: 1}, _) do
159213
"#DateRange<" <> inspect(first) <> ", " <> inspect(last) <> ">"
160214
end
161215

162216
def inspect(%Date.Range{first: first, last: last, step: step}, _) do
163217
"#DateRange<" <> inspect(first) <> ", " <> inspect(last) <> ", #{step}>"
164218
end
219+
220+
# TODO: Remove me on v2.0
221+
def inspect(%{__struct__: Date.Range, first: first, last: last} = date_range, opts) do
222+
step = if first <= last, do: 1, else: -1
223+
inspect(Map.put(date_range, :step, step), opts)
224+
end
165225
end
166226
end

lib/elixir/lib/enum.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2661,6 +2661,12 @@ defmodule Enum do
26612661
end
26622662
end
26632663

2664+
# TODO: Remove me on v2.0
2665+
def slice(enumerable, %{__struct__: Range, first: first, last: last} = index_range) do
2666+
step = if first <= last, do: 1, else: -1
2667+
slice(enumerable, Map.put(index_range, :step, step))
2668+
end
2669+
26642670
defp slice_range(enumerable, first, last) when last >= first and last >= 0 and first >= 0 do
26652671
slice_any(enumerable, first, last - first + 1)
26662672
end

lib/elixir/test/elixir/calendar/date_range_test.exs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,71 @@ defmodule Date.RangeTest do
141141
Date.range(~D[2000-01-01], ~D[2000-01-31], step)
142142
end
143143
end
144+
145+
describe "old date ranges" do
146+
test "inspect" do
147+
asc = %{
148+
__struct__: Date.Range,
149+
first: ~D[2021-07-14],
150+
first_in_iso_days: 738_350,
151+
last: ~D[2021-07-17],
152+
last_in_iso_days: 738_353
153+
}
154+
155+
desc = %{
156+
__struct__: Date.Range,
157+
first: ~D[2021-07-17],
158+
first_in_iso_days: 738_353,
159+
last: ~D[2021-07-14],
160+
last_in_iso_days: 738_350
161+
}
162+
163+
assert inspect(asc) == "#DateRange<~D[2021-07-14], ~D[2021-07-17]>"
164+
assert inspect(desc) == "#DateRange<~D[2021-07-17], ~D[2021-07-14], -1>"
165+
end
166+
167+
test "enumerable" do
168+
asc = %{
169+
__struct__: Date.Range,
170+
first: ~D[2021-07-14],
171+
first_in_iso_days: 738_350,
172+
last: ~D[2021-07-17],
173+
last_in_iso_days: 738_353
174+
}
175+
176+
desc = %{
177+
__struct__: Date.Range,
178+
first: ~D[2021-07-17],
179+
first_in_iso_days: 738_353,
180+
last: ~D[2021-07-14],
181+
last_in_iso_days: 738_350
182+
}
183+
184+
# member? implementations tests also empty?
185+
assert Enumerable.member?(asc, ~D[2021-07-15])
186+
assert {:ok, 4, _} = Enumerable.slice(asc)
187+
188+
assert Enum.reduce(asc, [], fn x, acc -> [x | acc] end) == [
189+
~D[2021-07-17],
190+
~D[2021-07-16],
191+
~D[2021-07-15],
192+
~D[2021-07-14]
193+
]
194+
195+
assert Enum.count(asc) == 4
196+
197+
# member? implementations tests also empty?
198+
assert Enumerable.member?(desc, ~D[2021-07-15])
199+
assert {:ok, 4, _} = Enumerable.slice(desc)
200+
201+
assert Enum.reduce(desc, [], fn x, acc -> [x | acc] end) == [
202+
~D[2021-07-14],
203+
~D[2021-07-15],
204+
~D[2021-07-16],
205+
~D[2021-07-17]
206+
]
207+
208+
assert Enum.count(desc) == 4
209+
end
210+
end
144211
end

lib/elixir/test/elixir/range_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ defmodule RangeTest do
9696
end
9797

9898
describe "old ranges" do
99+
test "inspect" do
100+
asc = %{__struct__: Range, first: 1, last: 3}
101+
desc = %{__struct__: Range, first: 3, last: 1}
102+
103+
assert inspect(asc) == "1..3"
104+
assert inspect(desc) == "3..1//-1"
105+
end
106+
99107
test "enum" do
100108
asc = %{__struct__: Range, first: 1, last: 3}
101109
desc = %{__struct__: Range, first: 3, last: 1}
@@ -104,11 +112,23 @@ defmodule RangeTest do
104112
assert Enum.member?(asc, 2)
105113
assert Enum.count(asc) == 3
106114
assert Enum.drop(asc, 1) == [2, 3]
115+
assert Enum.slice([1, 2, 3, 4, 5, 6], asc) == [2, 3, 4]
116+
# testing private Enum.aggregate
117+
assert Enum.max(asc) == 3
118+
assert Enum.sum(asc) == 6
119+
assert Enum.min_max(asc) == {1, 3}
120+
assert Enum.reduce(asc, 0, fn a, b -> a + b end) == 6
107121

108122
assert Enum.to_list(desc) == [3, 2, 1]
109123
assert Enum.member?(desc, 2)
110124
assert Enum.count(desc) == 3
111125
assert Enum.drop(desc, 1) == [2, 1]
126+
assert Enum.slice([1, 2, 3, 4, 5, 6], desc) == []
127+
# testing private Enum.aggregate
128+
assert Enum.max(desc) == 3
129+
assert Enum.sum(desc) == 6
130+
assert Enum.min_max(desc) == {1, 3}
131+
assert Enum.reduce(desc, 0, fn a, b -> a + b end) == 6
112132
end
113133

114134
test "string" do

0 commit comments

Comments
 (0)