-
Notifications
You must be signed in to change notification settings - Fork 21.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Duration#before and #after as aliases for #ago and #since #27721
Conversation
cc @pixeltrix |
For comparison, the existing API: let(:today) { 2.weeks.since(customer_start_date) }
let(:earlier_date) { 5.days.until(today) } |
I think the consensus is that existing methods are fine and adding new aliases isn't required. @Widdershin sorry, but thanks for your suggestion. |
I'm quite sympathetic to this. If you gave me the choice between: let(:today) { 2.weeks.since(customer_start_date) }
let(:earlier_date) { 5.days.until(today) } And let(:today) { 2.weeks.after(customer_start_date) }
let(:earlier_date) { 5.days.before(today) } I'd say the latter requires far less mental gymnastics to read. And I think that's a good example of the strength of alias. It allows us to bend the same instructions to read the most natural in more instances. |
Actually, I think the after is compelling enough that I'd like to see this make it in. I'd want to write code like the latter. |
Need a CHANGELOG entry explaining its value. Do use the before/after example. |
@dhh Thanks for your consideration. I've altered my commit to include a CHANGELOG entry. Let me know if you want anything else added. |
activesupport/CHANGELOG.md
Outdated
@@ -1,3 +1,28 @@ | |||
* Add `ActiveSupport::Duration#before` and `#after` as aliases for `#until` and `#since` | |||
|
|||
It is common in specs to declare dates relative to one another as part of setup. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good example, but it suggests that the API is somehow related to specs or that its value is derived from an edge case usage.
Think a simple before/after with just the code is clear & convincing, e.g.
Add `ActiveSupport::Duration#before` and `#after` as aliases for `#until` and `#since`
These read more like English and require less mental gymnastics to read and write.
Before:
2.weeks.since(customer_start_date)
5.days.until(today)
After:
2.weeks.after(customer_start_date)
5.days.before(today)
|
||
# Calculates a new Time or Date that is as far in the past | ||
# as this Duration represents. | ||
def ago(time = ::Time.current) | ||
sum(-1, time) | ||
end | ||
alias :until :ago | ||
alias :before :ago |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still feels weird to alias these—and leave ago's required argument as optional—rather than define new methods. Not necessary for this PR, but worth considering
# Calculates this duration in the past relative to +date_or_time+.
def before(date_or_time)
sum(-1, date_or_time)
end
alias :until :before
def ago
before ::Time.current
end
That'd break people using the odd 2.days.ago customer_start_date
and 5.weeks.since
formulations, though, so it'd need deprecation 😐
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to make this change if it's desired, but as you say, perhaps in a different PR. What is the process for deprecating something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The process is to allow both old and new method signatures and give a deprecation warning if we see the old one.
# Calculates this duration in the past relative to +date_or_time+.
def before(date_or_time)
sum(-1, date_or_time)
end
alias :until :before
def ago(deprecated_date_or_time = nil)
if deprecated_date_or_time
ActiveSupport::Deprecation.warn "Passing a date_or_time argument to #ago is deprecated and will be removed in Rails 5.2. Use #before(date_or_time) instead."
end
before deprecated_date_or_time || ::Time.current
end
I have resolved the conflicts and updated the CHANGELOG entry as per @jeremy's feedback. Please let me know if there's anything else you would like done before this is merged. |
activesupport/CHANGELOG.md
Outdated
@@ -1,3 +1,19 @@ | |||
* Add `ActiveSupport::Duration#before` and `#after` as aliases for `#until` and `#since` | |||
|
|||
These read more like English, and require less mental gymnastics to read and write. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can chop this comma.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs test coverage for the new aliases. (If these were removed, no tests would fail, but apps would break.)
Hi @jeremy, thanks for your review. I have added test coverage. I included a test for calling before and after with no arguments, following the rationale that since it's part of the public API it should be tested to avoid regressions. I did not duplicate the more intricate test coverage for since and ago, but I can if desired. I also removed the comma from my changelog entry. Please let me know if there are any other changes desired. 😸 |
It's common in test cases at my job to have code like this: let(:today) { customer_start_date + 2.weeks } let(:earlier_date) { today - 5.days } With this change, we can instead write let(:today) { 2.weeks.after(customer_start_date) } let(:earlier_date) { 5.days.before(today) }
Looks like I have a failure to look into. Strange, as I've adapted that test directly from another one. |
Thanks @jeremy for your review and merge, and also for sorting out that test case for me. 😄 |
It's common in test cases at my job to have code like this:
With this change, we can instead write:
I find this to be much more readable, and it makes me happy 😄
A small downside I see is that
before
andafter
don't make very much sense when used without an argument.I would be happy to pull these into a new set of methods that always take an argument, but I figured that the lowest impact change was an alias.
I also did not add a test case, as I saw there was no additional test coverage for
since
andago
. If desired I will happily add a test case.Please let me know if there's anything else I can address. Additionally, if this change isn't desired, please feel free to close it.