forked from spatten/ruby_koans
-
Notifications
You must be signed in to change notification settings - Fork 684
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from Wolwer1nE/pattern_matching
Added pattern matching koans
- Loading branch information
Showing
2 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
require File.expand_path(File.dirname(__FILE__) + '/neo') | ||
|
||
class AboutPatternMatching < Neo::Koan | ||
|
||
def test_pattern_may_not_match | ||
begin | ||
case [true, false] | ||
in [a, b] if a == b # The condition after pattern is called guard. | ||
:match | ||
end | ||
rescue Exception => ex | ||
# What exception has been caught? | ||
assert_equal __, ex.class | ||
end | ||
end | ||
|
||
def test_we_can_use_else | ||
result = case [true, false] | ||
in [a, b] if a == b | ||
:match | ||
else | ||
:no_match | ||
end | ||
|
||
assert_equal __, result | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
|
||
def value_pattern(variable) | ||
case variable | ||
in 0 | ||
:match_exact_value | ||
in 1..10 | ||
:match_in_range | ||
in Integer | ||
:match_with_class | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_value_pattern | ||
assert_equal __, value_pattern(0) | ||
assert_equal __, value_pattern(5) | ||
assert_equal __, value_pattern(100) | ||
assert_equal __, value_pattern('Not a Number!') | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
# This pattern will bind variable to the value | ||
|
||
def variable_pattern_with_binding(variable) | ||
case 0 | ||
in variable | ||
variable | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_variable_pattern_with_binding | ||
assert_equal __, variable_pattern_with_binding(1) | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
|
||
# We can pin the value of the variable with ^ | ||
|
||
def variable_pattern_with_pin(variable) | ||
case 0 | ||
in ^variable | ||
variable | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_variable_pattern_with_pin | ||
assert_equal __, variable_pattern_with_pin(1) | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
|
||
# We can drop values from pattern | ||
|
||
def pattern_with_dropping(variable) | ||
case variable | ||
in [_, 2] | ||
:match | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_pattern_with_dropping | ||
assert_equal __, pattern_with_dropping(['I will not be checked', 2]) | ||
assert_equal __, pattern_with_dropping(['I will not be checked', 'But I will!']) | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
|
||
# We can use logical *or* in patterns | ||
|
||
def alternative_pattern(variable) | ||
case variable | ||
in 0 | false | nil | ||
:match | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_alternative_pattern | ||
assert_equal __, alternative_pattern(0) | ||
assert_equal __, alternative_pattern(false) | ||
assert_equal __, alternative_pattern(nil) | ||
assert_equal __, alternative_pattern(4) | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
|
||
# As pattern binds the variable to the value if pattern matches | ||
# pat: pat => var | ||
|
||
def as_pattern | ||
a = 'First I was afraid' | ||
|
||
case 'I was petrified' | ||
in String => a | ||
a | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_as_pattern | ||
assert_equal __, as_pattern | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
|
||
# Array pattern works with all objects that have #deconstruct method that returns Array | ||
# It is useful to cut needed parts from Array-ish objects | ||
|
||
class Deconstructible | ||
def initialize(str) | ||
@data = str | ||
end | ||
|
||
def deconstruct | ||
@data&.split('') | ||
end | ||
end | ||
|
||
def array_pattern(deconstructible) | ||
case deconstructible | ||
in 'a', *res, 'd' | ||
res | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_array_pattern | ||
assert_equal __, array_pattern(Deconstructible.new('abcd')) | ||
assert_equal __, array_pattern(Deconstructible.new('123')) | ||
end | ||
|
||
# ------------------------------------------------------------------ | ||
|
||
# Hash pattern is quite the same as Array pattern, but it expects #deconsturct_keys(keys) method | ||
# It works with symbol keys for now | ||
|
||
class LetterAccountant | ||
def initialize(str) | ||
@data = str | ||
end | ||
|
||
def deconstruct_keys(keys) | ||
# we will count number of occurrences of each key in our data | ||
keys.map { |key| [key, @data.count(key.to_s)] }.to_h | ||
end | ||
end | ||
|
||
def hash_pattern(deconstructible_as_hash) | ||
case deconstructible_as_hash | ||
in {a: a, b: b} | ||
[a, b] | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_hash_pattern | ||
assert_equal __, hash_pattern(LetterAccountant.new('aaabbc')) | ||
assert_equal __, hash_pattern(LetterAccountant.new('xyz')) | ||
end | ||
|
||
# we can write it even shorter | ||
def hash_pattern_with_sugar(deconstructible_as_hash) | ||
case deconstructible_as_hash | ||
in a:, b: | ||
[a, b] | ||
else | ||
:no_match | ||
end | ||
end | ||
|
||
def test_hash_pattern_with_sugar | ||
assert_equal __, hash_pattern_with_sugar(LetterAccountant.new('aaabbc')) | ||
assert_equal __, hash_pattern_with_sugar(LetterAccountant.new('xyz')) | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters