如何存储和读取RubyVM :: InstructionSequence?

时间:2015-05-31 20:25:21

标签: ruby yarv

有没有办法将RubyVM :: InstructionSequence存储到文件中并在以后读取?

我试了Marshal.dump但没有成功。我得到以下错误:

`dump': no _dump_data is defined for class RubyVM::InstructionSequence (TypeError)

3 个答案:

答案 0 :(得分:12)

是的,有办法。

首先,您需要InstructionSequence的{​​{1}}方法,默认情况下已停用:

require 'fiddle'

class RubyVM::InstructionSequence
  # Retrieve Ruby Core's C-ext `iseq_load' function address
  load_fn_addr  = Fiddle::Handle::DEFAULT['rb_iseq_load']
  # Retrieve `iseq_load' C function representation
  load_fn       = Fiddle::Function.new(load_fn_addr,
                                       [Fiddle::TYPE_VOIDP] * 3,
                                       Fiddle::TYPE_VOIDP)

  # Make `iseq_load' accessible as `load' class method
  define_singleton_method(:load) do |data, parent = nil, opt = nil|
    load_fn.call(Fiddle.dlwrap(data), parent, opt).to_value
  end
end

因为RubyVM::InstructionSequence.load方法可以将编译的VM指令作为数组加载,所以您可以自由地将其用于(反)序列化目的:

irb> # compile simple ruby program into its instruction sequence
irb> seq = RubyVM::InstructionSequence.new <<-EOS
irb:   p 'Hello, world !'
irb:   EOS
=> <RubyVM::InstructionSequence:<compiled>@<compiled>

irb> # serialize sequence as Array instance representation
irb> data = Marshal.dump seq.to_a
=> "\x04\b[\x13\"-YARVInstructionSequence/SimpleDataFormat … ]"

irb> # de-serialize previously serialized sequence
irb> seq_loaded = Marshal.load data
=> ["YARVInstructionSequence/SimpleDataFormat", 2, 2, 1, { … ]

irb> # load deserialized Array back into instruction sequence
irb> new_iseq = RubyVM::InstructionSequence.load seq_loaded
=> <RubyVM::InstructionSequence:<compiled>@<compiled>>

irb> # execute instruction sequence in current context
irb> new_iseq.eval
"Hello, world !"
=> "Hello, world !"

那是所有人;)

答案 1 :(得分:2)

鉴于课程方法有限,您可以尝试的课程有限。可能你唯一能做的就是将它的实例保存为字符串:

result = MYSQL.query('SELECT cache_amount_with_discount_and_tax FROM t_payment WHERE organization_id = 1 AND receipt_id = '+param['receipt_id'].to_s).data_seek(3).fetch_hash

// where MYSQL is the original MYSQL client

结果:

puts RubyVM::InstructionSequence.disasm(proc{puts "foo"})

当你想反序列化它时,你需要解析这个字符串。

答案 2 :(得分:0)

这很简单。

iseq = RubyVM::InstructionSequence.compile("a = 1 + 2") # just an example
File.open('iseq.bin', 'wb') { |file| file.write iseq.to_binary }

# later
RubyVM::InstructionSequence.load_from_binary(File.read('iseq.bin')).eval # returns 3