5

Using Ruby 1.9.2

Problem
Compare the content, not the results, of two procs. I understand the results can't be tested because of the halting problem but that's OK; I don't want to test the results anyway.

For instance

proc {@x == "x"} == proc {@x == "x"}  => false # doh!

That returns false because the objects inside the procs are not the same.

My clunky solution
I have a work around solution that kinda sorta does what I want but it doesn't really test that the proc is "equal" to what I put in it. In my specific case the format of my procs will always be boolean tests on instance variables like this:

{@x == "x" && @y != "y" || @z == String} 

I wrote a method that builds classes dynamically and creates instance variables set to specified values:

def create_proc_tester(property_value_hash)
  new_class = Class.new.new

  new_class.class.class_eval do
     define_method(:xql?) { |&block| instance_eval &block }
  end

  property_value_hash.each do |key, value| 
    new_class.instance_variable_set("@#{key}", value)
  end

  new_class
end

Which could be used something like this:

class Foo
  attr_accessor :block
end

foo = Foo.new
foo.block = proc {@x == "x" && @y != "y" || @z == String}

tester = create_proc_tester(:x => "x", :y => "y", :z => Fixnum)
puts "Test #1: #{tester.xql? &foo.block}"
tester = create_proc_tester(:x => "x", :y => "x", :z => String)
puts "Test #2: #{tester.xql? &foo.block}"

> Test #1: false
> Test #2: true

.
.
That's all great and wonderful but I want to know if there is a better, more meta, way to do this that actually tests the contents of the proc not just a work around that solves my specific problem; something that could be used to test any proc.

I was thinking there might be a way to use the Ruby parser to get something to compare but I have no idea how. I'm researching it now but thought I'd try to see if anyone here has done this before and knows how. That might be a dead-end though because of the dynamic nature of Ruby but that's where I'm looking now.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
  • I'm not sure how this could be done meaningfully. For example, are equivalent single- and double-quoted strings different content? The same text but created in different methods? Tabs vs. spaces? There are so many things that don't make a difference to the meaning but cause the literal text to change and things that don't make a difference to the text but cause the meaning to change. What is content? – Chuck Dec 10 '10 at 00:35
  • I agree it's an odd problem and I don't really need to solve it anymore but I'm curious. Single and double quoted strings are definitely different though. A double quoted string will be escaped and a single quoted one will not. For instance puts "#{variable}" prints out the variable value while puts '#{variable}' prints out the literal string #{variable}. –  Dec 10 '10 at 00:50
  • @Greg, the fact that it is a question is implied otherwise it would not be on this site. Note that most questions on this site are not phrased in the form of a question as it would be redundant. Also the first word of a sentence and most words (nouns, pronouns, adjectives, verbs, adverbs, and subordinating conjunctions) in the titles of articles are capitalized. Thanks for the effort though. –  Dec 10 '10 at 06:41
  • @Mike Bethany, Both [Style guide for questions and answers](http://meta.stackexchange.com/q/18614/153968) and [Should question titles be phrased as questions? (A straw poll)](http://meta.stackexchange.com/q/19999/153968) recommend the "title" be phrased as a question, and in sentence-case. Proper nouns and abbreviations should be capitalized of course, but the titles are conversational sentences, not book or article titles. – the Tin Man Dec 10 '10 at 09:17
  • 1
    @Greg Those are posts by users not actual guidelines set by the site. By citing them you are making the logical fallacy argumentum ad populum, the argument from popularity, without even proving that these are in fact the popular opinions; just because most people believe something does not make it true. Looking at the "questions" post I see there is heated debate on both sides of the argument but the actual meat of the question presented isn't whether it's in the form of the question but the clarity of the question. Content based edits help, miscorrecting grammar to personal preferences don't. –  Dec 10 '10 at 16:44
  • @Mike You might be interested in this [stack-exchange proposal](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2 "code review"). It's almost ready to begin beta, just needs a few more. – greatwolf Jan 18 '11 at 09:38

2 Answers2

4

If you're using Ruby 1.9, you may be able to use the sourcify gem.

$ irb
> require 'sourcify'
=> true 
> a = proc {@x == "x"}
=> #<Proc:0x9ba4240@(irb):2> 
> b = proc {@x == %{x}}
=> #<Proc:0x9ba23f0@(irb):3> 
> a == b
=> false 
> a.to_source == b.to_source
=> true 
> RUBY_VERSION
=> "1.9.2" 

We also ran into the ParseTree/Ruby 1.9 incompatibility problem at my company.

Seamus Abshere
  • 8,326
  • 4
  • 44
  • 61
3
$ sudo gem install ruby2ruby ParseTree

require 'parse_tree'
require 'ruby2ruby'
require 'parse_tree_extensions'

# All of these are the same:
proc     { puts 'a'  }.to_ruby  # => "proc { puts(\"a\") }"
lambda   { puts "a"  }.to_ruby  # => "proc { puts(\"a\") }"
Proc.new { puts %{a} }.to_ruby  # => "proc { puts(\"a\") }"

# If you need to do this with classes:

class Bar; define_method(:foo) { 'a' }; end  

puts Ruby2Ruby.new.process(Unifier.new.process(ParseTree.translate(Bar)))

# will print this:
# class Bar < Object
#   def foo
#     "a"
#   end
# end
glebm
  • 20,282
  • 8
  • 51
  • 67
  • +1 for the effort. I should have said I'm using Ruby 1.9.2. Parse_Tree doesn't work with 1.9. –  Dec 10 '10 at 03:03
  • 1
    uh, then you'll need to write a c extension. since the AST is kept in memory for all procs it should be relatively easy. – glebm Dec 10 '10 at 05:52
  • "... it should be relatively easy." Not according to the guy that wrote Parse_Tree. I quote, "Because of changes to internals in 1.9, ParseTree simply can not work. I asked for hooks/options to allow us to get to the information but they never arrived. Specifically if you're using ParseTree to access the AST of a live method/block/proc, you're SOL." –  Dec 10 '10 at 06:48