我有这个方法#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
谢谢!
答案 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
如果参数的类别不同(String
与File
),那么您可以在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
仅由特别应该可转换为字符串的类实现。