ruby如何有两个可选参数但需要至少一个存在?

时间:2011-05-10 08:24:24

标签: ruby

我有这个方法#upload,除了其他参数之外,它基本上包含文件选项或一些文本。如果传递了一个文件(File.open(“test.txt”,'r +')),则上传(: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

谢谢!

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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,但这是一团糟。然而,请注意它们的意义在很大程度上取决于它所预测的对象的类型:取决于它是否是液体,数量,话语等,同时确定适当的“添加”感。多态的概念使用了这个事实,并将其应用于编程。在这种情况下,“upload”将具有不同的含义,具体取决于它是关于字符串还是文件。但只要它们在各自的类别中定义,您在使用它们时就不必关心它们之间的区别。因此,您将从case语句中解脱出来,并使代码更简单。

答案 2 :(得分: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

与其他两个相似,但我觉得有一些改进

  • 鸭子类型而不是基于类的基础行为,这意味着只要他们实现正确的方法,就可以使用其他类。主要是这允许除普通文件之外的其他形式的IO。可以通过子类型来完成,但这不是Ruby中的要求。

  • 使用to_str代替to_s,每个班级都有一个to_s方法,我假设你不想上传像#<MyClass:0x523e>这样的内容。另一方面,to_str仅由特别应该可转换为字符串的类实现。