Сравните содержание, а не результаты процедур - PullRequest
4 голосов
/ 10 декабря 2010

Использование Ruby 1.9.2

Задача
Сравните содержание, а не результаты двух процедур. Я понимаю, что результаты не могут быть проверены из-за проблемы остановки 1009 *, но это нормально; Я все равно не хочу проверять результаты.

Например

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

Это возвращает false, потому что объекты внутри процов не совпадают.

Мой неуклюжий раствор
У меня есть обходное решение, которое вроде как делает то, что я хочу, но на самом деле это не проверяет, что процесс "равен" тому, что я в него положил. В моем конкретном случае формат моих процедур всегда будет логическим тестом для переменных экземпляра, таких как:

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

Я написал метод, который динамически создает классы и создает переменные экземпляра с заданными значениями:

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

Что можно использовать примерно так:

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

.
.
Это все замечательно и замечательно, но я хочу знать, есть ли лучший, более мета-способ сделать это, который на самом деле проверяет содержимое процесса, а не просто работу, которая решает мою конкретную проблему; что-то, что можно использовать для проверки любого процесса.

Я думал, что может быть способ использовать синтаксический анализатор Ruby для сравнения, но я понятия не имею, как. Я исследую это сейчас, но подумал, что попробую посмотреть, делал ли кто-нибудь здесь это раньше и знает ли как. Это может быть тупик, хотя из-за динамической природы Ruby, но это то, что я сейчас смотрю.

Ответы [ 2 ]

4 голосов
/ 20 декабря 2010

Если вы используете Ruby 1.9, вы можете использовать камень sourcify.

$ 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" 

Мы также столкнулись с проблемой ParseTree / Ruby 1.9 в моей компании.

2 голосов
/ 10 декабря 2010
$ 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
...