From: Brian Candler Date: 2009-08-18T19:53:17+09:00 Subject: Re: How can I extract variables from a ruby snippet Laran Evans wrote: > So, using the snippet above, I would learn that there is: > > - a "post" variable which is a hash, expected to have the keys > "category_id", "title", "body", "extended_body" and "private". > - a "notify" variable which is an array (indicated by the fact that > it's iterated over with the .each) of simple values (i.e. it's not a > multi-dimensional array, or an array of hashes) You can't tell that - lots of objects implement an 'each' iterator, and there isn't really such thing as a 'simple value' in Ruby anyway. The number 1 and the Array [1] are both first-class Objects. e.g. >> h = {1=>"one", 2=>"two"} => {1=>"one", 2=>"two"} >> h.each { |elem| p elem } [1, "one"] [2, "two"] The full solution to what you want is probably to compile the ERB template into Ruby, and then compile the Ruby into an sexp (e.g. using ParseTree or ripper), and then analyse the sexp. This is quite a lot of work. Otherwise, you could execute the template using erb, and use method_missing to pick up attempts to access local variables. From these return a dummy object, which again uses method_missing to see what methods have been called on that dummy object. If the method_missing passes a block then you will need to yield the block with dummy arguments. This may be good enough for what you need, but isn't guaranteed to catch all possible execution paths. e.g. what about <% if foo %> <%= foo.xxx %> <% else %> <%= bar.yyy %> <% end %> ? You are going to find it hard to exercise both branches of this conditional. Similarly with loops, where the nth iteration may behave differently to the previous ones. Rails approaches the problem differently: whenever you render a template you pass in a hash of 'local_assigns', and it compiles the template assuming that these are the variables which will be substituted. It then makes a method signature using this set of variables. If the template is rendered again and 'local_assigns' contains a different set of variables to substitute, then it is recompiled. The assumption is that normally the template will be rendered multiple times using the same set of local_assigns variables (just with different values, of course) See actionpack/lib/action_view/renderable.rb -- Posted via http://www.ruby-forum.com/.