title: Dynamically creating a multi-dimensional hash in Ruby
body: <p>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 <code>poi</code> (point-of-interest) class for display later on.</p>
  
  <p>An example instance of that class would look something like this (modeled in YAML):</p>
  
  <pre><code>poi:
      file_type: "php"
      file: "the-scanned-file.php"
      line_number: 100
      match: "eval()"
      snippet: "echo eval()"
  </code></pre>
  
  <p>On display, I want to organize these points of interest like so:</p>
  
  <pre><code>- file_type
  -- file
  --- match (the searched payload)
  </code></pre>
  
  <p>Thus, before presentation, I'm trying to structure a flat array of <code>poi</code> 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.)</p>
  
  <p>And now, for my question: how do I do that in Ruby?</p>
  
  <p>In PHP, I could do something like this really easily:</p>
  
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  
  $sorted_pois = array();
  foreach($points_of_interest as $point){
      $sorted_pois[$point-&gt;file_type][$point-&gt;file][$point-&gt;match][] = $point;
  }
  
  ?&gt;
  </code></pre>
  
  <p>I've tried translating that thought from PHP to Ruby like this, but to no avail:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>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?</p>
  
  <p><strong>Update:</strong></p>
  
  <p>For reference, this is the precise method I have defined:</p>
  
  <pre><code># 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
  </code></pre>
  
  <p>This is the error I receive when I run the code:</p>
  
  <pre><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
  </code></pre>
  
  <p>Line 62 (as you can likely infer) is this line in particular:</p>
  
  <pre><code>@points_of_interest.each_with_index do |point, index|
  </code></pre>
  
  <p>As an additional reference, here's what (a snippet of) <code>@points_of_interest</code> looks like when converted to YAML:</p>
  
  <pre><code>- !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
  </code></pre>