rbpl 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+
2
+ task :test do
3
+ require 'rake/runtest'
4
+ $LOAD_PATH << "lib"
5
+ require 'perl'
6
+ Rake.run_tests 'tests/test_*.rb'
7
+ end
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/perl
2
+
3
+ use strict;
4
+ use YAML::Syck;
5
+
6
+ $| =1; # autoflush
7
+
8
+ our $data;
9
+ our $data_length;
10
+ our %SESSION;
11
+ our %_USER_METHODS;
12
+
13
+ sub eval_and_respond {
14
+ my ($block) = @_;
15
+ my $result = &$block();
16
+
17
+ my $packed_result = Dump($@ ?
18
+ { status => "error", error => $@ } :
19
+ { status => "ok", result => $result });
20
+ print pack("L", length($packed_result)).$packed_result;
21
+ $result;
22
+ }
23
+
24
+ while(1) {
25
+
26
+ exit 0 if eof(STDIN); # Wait for data or exit if the parent closes the pipe
27
+
28
+ read(STDIN, $data_length, 4) == 4 or die "Can not read \$data_length from stdin";
29
+ $data_length = unpack("L", $data_length);
30
+
31
+ read(STDIN, $data, $data_length) == $data_length or die "Can not read \$data from stdin";
32
+ $data = Load($data);
33
+
34
+ if($data->{request} eq "eval") {
35
+ eval_and_respond(sub { eval($data->{code}); });
36
+ } elsif($data->{request} eq "define_method") {
37
+ eval_and_respond(sub {
38
+ $_USER_METHODS{$data->{method_name}} = eval("sub { ".$data->{body}." }");
39
+ });
40
+ } elsif($data->{request} eq "invoke_method") {
41
+ eval_and_respond(sub {
42
+ my $arguments = $data->{arguments};
43
+ $_USER_METHODS{$data->{method_name}}(@$arguments);
44
+ });
45
+ }
46
+ }
@@ -0,0 +1,129 @@
1
+
2
+ require 'open3'
3
+ require 'yaml'
4
+
5
+ class Perl
6
+
7
+ # Base for every exception raised by Perl::Engine
8
+ class EngineError < Exception; end
9
+
10
+ # Raised when a request is to be sent but the engine is stopped
11
+ class EngineNotRunningError < EngineError; end
12
+
13
+ # Raised when a request has been sent but an error ocurred when the response is read
14
+ class EngineReadingError < EngineError; end
15
+
16
+ # Raised when an evaluated code has errors
17
+ class EngineCodeError < EngineError; end
18
+
19
+ # Manages an instance of the Perl interpreter. With #eval method you can execute Perl code and get the result in a Ruby object.
20
+ # Objects are serialized using YAML, both in the Ruby and Perl side.
21
+ class Engine
22
+
23
+ PerlFile = File.join(File.dirname(__FILE__), "engine.pl")
24
+
25
+ # Creates a new instance of the Perl interpreter.
26
+ def initialize
27
+ writer = IO.pipe
28
+ reader = IO.pipe
29
+
30
+ @pid = fork do
31
+ writer[1].close
32
+ STDIN.reopen(writer[0])
33
+ writer[0].close
34
+
35
+ reader[0].close
36
+ STDOUT.reopen(reader[1])
37
+ reader[1].close
38
+
39
+ exec "perl", PerlFile
40
+ end
41
+
42
+ reader[1].close
43
+ writer[0].close
44
+
45
+ @stdin = reader[0]
46
+ @stdout = writer[1]
47
+ end
48
+
49
+ # Check if the Perl interpreter is still alive
50
+ def running?
51
+ return false unless @stdin and @stdout
52
+
53
+ if IO.select [@stdin], [], [], 0
54
+ return false if @stdin.eof?
55
+ end
56
+
57
+ true
58
+ end
59
+
60
+ # Stop the Perl interpreter
61
+ def stop!
62
+ return false unless running?
63
+
64
+ @stdin.close
65
+ @stdout.close
66
+ @stdin = @stdout = nil
67
+
68
+ Process.kill "TERM", @pid
69
+ Process.wait @pid
70
+
71
+ true
72
+ end
73
+
74
+ def request(request, options = {}) # :nodoc:
75
+ raise EngineNotRunningError, "Engine is not running" unless @stdout and @stdin
76
+
77
+ generic_response = options.delete(:generic_response)
78
+
79
+ data = { "request" => request.to_s }.merge!(options).to_yaml
80
+ @stdout.print([data.length].pack("L") + data)
81
+
82
+ data_length = @stdin.read(4).to_s
83
+ raise EngineReadingError, "Can not read data" if data_length.length != 4
84
+
85
+ data_length = data_length.unpack("L").first
86
+ data = @stdin.read(data_length)
87
+ raise EngineReadingError, "Can not read data" if data.length != data_length
88
+
89
+ response = YAML.load data
90
+
91
+ if generic_response
92
+ case response["status"]
93
+ when "ok"
94
+ response["result"]
95
+ when "error"
96
+ raise EngineCodeError, response["error"].chomp
97
+ end
98
+ else
99
+ response
100
+ end
101
+ end
102
+
103
+ # Executes the given code in the Perl interpreter.
104
+ # EngineNotRunningError will be raised if the interpreter is stopped.
105
+ #
106
+ # The result will be returned in a Ruby object, using YAML to transport
107
+ # it. If an error is produced in the Perl interpreter the EngineCodeError
108
+ # exception will be raised, with the error message generated by Perl.
109
+ def eval(code)
110
+ request :eval, "code" => code, :generic_response => true
111
+ end
112
+
113
+ # Defines a method in the Perl interpreter.
114
+ #
115
+ # You can access to the arguments using the normal Perl syntax:
116
+ # engine.define_method "add_two_values", "$_[0] + $_[1]"
117
+ def define_method(method_name, body)
118
+ request "define_method", "name" => method_name.to_s, "body" => body.to_s, :generic_response => true
119
+ end
120
+
121
+ # Invokes a method previously defined by #define_method
122
+ #
123
+ # Objects are passed to Perl using YAML. Everything that can be understood by YAML in both sides can be used as an argument.
124
+ def invoke_method(method_name, *arguments)
125
+ request "invoke_method", "name" => method_name.to_s, "arguments" => arguments, :generic_response => true
126
+ end
127
+ end
128
+ end
129
+
data/lib/perl.rb ADDED
@@ -0,0 +1,2 @@
1
+
2
+ require 'perl/engine'
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rbpl
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Ayose Cazorla
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-06-13 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Loads a Perl interpreter and evaluates inside it code generated in the Ruby side
17
+ email: setepo@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/perl/engine.pl
26
+ - lib/perl/engine.rb
27
+ - lib/perl.rb
28
+ - Rakefile
29
+ has_rdoc: true
30
+ homepage: http://github.com/setepo/rbpl
31
+ licenses: []
32
+
33
+ post_install_message:
34
+ rdoc_options: []
35
+
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: "0"
43
+ version:
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ requirements: []
51
+
52
+ rubyforge_project:
53
+ rubygems_version: 1.3.5
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: Execute Perl code from a Ruby script
57
+ test_files: []
58
+