0

我在模型中编写了一个函数来抓取站点并将某些属性存储在单独的模型中(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 变量的urlanchorrange属性。range 属性存储为数组范围 - 即0..211..13- 但是,我被告知它不能将字符串转换为变量。我试过存储range为整数和字符串,但都失败了。

我意识到我可以在我的数据库中输入范围的开头和结尾作为两个单独的整数,然后放["#{beginrange}".."#{endrange}"],但这似乎是一种混乱的方式。

还有其他想法吗?提前谢谢了

4

2 回答 2

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毫无风险地使用。

于 2012-11-22T18:10:33.780 回答
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)]
于 2012-11-22T18:37:40.847 回答