Class: Perl::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/perl/engine.rb

Overview

Manages an instance of the Perl interpreter. With #eval method you can execute Perl code and get the result in a Ruby object. Objects are serialized using YAML, both in the Ruby and Perl side.

Constant Summary collapse

PerlFile =
File.join(File.dirname(__FILE__), "engine.pl")

Instance Method Summary collapse

Constructor Details

#initializeEngine

Creates a new instance of the Perl interpreter.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/perl/engine.rb', line 26

def initialize
    writer = IO.pipe
    reader = IO.pipe

    @pid = fork do
        writer[1].close
        reader[0].close
        ENV["ENGINE_READER"] = writer[0].fileno.to_s
        ENV["ENGINE_WRITER"] = reader[1].fileno.to_s

        exec "perl", PerlFile
    end

    reader[1].close
    writer[0].close

    @stdin = reader[0]
    @stdout = writer[1]
end

Instance Method Details

#define_method(method_name, body) ⇒ Object

Defines a method in the Perl interpreter.

You can access to the arguments using the normal Perl syntax:

engine.define_method "add_two_values", "$_[0] + $_[1]"


114
115
116
# File 'lib/perl/engine.rb', line 114

def define_method(method_name, body)
    request "define_method", "name" => method_name.to_s, "body" => body.to_s, :generic_response => true
end

#eval(code) ⇒ Object

Executes the given code in the Perl interpreter. EngineNotRunningError will be raised if the interpreter is stopped.

The result will be returned in a Ruby object, using YAML to transport it. If an error is produced in the Perl interpreter the EngineCodeError exception will be raised, with the error message generated by Perl.



106
107
108
# File 'lib/perl/engine.rb', line 106

def eval(code)
    request :eval, "code" => code, :generic_response => true
end

#invoke_method(method_name, *arguments) ⇒ Object

Invokes a method previously defined by #define_method

Objects are passed to Perl using YAML. Everything that can be understood by YAML in both sides can be used as an argument.



121
122
123
# File 'lib/perl/engine.rb', line 121

def invoke_method(method_name, *arguments)
    request "invoke_method", "name" => method_name.to_s, "arguments" => arguments, :generic_response => true
end

#request(request, options = {}) ⇒ Object

:nodoc:



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/perl/engine.rb', line 71

def request(request, options = {}) # :nodoc:
    raise EngineNotRunningError, "Engine is not running" unless @stdout and @stdin

    generic_response = options.delete(:generic_response)

    data = { "request" => request.to_s }.merge!(options).to_yaml
    @stdout.print([data.length].pack("L") + data)

    data_length = @stdin.read(4).to_s
    raise EngineReadingError, "Can not read data" if data_length.length != 4

    data_length = data_length.unpack("L").first
    data = @stdin.read(data_length)
    raise EngineReadingError, "Can not read data" if data.length != data_length

    response = YAML.load data

    if generic_response
        case response["status"]
        when "ok"
            response["result"]
        when "error"
            raise EngineCodeError, response["error"].chomp
        end
    else
        response
    end
end

#running?Boolean

Check if the Perl interpreter is still alive

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
55
# File 'lib/perl/engine.rb', line 47

def running?
    return false unless @stdin and @stdout

    if IO.select [@stdin], [], [], 0
        return false if @stdin.eof?
    end

    true
end

#stop!Object

Stop the Perl interpreter



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/perl/engine.rb', line 58

def stop!
    return false unless running?

    @stdin.close
    @stdout.close
    @stdin = @stdout = nil

    Process.kill "TERM", @pid
    Process.wait @pid

    true
end