2011-05-10 21 views
2

我有这个方法,#upload,基本上包括文件选项或一些文本等参数。如果传递了一个文件(File.open(“test.txt”,'r +')),upload(:file => ...),那么这个方法从文件读取文本,或者如果有人决定通过那个非常相同的文本只是不在txt文件中,他可以做上传(:content => ...)红宝石如何有两个可选的参数,但至少需要一个礼物?

但我需要一个文本或文本本身通过的文件,你会如何处理?

这是我到目前为止。

def upload(args) 
    if args[:content].present? 
    self.content = args[:content] 
    elsif args[:file].present? 
    self.content = args[:file].read 
    end 
end 

谢谢!

+1

你能澄清你的示例代码有什么问题吗?它究竟如何不适合你? – Laas 2011-05-10 10:23:56

+0

我只是想知道这是否是最好的方法。它确实有效 – 2011-05-13 19:26:07

回答

2

解决方案1 ​​

如果类的说法是不同的(StringFile),那么你可以使用在case建设。你不需要进一步的信息来区分。

def upload(arg) 
    self.content = 
    case arg 
    when String; arg 
    when File; arg.read 
    end 
end 

解决方案2

添加的启发后评论由Nemo157

使用面向对象编程的多态性,你可以这样做:

def upload(arg); self.content = arg.upload end 
class String 
    def upload; self end 
end 
class File 
    def upload; read end 
end 

一些关于多态性的注释

通常,我们在同一个词语中指的是相似但不同的动作。例如,在日常生活的背景下,考虑单词add:我们在不同的意义上使用它:给罐子加水,加3比1,添加评论,为绿色涂料添加蓝色阴影,等等。他们有不同的含义,但我们有直觉,他们有某种相关性。区分这些含义的一种方法是使用不同的单词,如液体添加,数字添加,上下文添加,或者可以将它们编号为add1,add2,add3,但这是一团糟。但是,请注意,它们的含义在很大程度上取决于它所预测的对象的类型:取决于它是否是液体,数量,话语等,在确定时确定“添加”的适当含义。多态的想法使用这个事实,并将其应用于编程。在这种情况下,“上传”根据其是关于字符串还是文件而具有不同的含义。但只要它们在各自的课堂中定义,您在使用它们时就不必关心它们之间的差异。因此,您可以从case语句中解脱出来,并使代码更简单。

+0

你应该(几乎)从不使用类来开启,它完全毁了鸭子打字。一个更好的版本会首先检查'to_str'方法来判断它是否是某种形式的字符串,然后检查'read'是否是某种IO。 – Nemo157 2011-05-12 07:52:43

+0

@ Nemo157在您的评论之后启发,我添加了另一种利用多态性的解决方案。我不确定这是否是你的意思。 – sawa 2011-05-12 08:09:40

+0

谢谢Sawa提供了两种解决方案,您是否会善意地抛出一两行来解释为什么这是一种好的做法?一般来说,我对编程还比较陌生。我立即去阅读维基百科有关面向对象多态性的文章,但不能走得太远。或者也许你有一些我可以检查的其他文章的建议。更多类型的noobs?谢谢。 – 2011-05-13 19:38:17

0

只是让它在方法的测试,像

def upload(args) 
    if args[:content].present? 
    self.content = args[:content] 
    elsif args[:file].present? 
    self.content = args[:file].read 
    else 
    raise ArgumentError, 'one of :content or :file must be given' 
    end 
end 

编辑:替代方案,只使用一个参数和鸭打字

def upload(arg) 
    if arg.respond_to? :to_str 
    self.content = arg.to_str 
    elsif arg.respond_to? :read 
    self.content = arg.read 
    else 
    raise ArgumentError, 'a String-like or IO-like object must be given' 
    end 
end 

类似于其它两个,而是什么我觉得是一些改进

  • 鸭 - 而不是基于行为on这个类,这意味着只要他们实施正确的方法,其他类就可以使用。主要是这允许除了普通文件以外的其他形式的IO。可以通过子类型来完成,但这在Ruby中并不是那么重要。

  • 使用to_str代替to_s,每个类都有一个to_s方法,我假设你不想上传内容,如#<MyClass:0x523e>。另一方面,to_str只能由专门应该转换为字符串的类实现。

+0

所以我的方法也被普遍接受为解决方案,对吧?基本上我正在寻找konw。 – 2011-05-13 19:39:22

+0

你的方法很好,Ruby是一种足够好的语言,只要它可读性就足够好。把它整合到一个参数中的主要优点是它减少了认知负担,方法的用户不必记住他们是否应该写'upload(content:my_string)'或'upload(file:my_file)'(使用新的1.9.2哈希语法)。我已经添加了我可能会用一个参数和我的推理来做到这一点。 – Nemo157 2011-05-14 13:23:18

2

你是否特意要将参数作为散列来传递?如果没有,我会去这样的事情:

def upload(args) 
    if args.respond_to? :read 
    self.content = args.read 
    else 
    self.content = args.to_s # This allows non-string arguments. 
    end 
end 
+0

我喜欢在散列中传递参数,对编程仍然比较新,但是如果有超过2个参数传递给方法,我会发现更多的参数,因为我可以看到传递给方法的东西,例如,:content =>“你好”。但肯定的是,你的解决方案工作 – 2011-05-13 19:32:36