Compare the Content, Not the Results, of Procs

人盡茶涼 提交于 2019-12-01 05:22:51

问题


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.


回答1:


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.




回答2:


$ 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


来源:https://stackoverflow.com/questions/4404362/compare-the-content-not-the-results-of-procs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!