在Ruby中动态创建多维哈希 [英] Dynamically creating a multi-dimensional hash in Ruby

查看:98
本文介绍了在Ruby中动态创建多维哈希的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一名试图掌握Ruby技能的PHP开发人员。我现在正在削减我的一个项目是一个源代码审计工具,它可以扫描webapp文件,查找几种网络编程语言中潜在的危险功能。当找到匹配项时,脚本会将相关信息保存在 poi (兴趣点)类中以供稍后显示。



该类的示例实例看起来像这样(在YAML中建模):

pre $ $ $ $ $ $ $ $ $ b file_type:php
file:the-scanned-file.php
line_number:100
match:eval()
snippet:echo eval )

在展示中,我想组织这些兴趣点如下所示:

   -  file_type 
- 文件
---匹配(搜索到的有效内容)
poi
对象成一个哈希镜像上面的结构。这将允许我简单地遍历散列中的项目以产生期望的屏幕上组织。 (或者至少,这是计划。)



现在,对于我的问题:我该如何在Ruby中执行此操作?



在PHP中,我可以很轻松地做这样的事情:
$ b

 < ?php 

$ sorted_pois = array();
foreach($ points_of_interest as $ point){
$ sorted_pois [$ point-> file_type] [$ point-> file] [$ point-> match] [] = $ point;
}

?>

我尝试将这种想法从PHP转换为Ruby,但是无济于事:

  sorted_pois = {} 
@ points_of_interest.each_with_index do | point,index |
sorted_pois [point.file_type.to_sym] [point.file.to_sym] [point.match.to_sym] .push point
end

我已经在这上面花了几个小时了,在这一点上我的头撞到了墙上,所以大概我是离开了基地。在Ruby中处理这个问题的正确方法是什么?



更新:
$ b

引用,这是我定义的精确方法:

$ pre $ #将感兴趣的点排序为结构化散列
def sort
sorted_pois = {}
@ points_of_interest.each_with_index do | point,index |
sorted_pois [point.file_type.to_sym] [point.file.to_sym] [point.match.to_sym] .push point
end
end



这是我运行代码时收到的错误:

  ./ lib / models / vulnscanner.rb:63:在`sort'中:未定义的方法`[]'为nil:NilClass(NoMethodError)
from /usr/lib/ruby/1.8/rubygems/ custom_require.rb:31:在`each_with_index'
from ./lib/models/vulnscanner.rb:62:in`each'
from ./lib/models/vulnscanner.rb:62:in` each_with_index'
from ./lib/models/vulnscanner.rb:62:in`sort'
from ./webapp-vulnscan:69

第62行(正如你可能推断的)特别是这一行:

  @points_of_interest.each_with_index do | point,index | 

作为附加参考,以下是 @points_of_interest 看起来像转换为YAML时:

   - !ruby / object:PoI 
file: models / couponkimoffer.php
file_type:php
group::dangerous_functions
line_number:472
match:`
snippet:ORDER BY`created_at` DESC
- !ruby / object:PoI
file:models / couponkimoffer.php
file_type:php
group::dangerous_functions
line_number:818
match: `
snippet:WHERE`company_slug` ='$ company_slug'
- !ruby / object:PoI
file:models / couponkimoffer.php
file_type:php
group ::dangerous_functions
line_number:819
match:`
snippet:ORDER BY`created_at` DESC


解决方案

@ John's Enumerable#group_by 建议是解决您的需求的好方法。另一种方法是创建一个自动生成哈希(就像你看起来在PHP中一样):
$ b

  hash = Hash。新{| h,k | h [k] = Hash.new(& h.default_proc)} 
hash [:a] [:b] [:c] = 42
$ hash
#=> {:a => {:b => {:c => 42}}}

请注意,如果您访问不存在的按键,这种自动生成功能可能会危险,因为它会为您创建它们:

  p hash [这是否存在?] 
#=> {}

p hash
#=> {:a => {:b => {:c => 42}},这是否存在?=> {}}

如果您使用键,您仍然可以使用生动的 default_proc code>首先测试键:

  val = hash [OH NOES] if hash.key? (OH NOES)
#=>无

p散列
#=> {:a => {:b => {:c => 42}},这是否存在?=> {}}






FWIW,你得到的错误说,嘿,你把 [] 之后,评估为 nil nil 没有<$ c $

  sorted_pois   [point.file_type.to_sym] 

评估为(因为哈希值没有这个键的值),然后你试图请求

$ pre code> nil [point .file.to_sym]


I'm a PHP developer who's trying to gain some proficiency in Ruby. One of the projects I'm cutting my teeth on now is a source-code auditing tool that scans webapp files for potentially dangerous functions in several web programming languages. When matches are found, the script saves the relevant information in a poi (point-of-interest) class for display later on.

An example instance of that class would look something like this (modeled in YAML):

poi:
    file_type: "php"
    file: "the-scanned-file.php"
    line_number: 100
    match: "eval()"
    snippet: "echo eval()"

On display, I want to organize these points of interest like so:

- file_type
-- file
--- match (the searched payload)

Thus, before presentation, I'm trying to structure a flat array of poi objects into a hash mirroring the structure above. This will allow me to simply iterate over the items in the hash to produce the desired on-screen organization. (Or at least, that's the plan.)

And now, for my question: how do I do that in Ruby?

In PHP, I could do something like this really easily:

<?php

$sorted_pois = array();
foreach($points_of_interest as $point){
    $sorted_pois[$point->file_type][$point->file][$point->match][] = $point;
}

?>

I've tried translating that thought from PHP to Ruby like this, but to no avail:

sorted_pois = {}
@points_of_interest.each_with_index do |point, index|
    sorted_pois[point.file_type.to_sym][point.file.to_sym][point.match.to_sym].push point
end

I've spent a few hours on this, and I'm kind of banging my head against the wall at this point, so presumably I'm way off-base. What's the proper way to handle this in Ruby?

Update:

For reference, this is the precise method I have defined:

# sort the points of interest into a structured hash
def sort
  sorted_pois = {}
  @points_of_interest.each_with_index do |point, index|
    sorted_pois[point.file_type.to_sym][point.file.to_sym][point.match.to_sym].push point
  end
end

This is the error I receive when I run the code:

./lib/models/vulnscanner.rb:63:in `sort': undefined method `[]' for nil:NilClass (NoMethodError)
    from /usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `each_with_index'
    from ./lib/models/vulnscanner.rb:62:in `each'
    from ./lib/models/vulnscanner.rb:62:in `each_with_index'
    from ./lib/models/vulnscanner.rb:62:in `sort'
    from ./webapp-vulnscan:69

Line 62 (as you can likely infer) is this line in particular:

@points_of_interest.each_with_index do |point, index|

As an additional reference, here's what (a snippet of) @points_of_interest looks like when converted to YAML:

- !ruby/object:PoI 
  file: models/couponkimoffer.php
  file_type: php
  group: :dangerous_functions
  line_number: "472"
  match: `
  snippet: ORDER BY `created_at` DESC
- !ruby/object:PoI 
  file: models/couponkimoffer.php
  file_type: php
  group: :dangerous_functions
  line_number: "818"
  match: `
  snippet: WHERE `company_slug` = '$company_slug'
- !ruby/object:PoI 
  file: models/couponkimoffer.php
  file_type: php
  group: :dangerous_functions
  line_number: "819"
  match: `
  snippet: ORDER BY `created_at` DESC

解决方案

@John's Enumerable#group_by suggestion is one good way to solve your needs. Another would be to create an auto-vivifying Hash (like you appear to have in PHP) like so:

hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
hash[:a][:b][:c] = 42
p hash
#=> {:a=>{:b=>{:c=>42}}}

Note that this sort of auto-vivification can be 'dangerous' if you access keys that don't exist, as it creates them for you:

p hash["does this exist?"]
#=> {}

p hash
#=> {:a=>{:b=>{:c=>42}}, "does this exist?"=>{}}

You can still use the vivifying default_proc without hitting this danger if you use key? to test for the key first:

val = hash["OH NOES"] if hash.key?("OH NOES")
#=> nil

p hash
#=> {:a=>{:b=>{:c=>42}}, "does this exist?"=>{}}


FWIW, the error you are getting says, "Hey, you put [] after something that evaluated to nil, and nil doesn't have a [] method." Specifically, your code...

sorted_pois[point.file_type.to_sym]

evaluated to nil (because the hash did not yet have a value for this key) and then you attempted to ask for

nil[point.file.to_sym]

这篇关于在Ruby中动态创建多维哈希的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆