2011-05-23 32 views
3

想象一下下面的代码:有没有比使用自定义的case语句更有用的方法来在Ruby中编写它?

class SimpleLetter 
    def values 
    ("a" .. "z").to_a 
    end 

    def ===(other) 
    values.include?(other) 
    end 
end 

class Vowel < SimpleLetter 
    def values 
    ["a","e","i","o","u"] 
    end 
end 

class Consonant < SimpleLetter 
    def values 
    super - Vowel.new.values 
    end 
end 

objects = ("a" .. "f").to_a + (1 .. 5).to_a 

objects.each do |letter| 
    case letter 
    when Vowel.new 
     puts "#{letter} it's a vowel" 
    when Consonant.new 
     puts "#{letter} it's a consonant" 
    else 
     puts "#{letter} it's something else" 
    end 
end 

我可以选择任何其他类,而不是,我只是用它们作为一个例子。我非常喜欢Scala的match和提取器,我认为这可能是在Ruby中编写相同的东西的一种很好的方式。有没有更好的方式来写上述,而不必实例化新的对象,所以我可以调用他们的===方法?

只是为了避免不必要的岗位,是的,我知道我能做到这一点:

case letter 
    when ["a","e","i","o","u"].include?(letter) 
    # ... 
end 

回答

3

你可以使用类方法而不是实例方法:

class SimpleLetter 
    def self.values 
     ("a" .. "z").to_a 
    end 

    def self.===(other) 
     values.include?(other) 
    end 
end 

class Vowel < SimpleLetter 
    def self.values 
     ["a","e","i","o","u"] 
    end 
end 

class Consonant < SimpleLetter 
    def self.values 
     super - Vowel.values 
    end 
end 

objects = ("a" .. "f").to_a + (1 .. 5).to_a 

objects.each do |letter| 

    case letter 
     when Vowel 
      puts "#{letter} it's a vowel" 
     when Consonant 
      puts "#{letter} it's a consonant" 
     else 
      puts "#{letter} it's something else" 
    end 

end 
+0

使用类方法看起来比我更好的变种很多。我不知道我们可以定义'==='来处理类作用域。 – Geo 2011-05-23 20:04:43

5

你不需要上课那些角色。将它们设置为数组,并在case语句中使用splat运算符。

SimpleLetter = ("a" .. "z").to_a 
Vowel  = %w[a e i o u] 
Consonant = SimpleLetter - Vowel 

(("a" .. "f").to_a + (1 .. 5).to_a).each do |letter| 
    case letter 
    when *Vowel 
     puts "#{letter} it's a vowel" 
    when *Consonant 
     puts "#{letter} it's a consonant" 
    else 
     puts "#{letter} it's something else" 
    end 
end 
4

===作品上的块,太:

Letters = ('a'..'z').to_a 
Vowels = ['a','e','i','o','u'] 
Consonants = Letters - Vowels 

Vowel = lambda { |x| Vowels.include? x } 
Consonant = lambda { |x| Consonants.include? x } 

objects = ("a" .. "f").to_a + (1 .. 5).to_a 

objects.each do |object| 
    case object 
    when Vowel 
     puts "#{object} is a vowel." 
    when Consonant 
     puts "#{object} is a consonant." 
    else 
     puts "#{object} is an object." 
    end 
end 
+0

可以使用任何具有'.call'方法的对象吗? – Geo 2011-05-23 20:10:41

+0

实际上,规则是任何具有'。==='的对象都与'case'语句兼容。 – Tom 2011-05-23 20:12:02

+0

在Ruby 1.8中无法使用 – 2011-05-23 20:44:48

1

你已经有几个很好的答案(如泽的),所以我包括一个玩票一个没有case声明:

SIMPLE_LETTER = [*"a" .. "z"] 
VOWEL  = %w[a e i o u] 
CONSONANT = SIMPLE_LETTER - VOWEL 

[*?a..?f,*1..5].each do |letter| 
    letter_class = %w(vowel consonant).select { |c| Object.const_get(c.upcase).include? letter}.first 
    puts "'#{letter}': #{ letter_class || "something else"}" 
end 

输出:

'a': vowel 
'b': consonant 
'c': consonant 
'd': consonant 
'e': vowel 
'f': consonant 
'1': something else 
'2': something else 
'3': something else 
'4': something else 
'5': something else 

多图示和字符文字只能在1.9中使用。

+0

您对splat运算符的使用比我的更加密集和更好。 – sawa 2011-05-24 00:24:55

2

你让我困惑的代码,因为SimpleLetter应该是单个字母,而不是整个字母表。

我会都特别想做到以下几点,尽管是的monkeypatching一个有点冒险:

module Voweliness 
    def vowel? 
    self =~ /[aeiou]/i 
    end 

    def consonant? 
    (self =~ /[a-z]/i and not vowel?) 
    end 
end 

class String 
    include Voweliness 
end 


objects.each do |letter| 
    case 
    when letter.vowel? 
     puts "#{letter} is a vowel" 
    when letter.consonant? 
     puts "#{letter} is a consonant" 
    else 
     puts "#{letter} is something else" 
    end 
end 
相关问题