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 seek to hash for deep pluck of key #11165
Conversation
I'm not sure how common this is, and I'm not sure that a recursive implementation is the best idea. I feel like we have rejected this feature before. |
I run into this whenever I work with json data - there's always some degree of null-checking involved. I'm fine not doing a recursive implementation for this, but I'd be curious as to why you'd feel like it's better to handle it iteratively. |
I definitely ran into this situation and built small helper function to accomplish it. I would be interested in the thoughts of @fxn @rafaelfranca and @carlosantoniodasilva |
I've needed this before but it didn't bother me that much to the point of adding it to core, so I'm not sure it should be there. No strong opinion. Thanks. |
@@ -0,0 +1,9 @@ | |||
class Hash |
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 needs to require try
.
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've removed the dependency on .try in the new iterative implementation.
I made some comments anyway, it'd also need a changelog entry in case it goes in (but you can do that later if it's a yes). Thanks. |
I'd imagine many, if not most, Rails developers would sooner or later run into the need to extract a nested hash item. It's quite annoying to have to check for nil at each step of the way. I think it's reasonable to support this - either on the hash level, or as a special case on the singleton class of the I'm not sure Iterative vs recursive - iterative is usually a little bit faster and less memory intensive, so for a low-level helper function that may be run in an inner loop-scenario, it's probably better. Iterative tends to be a little bit less intuitive to read and maintain, but again, a very simple low-level helper function wouldn't be changed that often and wouldn't have many gotchas requiring understanding of its innerworkings, so most users wouldn't care about implementation any more than they care about implementation of the C-based MRI standard library. |
I changed this to an iterative implementation, added a changelog entry, and cleaned up the tests according to @carlosantoniodasilva 's comments. Thanks for the feedback Carlos. Anyone feel like merging this? |
Oh, and @egilburg , I don't like naming it deep_fetch, since fetch allows the optional block to provide a default value. I can add another method to the pull request implementing deep_fetch with those semantics though. |
@@ -0,0 +1,7 @@ | |||
class Hash | |||
def seek(*args) |
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 to have API documentation similar to the other Hash and other core_ext docs.
Why not improve existing implementation to allow for default block similar to how fetch does it? You can combine varargs with block, The only reason I see NOT to do this is due to different variation - Update - nevermind, I realized that |
@egilburg I think it is a good idea to add an optional block to define the default value though, I've added that functionality. |
I'm 👎 for this one. I don't see this as a common pattern, and you can already do with params.try(:[], :user).try(:[], :groups).try(:[], :groups_id) Also, in my opinion, this is a smell. |
Agree with @rafaelfranca. You can also do this with >> params = { :user => { :groups => { :group_id => 10 } } }
=> {:user=>{:groups=>{:group_id=>10}}}
>> [:user, :groups, :group_id].inject(params) { |hash, val| hash[val] ? hash[val] : break }
=> 10
>> You can even do it without writing any conditionals: >> params = { }
=> {}
>> [:user, :groups].inject(params) { |hash, val| hash.fetch(val, {}) }[:group_id]
=> nil
>> params = { :user => { :groups => { :group_id => 10 } } }
=> {:user=>{:groups=>{:group_id=>10}}}
>> [:user, :groups].inject(params) { |hash, val| hash.fetch(val, {}) }[:group_id]
=> 10
>> |
Thank you for the contribution. ❤️ We try to not add new things to Active Support core extensions if they are not really needed. |
The pattern of:
... really sucks. Add a method that allows easy plucking from within a hash: