Feature #8499

Importing Hash#slice, Hash#slice!, Hash#except, and Hash#except! from ActiveSupport

Added by Kenta Murata 11 months ago. Updated 3 months ago.

[ruby-core:55330]
Status:Assigned
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:core
Target version:current: 2.2.0

Description

=begin RD
According to my experiences, the following two idioms often appeare in application codes.

(1) (({hash = otherhash.select { |k, | [:key1, :key2, :key3].include? k }}))
(2) (({hash = other
hash.reject { |k, | [:key1, :key2, :key3].include? k }}))

On Rails, they can be written in the following forms by using ActiveSupport's features.

(1) (({hash = otherhash.slice(:key1, :key2, :key3)}))
(2) (({hash = other
hash.except(:key1, :key2, :key3)}))

I think the latter forms are shorter and more readable than the former ones.

So I propose to import the following methods from ActiveSupport:

  • (({Hash#slice}))
  • (({Hash#slice!}))
  • (({Hash#except}))
  • (({Hash#except!})) =end

patch.diff Magnifier - built-in Hash#slice, Hash#slice!, Hash#except, and Hash#except! (4.05 KB) Masaki Matsushita, 07/26/2013 10:58 PM

patch2.diff Magnifier (4.07 KB) Masaki Matsushita, 07/29/2013 12:24 PM

History

#1 Updated by Shota Fukumori 11 months ago

+1

#2 Updated by Zachary Scott 11 months ago

Hello,

On Thu, Jun 6, 2013 at 4:12 PM, mrkn (Kenta Murata) muraken@gmail.com wrote:

On Rails, they can be written in the following forms by using ActiveSupport's features.

(1) (({hash = otherhash.slice(:key1, :key2, :key3)}))
(2) (({hash = other
hash.reject(:key1, :key2, :key3}}))

Do you mean "other_hash.except(...)"? There is already Hash#reject

#3 Updated by Nobuyoshi Nakada 11 months ago

  • Description updated (diff)

#4 Updated by Kenta Murata 11 months ago

zzak (Zachary Scott) wrote:

Hello,

On Thu, Jun 6, 2013 at 4:12 PM, mrkn (Kenta Murata) muraken@gmail.com wrote:

On Rails, they can be written in the following forms by using ActiveSupport's features.

(1) (({hash = otherhash.slice(:key1, :key2, :key3)}))
(2) (({hash = other
hash.reject(:key1, :key2, :key3}}))

Do you mean "other_hash.except(...)"? There is already Hash#reject

Yes, It's my mistake!

How can I edit the issue description?

#5 Updated by Kenta Murata 11 months ago

  • Description updated (diff)

I could fix the description.

#6 Updated by Nobuyoshi Nakada 11 months ago

Or enhance the existing methods?

#7 Updated by Kenta Murata 11 months ago

nobu (Nobuyoshi Nakada) wrote:

Or enhance the existing methods?

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

#8 Updated by Charlie Somerville 11 months ago

+1

#9 Updated by Nobuyoshi Nakada 11 months ago

mrkn (Kenta Murata) wrote:

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

Hash#[] should return the values, not the pairs.

#11 Updated by Ilya Vorontsov 11 months ago

mrkn (Kenta Murata) wrote:

nobu (Nobuyoshi Nakada) wrote:

Or enhance the existing methods?

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

There was a proposal (can't find it) to make indexing by multiple arguments to work as nested hashes so that hsh[:a,:b,:c] works as (hsh[:a] && hsh[:a][:b] && hsh[:a][:b][:c]). Your proposal automatically blocks this proposal.

#12 Updated by Kenta Murata 11 months ago

prijutme4ty (Ilya Vorontsov) wrote:

mrkn (Kenta Murata) wrote:

nobu (Nobuyoshi Nakada) wrote:

Or enhance the existing methods?

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

There was a proposal (can't find it) to make indexing by multiple arguments to work as nested hashes so that hsh[:a,:b,:c] works as (hsh[:a] && hsh[:a][:b] && hsh[:a][:b][:c]). Your proposal automatically blocks this proposal.

My proposal primaliry consists of Hash#slice, Hash#except, and bang versions of them.
Hash#[] is optional.

#13 Updated by Clay Trump 11 months ago

Yay, +1 for slice & except

BTW, makes no sense to me if h[:foo, :bar] returns keys and values in a
hash while h[:foo] returns a value.
--

#14 Updated by Vipul Amler 11 months ago

+1

#15 Updated by Kenta Murata 11 months ago

On Fri, Jun 7, 2013 at 1:50 AM, Zachary Scott zachary@zacharyscott.net wrote:

Please update description if the proposal has changed (ie: Hash#[])

I mentioned Hash#[] as the reply to nobu's comment #6.
It has not changed my proposal.
My proposal only consists of slice, slice!, except, and except!.

--
Kenta Murata
OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062

#16 Updated by Nobuyoshi Nakada 11 months ago

I meant Hash#select and Hash#reject by "the existing methods".

i.e.:

hash = other_hash.select(:key1, :key2, :key3)
hash = other_hash.reject(:key1, :key2, :key3)

But Hash#slice and Hash#except seems fine.

#17 Updated by Masaki Matsushita 9 months ago

How about this implementation?

#18 Updated by Yukihiro Matsumoto 9 months ago

The slice method (Array#slice) retrieve "a slice of elements" from an Array.
Considering that, slice is not a good name for the behavior.

So, I prefer Nobu's idea in comment #16

hash = other_hash.select(:key1, :key2, :key3)
hash = other_hash.reject(:key1, :key2, :key3)

Matz

#19 Updated by Kazuhiro NISHIYAMA 9 months ago

=begin
In attached patch.diff
assert_equal({1=>2, 3=>4}, h.slice!(1, 3))
but ActiveSupport's h.slice!(1, 3) returns {5=>6}.

http://api.rubyonrails.org/classes/Hash.html#method-i-slice-21
=end

#20 Updated by Nobuyoshi Nakada 9 months ago

=begin
I've missed the returned values until I've implemented it actually.

:In ActiveSupport:
* (({Hash#slice!})) keeps the given keys and returns removed key/value pairs.
* (({Hash#except!})) removes the given keys and returns self.

:In this proposal:
* (({Hash#slice!})) removes the given keys and returns removed key/value pairs.
* (({Hash#except!})) is same as ActiveSupport.

:Existing methods:
* (({Hash#select!})) keeps the given (by the block) keys and returns self or nil.
* (({Hash#reject!})) removes the given (by the block) keys and returns self or nil.

I don't think changing the result semantics by if any arguments are given is good idea.
What I've thoutht about (({Hash#slice!})) was (({Hash#extract!})) in ActiveSupport actually.
So what about (({Hash#extract})), (({Hash#except})) and those (({!}))-versions?
=end

#21 Updated by Kenta Murata 9 months ago

=begin
The attached file is not a part of my proposal. It made by Glass_saga. My proposal is the same as ActiveSupport.
=end

#22 Updated by Masaki Matsushita 9 months ago

I'm sorry for my wrong implementation.
patch2.diff makes Hash#slice! and #except! behave the same as ActiveSupport.
However, I think it isn't good idea to import Hash#slice! and #except! from ActiveSupport as it is.

Because:
* They returns self if no changes were made. It is inconsistent with other built-in methods like #select! and #reject!.
* #slice! returns rest of hash, not slice of hash like following. It may be confusing.

hash = {1=>2,3=>4,5=>6}
hash.slice!(1,3) #=> {5,6}
hash #=> {1=>2,3=>4}

#23 Updated by Hiroshi SHIBATA 3 months ago

  • Target version changed from 2.1.0 to current: 2.2.0

Also available in: Atom PDF