[ruby-core:88359] [Ruby trunk Feature#14869] Proposal to add Hash#===

From: manga.osyo@...
Date: 2018-08-09 02:09:03 UTC
List: ruby-core #88359
Issue #14869 has been updated by osyo (manga osyo).

File hash_eqq.patch added

> Much like the suggestion in the Array topic, would it be a good idea to leverage to_hash? In Ruby this means that an object behaves like a hash, allowing us duck-typing and more flexibility.

Support call `to_hash`.

```ruby
o = Object.new
def o.to_hash
  { name: "homu", age: 14 }
end
{ name: /^h/ } === o
# => true
```

----------------------------------------
Feature #14869: Proposal to add Hash#===
https://bugs.ruby-lang.org/issues/14869#change-73388

* Author: osyo (manga osyo)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
## ๆฆ‚่ฆ

`Hash#===` ใ‚’่ฟฝๅŠ ใ™ใ‚‹ๆๆกˆใซใชใ‚Šใพใ™ใ€‚


## ไป•ๆง˜

ใƒฌใ‚ทใƒผใƒใฎใ‚ญใƒผใฎ่ฆ็ด ใจๅผ•ๆ•ฐใฎใƒใƒƒใ‚ทใƒฅใฎใ‚ญใƒผใฎ่ฆ็ด ใ‚’ `#===` ใงๆฏ”่ผƒใ—ใฆใ€ๅ…จใฆใŒ็œŸใชใ‚‰ `true` ใ‚’่ฟ”ใ—ใ€ใใ†ใงใชใ„ใชใ‚‰ `false` ใ‚’่ฟ”ใ™ใ€‚
ใพใŸใ€ใƒฌใ‚ทใƒผใƒใŒ็ฉบใฎใƒใƒƒใ‚ทใƒฅใฎๅ ดๅˆใ€ๅผ•ๆ•ฐใŒ็ฉบใฎใƒใƒƒใ‚ทใƒฅใชใ‚‰ `true` ใ‚’่ฟ”ใ—ใ€ใใ†ใงใชใ„ใชใ‚‰ `false` ใ‚’่ฟ”ใ™ใ€‚

```ruby
user = { id: 1, name: "homu", age: 14 }

# name ่ฆ็ด ใŒ data ใซใ‚ใ‚‹ใฎใง true
p ({ name: "homu" } === user)
# => true

# ่ค‡ๆ•ฐใฎ่ฆ็ด ใŒใ‚ใฃใฆใ‚‚ OK
p ({ id: 1, name: "homu", age: 14 } === user)
# => true

# name ่ฆ็ด ใŒ user ใซใ‚ใ‚‹ใŒใ€ๅ€คใŒ้•ใ†ใฎใง false
p ({ name: "name" } === user)
# => false

# ใ‚ญใƒผใฎ่ฆ็ด ใŒๅผ•ๆ•ฐใซใชใ„ใฎใง false
p ({ number: 42 } === user)
# => false

# 1ใคใงใ‚‚ใ‚ญใƒผใฎ่ฆ็ด ใŒใชใ„ๅ ดๅˆใ‚‚ false
p ({ id: 1, name: "homu", number: 42 } === user)
# => false

# ใƒฌใ‚ทใƒผใƒใŒ็ฉบใฎใƒใƒƒใ‚ทใƒฅใชใ‚‰ false
p ({} == user)
# => false

# ็ฉบใฎใƒใƒƒใ‚ทใƒฅๅŒๅฃซใชใ‚‰ true
p ({} == {})
# => true

# ๅผ•ๆ•ฐใŒใƒใƒƒใ‚ทใƒฅไปฅๅค–ใชใ‚‰ false
p ({ id: 42 } == 42)
# => false

# #=== ใงๆฏ”่ผƒใ—ใฆใ„ใ‚‹ใฎใงใ“ใ†ใ„ใ†ใ“ใจใ‚‚ใงใใ‚‹
p ({ name: /^h/ } === user)
# => true

p ({ age: (1..20) } === user)
# => true

p ({ age: Integer } === user)
# => true
```


## ใƒฆใƒผใ‚นใ‚ฑใƒผใ‚น

### ใƒใƒชใƒ‡ใƒผใ‚ทใƒงใƒณ

case-when ใงใฏ `===` ใ‚’ไฝฟ็”จใ—ใฆๅ€คใ‚’ๆฏ”่ผƒใ—ใฆใ„ใ‚‹ใฎใงใ€`Hash#===` ใ‚’ๅˆฉ็”จใ™ใ‚‹ใ“ใจใงๆฌกใฎใ‚ˆใ†ใซๆกไปถๅˆ†ๅฒใ‚’่กŒใ†ใ“ใจใŒๅ‡บๆฅใ‚‹ใ€‚

```ruby
def validation user
	case user
	# name ใซๅฏพใ™ใ‚‹ใƒใƒชใƒ‡ใƒผใ‚ทใƒงใƒณ
	when { name: /^[a-z]/ }
		raise "ๅๅ‰ใฎๅ…ˆ้ ญใŒๅฐๆ–‡ๅญ—ใฎๅ ดๅˆใฏ็™ป้Œฒใงใใพใ›ใ‚“"
	# age ใซๅฏพใ™ใ‚‹ใƒใƒชใƒ‡ใƒผใ‚ทใƒงใƒณ
	when { age: (0..20) }
		raise "0ใ€œ20ๆญณใฏ็™ป้Œฒใงใใพใ›ใ‚“"
	# ๅ„่ฆ็ด ใŒไปปๆ„ใฎใ‚ฏใƒฉใ‚นใฎใ‚คใƒณใ‚นใ‚ฟใƒณใ‚นใ‹ใฉใ†ใ‹ใฎใƒใƒชใƒ‡ใƒผใ‚ทใƒงใƒณ
	when { id: Integer, name: String, age: Integer }
		true
	else
		false
	end
end

# ๆกไปถใ‚’ๆบ€ใŸใ—ใฆใ„ใ‚‹ใฎใง OK
mami = { id: 1, name: "Mami", age: 21 }
validation mami
# => true

# name ใŒๅฐๆ–‡ๅญ—ใ‹ใ‚‰ๅง‹ใพใฃใฆใ„ใ‚‹ใฎใง NG
mado = { id: 2, name: "mado", age: 13 }
validation mado
# => ๅๅ‰ใฎๅ…ˆ้ ญใŒๅฐๆ–‡ๅญ—ใฎๅ ดๅˆใฏ็™ป้Œฒใงใใพใ›ใ‚“ (RuntimeError)

# age ใŒ 0ใ€œ20ๆญณไปฅๅ†…ใชใฎใง NG
homu = { id: 3, name: "Homu", age: 14 }
validation homu
# => 0ใ€œ20ๆญณใฏ็™ป้Œฒใงใใพใ›ใ‚“ (RuntimeError)
```

### `Enumerable#grep`

`Enumerable#grep` ใฏๅ†…้ƒจใง `===` ใ‚’ไฝฟ็”จใ—ใŸๆฏ”่ผƒใ‚’่กŒใฃใฆใ„ใ‚‹ใฎใงใ€ๆฌกใฎใ‚ˆใ†ใซไปปๆ„ใฎ Hash ใฎใ‚ญใƒผใฎ่ฆ็ด ใซๅฏพใ—ใฆๆคœ็ดขใ‚’่กŒใ†ใ“ใจใŒๅ‡บๆฅใ‚‹ใ€‚

```ruby
data = [
	{ id: 1, name: "Homu", age: 13 },
	{ id: 2, name: "mami", age: 14 },
	{ id: 3, name: "Mado", age: 21 },
	{ id: 4, name: "saya", age: 14 },
]

# ็‰นๅฎšใฎ่ฆ็ด ใŒๅซใพใ‚Œใฆใ„ใ‚‹ Hash ใฎใฟใ‚’็ตžใ‚Š่พผใ‚€
p data.grep(name: /m/)
# => [{:id=>1, :name=>"Homu", :age=>13}, {:id=>2, :name=>"mami", :age=>14}]

p data.grep(age: (1..20))
# => [{:id=>1, :name=>"Homu", :age=>13}, {:id=>2, :name=>"mami", :age=>14}, {:id=>4, :name=>"saya", :age=>14}]
```


## ่ฃœ่ถณ1๏ผš `==` ใงใฏใชใใฆ `===` ใงๆฏ”่ผƒใ™ใ‚‹็†็”ฑ

* `===` ใ‚’ไฝฟ็”จใ™ใ‚‹ใ“ใจใงใ‚ˆใ‚Š็ดฐใ‹ใ„ใƒปๆŠฝ่ฑก็š„ใชๆกไปถใ‚’ๆŒ‡ๅฎšใ™ใ‚‹ใ“ใจใŒๅ‡บๆฅใ‚‹
  * `Class` ใ‚„ `Regexp`ใ€`Proc` ใชใฉใงๆฏ”่ผƒใ™ใ‚‹ใ“ใจใŒๅ‡บๆฅใ‚‹
* ๅ†…้ƒจใง `===` ใ‚’ไฝฟ็”จใ—ใฆใ„ใ‚‹ๅ ดๅˆใ€ `==` ใงๆฏ”่ผƒใ—ใŸใ„ๅ ดๅˆใฏ `obj.method(:==)` ใ‚’ๆธกใ›ใฐๅฎŸ็พๅ‡บๆฅใ‚‹ใŒใ€ใใฎ้€†ใฏๅ‡บๆฅใชใ„
  * ๅ†…้ƒจใง `==` ใ‚’ไฝฟ็”จใ—ใฆใ„ใ‚‹ๅ ดๅˆใ€ `===` ใงๆฏ”่ผƒใ—ใ—ใŸใใฆใ‚‚ๅ‡บๆฅใชใ„


## ่ฃœ่ถณ2๏ผš ็ฉบใฎใƒใƒƒใ‚ทใƒฅใฎๆฏ”่ผƒใซ้–ขใ—ใฆ

* `Object#===` ใฎๅ ดๅˆใ ใจ `{} === 42` ใŒไพ‹ๅค–ใงใฏใชใใฆ `false` ใ‚’่ฟ”ใ—ใฆใ„ใŸใฎใงใ€`Hash#===` ใ‚‚ `false` ใ‚’่ฟ”ใ™ใ‚ˆใ†ใซใ—ใŸ
  * `{} === {}` ใŒ `true` ใ‚’่ฟ”ใ™ใฎใ‚‚ๅŒๆง˜ใฎ็†็”ฑใซใชใ‚Šใพใ™
  * ใ“ใ‚Œใซใ‚ˆใ‚Šไปฅไธ‹ใฎใ‚ˆใ†ใชๆ—ขๅญ˜ใฎใ‚ณใƒผใƒ‰ใ‚‚ไบ’ๆ›ๆ€งใ‚’ๅฃŠใ™ใ“ใจใชใๅ‹•ไฝœใ™ใ‚‹ใ‹ใจๆ€ใ„ใพใ™

```ruby
def check n
	case n
	when {}
		"Empty Hash"
	when []
		"Empty Array"
	when 0
		"Zero"
	else
		"Not empty"
	end
end

p check({})   # => "Empty Hash"
p check([])   # => "Empty Array"
p check(0)    # => "Zero"
p check({ name: "mado" })   # => "Not empty"
```

ไปฅไธŠใ€`Hash#===` ใซ้–ขใ™ใ‚‹ๆๆกˆใซใชใ‚Šใพใ™ใ€‚
ๆŒ™ๅ‹•ใซ้–ขใ—ใฆ็–‘ๅ•็‚นใ‚„ๆ„่ฆ‹ใชใฉใ”ใ–ใ„ใพใ—ใŸใ‚‰ใ‚ณใƒกใƒณใƒˆ้ ‚ใ‘ใ‚‹ใจๅŠฉใ‹ใ‚Šใพใ™ใ€‚


---Files--------------------------------
hash_eqq.patch (3.54 KB)
hash_eqq.patch (4.43 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread

Prev Next