我在模型中编写了一个函数来刮取网站并将某些属性存储在单独的模型中(story
):
def get_content
request = HTTParty.get("#{url}")
doc = Nokogiri::HTML(request.body)
doc.css("#{anchor}")["#{range}"].each do |entry|
story = self.stories.new
story.title = entry.text
story.url = entry[:href]
story.save
end
这使用了Sections变量的url
,anchor
和range
属性。 range属性存储为数组范围 - 即0..2
或11..13
- 然而,我被告知它无法将字符串转换为变量。我已经尝试将range
存储为整数和字符串,但都失败了。
我意识到我可以在我的数据库中输入范围的开头和结尾作为两个单独的整数,并放置["#{beginrange}".."#{endrange}"]
但这似乎是一种混乱的方式。
还有其他想法吗?非常感谢提前
答案 0 :(得分:1)
如果您确定range
始终是“1..2
”(“<Integer >..<Integer>
”)之类的字符串,则可以使用eval
方法:
在我的IRB控制台中:
1.9.3p0 :032 > (eval "1..2").each { |l| puts l }
1
2
=> 1..2
1.9.3p0 :033 > (eval "1..2").inspect
=> "1..2"
1.9.3p0 :034 > (eval "1..2").class
=> Range
在您的情况下:
doc.css("#{anchor}")[eval(range)].each do |entry|
#...
end
但eval
有点危险。如果您确定range
属性是一个范围作为字符串(验证和正则表达式可以提供帮助),您可以使用eval
而无风险。
答案 1 :(得分:0)
我看错了几件事。
["#{beginrange}".."#{endrange}"]
创建一系列字符,而不是Array[]
所需的整数范围:
beginrange = 1
endrange = 2
["#{beginrange}".."#{endrange}"]
=> ["1".."2"]
[beginrange..endrange]
=> [1..2]
但是,您将所需的数组范围的表示形式存储为字符串。如果我有一个范围的字符串表示,我会使用它:
range_value = '1..2'
[Range.new(*range_value.scan(/\d+/).map(&:to_i))]
=> [1..2]
或者,如果有机会我会遇到一个专属范围:
[Range.new(*range_value.scan(/\d+/).map(&:to_i), range_value['...'])]
=> [1..2]
range_value = '1...2'
[Range.new(*range_value.scan(/\d+/).map(&:to_i), range_value['...'])]
=> [1...2]
当你不能信任Range字符串表示的来源时,这些都是好的,即,值来自其他人创建的表单或文件。如果您拥有传入的值,或者为方便起见,将其作为字符串存储在数据库中,您可以使用eval
轻松地重新创建范围:
eval('1..2').class
=> Range
eval('1..2')
=> 1..2
eval('1...2')
=> 1...2
人们害怕eval
,因为不明智地使用它是危险的。这并不意味着我们应该避免使用它,相反,我们应该在它安全时使用它。
您可以使用正则表达式检查字符串的格式,如果不接受则引发异常,然后继续:
raise "Invalid range value received" if (!range_value[/\A\d+\s*\.{2,3}\s*\d+\z/])
[eval(range_value)]