Skip to content

add implementation of respond_to? for ActiveSupport::Duration#16574

Merged
jeremy merged 1 commit intorails:masterfrom
lsylvester:duration-respond_to
Sep 15, 2014
Merged

add implementation of respond_to? for ActiveSupport::Duration#16574
jeremy merged 1 commit intorails:masterfrom
lsylvester:duration-respond_to

Conversation

@lsylvester
Copy link
Contributor

In rails 4.2.beta, calling respond_to? on a ActiveSupport::Duration no longer returns true for the methods defined in ActiveSupport::Duration. ie

10.seconds.respond_to?(:since) #=> false 

This is because the since, ago and similar methods were removed from Numeric.

This adds a custom respond_to? method to currently return if the duration responds to these methods.

@lsylvester lsylvester force-pushed the duration-respond_to branch from 299f668 to 428a569 Compare August 20, 2014 07:08
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this just be super || @value.respond_to?(method, include_private)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because Duration is a subclass of ProxyObject it doesn't have a respond_to? method in its superclass, so calling super goes straight to method_missing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>> class O < BasicObject; HAX = ::Object.method(:respond_to?).unbind.bind(self); def respond_to?(*args) HAX.call(*args) end end
=> :respond_to?
>> O.new.respond_to? :a
=> false

Reimplementing Ruby's respond_to? + respond_to_missing? protocol will lead to breakage down the line.

Is there a better way?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeremy I think implementation of respond_to? returns true based on if the class has the methods defined instead of the the instance.

I don't think that it is possible to bind a method to a ProxyObject from Object as I get an error when I try to do so.

Object.instance_method(:respond_to?).bind(BasicObject.new)
 #=> bind argument must be an instance of Object (TypeError)

Maybe Duration should be a subclass of Object so it can get the correct respond_to? behaviour for free.

The only issue identified by the tests when Durations superclass is changed to Object is that it can now be duplicated, which can be fixed by defining duplicable? and undefining dup.

Do you know any reasons why Durations superclass shouldn't be changed to Object.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lsylvester See the code snippet above 😁 You have to #unbind the Method first, then #bind the UnboundMethod to the class.

Agree that Duration should simply be an Object. It's not really a transparent proxy anymore.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #11794 for another case where being an Object would help. We don't have hash-equality with #eql? currently.

@Envek
Copy link
Contributor

Envek commented Sep 12, 2014

Need it strongly in release of 4.2. Thanks!

@chancancode
Copy link
Member

cc @pixeltrix @robin850 @jeremy can one of you take a look 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refute

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, we prefer assert_not

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then let use assert_not_respond_to

@pixeltrix
Copy link
Contributor

Isn't this really a problem with the ProxyObject class? Shouldn't the fix be there (whatever it is)?

@lsylvester
Copy link
Contributor Author

I have changed this to make Duration a subclass of Object, so that it gets the correct respond_to? behaviour without having to reimplement it.

I have made it non duplicatable, not sure if this is required or it should be removed or deprecated.

Also, ProxyObject does not seem to be used anymore. Should it be deprecated?

@jeremy
Copy link
Member

jeremy commented Sep 15, 2014

Nice @lsylvester - that feels a lot better! The object is duplicable, so that bit can go.

ProxyObject is public API - other libraries use it 😁

@lsylvester lsylvester force-pushed the duration-respond_to branch 2 times, most recently from b2b17da to 32f3115 Compare September 15, 2014 02:05
@lsylvester
Copy link
Contributor Author

The duplicatable bit is gone.

jeremy added a commit that referenced this pull request Sep 15, 2014
add implementation of respond_to? for ActiveSupport::Duration
@jeremy jeremy merged commit c0a4a30 into rails:master Sep 15, 2014
@jeremy
Copy link
Member

jeremy commented Sep 15, 2014

Thank you @lsylvester !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants