8

私は、Ruby に習熟しようとしている PHP 開発者です。私が現在取り組んでいるプロジェクトの 1 つは、いくつかの Web プログラミング言語で Web アプリケーション ファイルをスキャンして潜在的に危険な機能を探すソース コード監査ツールです。一致が見つかると、スクリプトはpoi後で表示するために関連情報を (関心のあるポイント) クラスに保存します。

そのクラスのインスタンスの例は、次のようになります (YAML でモデル化されています)。

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

展示では、これらの興味深い点を次のように整理したいと思います。

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

poiしたがって、プレゼンテーションの前に、オブジェクトのフラット配列を上記の構造を反映したハッシュに構造化しようとしています。これにより、ハッシュ内のアイテムを単純に反復処理して、目的の画面上の編成を生成できます。(または、少なくとも、それが計画です。)

さて、私の質問ですが、Ruby でそれを行うにはどうすればよいでしょうか?

PHP では、次のようなことを非常に簡単に行うことができます。

<?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でこれを処理する適切な方法は何ですか?

アップデート:

参考までに、これは私が定義した正確な方法です。

# 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

これは、コードを実行したときに受け取るエラーです。

./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

62 行目 (ご想像のとおり) は、特に次の行です。

@points_of_interest.each_with_index do |point, index|

追加の参考として、@points_of_interestYAML に変換したときの (一部の抜粋) を次に示します。

- !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
4

3 に答える 3

32

@John のEnumerable#group_by提案は、ニーズを解決する 1 つの良い方法です。もう1つは、次のように(PHPにあるように)自動有効化ハッシュを作成することです。

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

この種の自動有効化は、存在しないキーにアクセスすると作成されるため、「危険」になる可能性があることに注意してください。

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

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

最初にキーをテストするためにdefault_proc使用する場合は、この危険を冒さずに生き生きと使用できます。key?

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

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

FWIW、あなたが得ているエラーは、「ねえ、あなたは[]に評価されたものを置き、メソッドを持っていません.」nilと言っています。nil[]具体的には、あなたのコード...

sorted_pois[point.file_type.to_sym]

(ハッシュにはこのキーの値がまだないため) に評価されnil、次に要求しようとしました

nil[point.file.to_sym]
于 2012-04-20T20:48:54.497 に答える
8

group_byに興味があるかもしれません。

使用例:

birds = ["Golden Eagle", "Gyrfalcon", "American Robin",
         "Mountain BlueBird", "Mountain-Hawk Eagle"]
grouped_by_first_letter = birds.group_by { |s| s[0] }

# { "G"=>["Golden Eagle", "Gyrfalcon"], "A"=>["American Robin"],
#   "M"=>["Mountain BlueBird", "Mountain-Hawk Eagle"] }
于 2012-04-20T20:43:12.667 に答える
2

上記の例の明らかな問題は、使用しようとしているネストされたハッシュと配列が存在しないことです。これを試して:

sorted_pois = {}
pois.each do |point|
  # sanitize data - convert to hash of symbolized keys and values
  poi = Hash[ %w{file_type file match}.map do |key| 
    [key.to_sym, point.send(key).to_sym]
  end ]

  # create nested hash/array if it doesn't already exist
  sorted_pois[ poi[:file_type] ] ||= {}
  sorted_pois[ poi[:file_type] ][ poi[:file] ] ||= {}
  sorted_pois[ poi[:file_type] ][ poi[:file] ][ poi[:match] ] ||= []

  sorted_pois[ poi[:file_type] ][ poi[:file] ][ poi[:match] ] << point
end
于 2012-04-20T20:42:24.383 に答える