ruby-perl 0.99.15j
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/.autotest +1 -0
- data/.rspec +0 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +49 -0
- data/README.md +123 -0
- data/Rakefile +5 -0
- data/autotest/discover.rb +1 -0
- data/bin/rperl +23 -0
- data/examples/hello.pl +1 -0
- data/examples/hello.rb +9 -0
- data/examples/hello_block.rb +5 -0
- data/examples/hello_here.rb +5 -0
- data/examples/passenger/config.ru +3 -0
- data/examples/passenger/log/.keep +0 -0
- data/examples/passenger/public/.keep +0 -0
- data/examples/passenger/tmp/.keep +0 -0
- data/examples/passenger/webapp.psgi +16 -0
- data/examples/perl.ru +4 -0
- data/examples/webapp.psgi +16 -0
- data/lib/perl.rb +43 -0
- data/lib/perl/common.rb +64 -0
- data/lib/perl/ext/hash.rb +10 -0
- data/lib/perl/ext/object.rb +30 -0
- data/lib/perl/ext/string.rb +10 -0
- data/lib/perl/ffi_lib.rb +65 -0
- data/lib/perl/internal.rb +73 -0
- data/lib/perl/interpreter.rb +89 -0
- data/lib/perl/rack.rb +45 -0
- data/lib/perl/shell.rb +28 -0
- data/lib/perl/stack.rb +99 -0
- data/lib/perl/stack/function.rb +67 -0
- data/lib/perl/value.rb +4 -0
- data/lib/perl/value/array.rb +54 -0
- data/lib/perl/value/hash.rb +73 -0
- data/lib/perl/value/scalar.rb +130 -0
- data/spec/ext/hash_spec.rb +24 -0
- data/spec/ext/object_spec.rb +40 -0
- data/spec/ext/string_spec.rb +37 -0
- data/spec/hash_value_spec.rb +47 -0
- data/spec/interpreter_spec.rb +220 -0
- data/spec/scalar_value_spec.rb +82 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/perl_value_helpers.rb +13 -0
- metadata +109 -0
data/.autotest
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "autotest/bundler"
|
data/.rspec
ADDED
File without changes
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
ZenTest (4.5.0)
|
5
|
+
autotest (4.4.6)
|
6
|
+
ZenTest (>= 4.4.1)
|
7
|
+
daemon_controller (0.2.6)
|
8
|
+
daemons (1.1.0)
|
9
|
+
diff-lcs (1.1.2)
|
10
|
+
eventmachine (0.12.10)
|
11
|
+
fastthread (1.0.7)
|
12
|
+
ffi (1.0.6)
|
13
|
+
rake (>= 0.8.7)
|
14
|
+
file-tail (1.0.5)
|
15
|
+
spruz (>= 0.1.0)
|
16
|
+
passenger (3.0.5)
|
17
|
+
daemon_controller (>= 0.2.5)
|
18
|
+
fastthread (>= 1.0.1)
|
19
|
+
file-tail
|
20
|
+
rack
|
21
|
+
rake (>= 0.8.1)
|
22
|
+
rack (1.2.1)
|
23
|
+
rake (0.8.7)
|
24
|
+
rspec (2.0.1)
|
25
|
+
rspec-core (~> 2.0.1)
|
26
|
+
rspec-expectations (~> 2.0.1)
|
27
|
+
rspec-mocks (~> 2.0.1)
|
28
|
+
rspec-core (2.0.1)
|
29
|
+
rspec-expectations (2.0.1)
|
30
|
+
diff-lcs (>= 1.1.2)
|
31
|
+
rspec-mocks (2.0.1)
|
32
|
+
rspec-core (~> 2.0.1)
|
33
|
+
rspec-expectations (~> 2.0.1)
|
34
|
+
spruz (0.2.5)
|
35
|
+
thin (1.2.8)
|
36
|
+
daemons (>= 1.0.9)
|
37
|
+
eventmachine (>= 0.12.6)
|
38
|
+
rack (>= 1.0.0)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
autotest
|
45
|
+
ffi
|
46
|
+
passenger
|
47
|
+
rack
|
48
|
+
rspec
|
49
|
+
thin
|
data/README.md
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
ruby-perl
|
2
|
+
=========
|
3
|
+
|
4
|
+
Ruby and Perl, sitting in a tree K-I-S-S-I-N-G
|
5
|
+
|
6
|
+
For rubyists:
|
7
|
+
-------------
|
8
|
+
|
9
|
+
ruby-perl lets you evaluate and run Perl code within the same binary, without
|
10
|
+
any heavy-weight forking of sub-processes. Enjoy the compactness, robustness
|
11
|
+
and maintainability of Perl!
|
12
|
+
|
13
|
+
For perlists:
|
14
|
+
-------------
|
15
|
+
|
16
|
+
Run your Perl application over industry-standard, enterprise-grade MRI Ruby,
|
17
|
+
Rack and Passenger!
|
18
|
+
|
19
|
+
Getting started
|
20
|
+
===============
|
21
|
+
|
22
|
+
On the command line
|
23
|
+
-------------------
|
24
|
+
|
25
|
+
Install the gem:
|
26
|
+
|
27
|
+
gem install ruby-perl
|
28
|
+
|
29
|
+
Run a Perl program:
|
30
|
+
|
31
|
+
rperl examples/hello.pl
|
32
|
+
|
33
|
+
Or play around in the Perl interactive shell:
|
34
|
+
|
35
|
+
rperl -de 0
|
36
|
+
|
37
|
+
Web applications
|
38
|
+
----------------
|
39
|
+
|
40
|
+
You can run your Perl webapp with Rack using the provided Rack adapter:
|
41
|
+
|
42
|
+
thin -R examples/perl.ru
|
43
|
+
|
44
|
+
ruby-perl supports [PSGI](http://search.cpan.org/~miyagawa/PSGI-1.03/PSGI.pod)
|
45
|
+
(Perl Web Server Gateway Interface Specification); as such it can run any
|
46
|
+
webapp written in any conforming framework, such as
|
47
|
+
[Mason](http://www.masonhq.com/).
|
48
|
+
|
49
|
+
However, for the time you have to provide your own Rackup file. Luckily a
|
50
|
+
typical Rackup file for ruby-perl is fairly simple (just take a look at
|
51
|
+
[examples/perl.ru](examples/perl.ru) in the repository), and it boils down to:
|
52
|
+
|
53
|
+
run Perl::Rack.new("examples/webapp.psgi")
|
54
|
+
|
55
|
+
ruby-perl has been developed with [Thin](http://code.macournoyer.com/thin/)
|
56
|
+
in mind, but since [Phusion Passenger](http://www.modrails.com/) is 100%
|
57
|
+
compatible with Rack, you can use it too: just stick a config.ru file in your
|
58
|
+
document root (together with the mandatory public/ and tmp/ subdirectories)
|
59
|
+
and you are ready to go. Read The Fine [Passenger Manual](http://www.modrails.com/documentation/Users%20guide%20Apache.html#_deploying_a_rack_based_ruby_application)
|
60
|
+
for more info.
|
61
|
+
|
62
|
+
In your own application: evaluating Perl code
|
63
|
+
---------------------------------------------
|
64
|
+
|
65
|
+
You can embed Perl code directly in your Ruby application in a nice and
|
66
|
+
friendly way:
|
67
|
+
|
68
|
+
require 'perl'
|
69
|
+
|
70
|
+
def foo(arg)
|
71
|
+
Perl.run %Q{$_=#{arg};(1x$_)!~/^1?$|^(11+?)\\1+$/&&print"$_\n"}
|
72
|
+
end
|
73
|
+
|
74
|
+
foo(42)
|
75
|
+
foo(13)
|
76
|
+
|
77
|
+
For additional eye-candy, more styles are supported:
|
78
|
+
|
79
|
+
Perl <<-PERL
|
80
|
+
return 0 if $_[0] =~
|
81
|
+
/(?:[\.\-\_]{2,})|(?:@[\.\-\_])|(?:[\.\-\_]@)|(?:\A\.)/;
|
82
|
+
return 1 if $_[0] =~
|
83
|
+
/^[\w\.\-\_]+\@\[?[\w\.\-\_]+\.(?:[\w\.\-\_]{2,}|[0-9])\]?$/;
|
84
|
+
return 0;
|
85
|
+
PERL
|
86
|
+
|
87
|
+
or:
|
88
|
+
|
89
|
+
Perl do
|
90
|
+
run <<-PERL
|
91
|
+
my @sorted_ips = #sort by ip
|
92
|
+
map substr($_, 4) =>
|
93
|
+
sort map pack('C4' =>
|
94
|
+
split /\./)
|
95
|
+
. $_ => (@unsorted_ips);
|
96
|
+
PERL
|
97
|
+
end
|
98
|
+
|
99
|
+
Embedded Perl however has a some pretty big limitation, the biggest being
|
100
|
+
that you cannot easily pass data from Ruby to Perl and vice-versa, except
|
101
|
+
by string interpolation as shown in the first example.
|
102
|
+
|
103
|
+
In your own application: invoking Perl code
|
104
|
+
-------------------------------------------
|
105
|
+
|
106
|
+
ruby-perl lets you invoke arbitrary Perl code you have loaded or evaluated.
|
107
|
+
In other words, you can implement some functionality in Perl and seamlessly
|
108
|
+
call it from Ruby:
|
109
|
+
|
110
|
+
require 'perl'
|
111
|
+
|
112
|
+
Perl do
|
113
|
+
@func = eval %Q{sub { $arg = shift; print "You said: $arg\n"; };}
|
114
|
+
|
115
|
+
...
|
116
|
+
|
117
|
+
call @func, "42", :scalar
|
118
|
+
end
|
119
|
+
|
120
|
+
In the previous snippet we first define a Perl `sub` and we assign it to
|
121
|
+
the `@func` instance variable; we then call it passing a String. For all
|
122
|
+
intents and purposes, `@func` is now a lambda you can pass around and call,
|
123
|
+
only it's implemented in Perl.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
data/bin/rperl
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
# This allows us to run easily from a git checkout without install.
|
4
|
+
def fallback_load_path(path)
|
5
|
+
retried = false
|
6
|
+
begin
|
7
|
+
yield
|
8
|
+
rescue LoadError
|
9
|
+
unless retried
|
10
|
+
$: << path
|
11
|
+
retried = true
|
12
|
+
retry
|
13
|
+
end
|
14
|
+
raise
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
fallback_load_path(File.join(File.dirname(__FILE__), '..', 'lib')) do
|
19
|
+
require 'perl'
|
20
|
+
require 'perl/shell'
|
21
|
+
end
|
22
|
+
|
23
|
+
Perl::Shell.run
|
data/examples/hello.pl
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
''=~('(?{'.('_/)@^['^'/]@.*{').'"'.('/+<][}}{|'^']^^${;),^').',$/})')
|
data/examples/hello.rb
ADDED
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
my $app = sub {
|
2
|
+
print STDERR "just in app\n";
|
3
|
+
my $env = shift;
|
4
|
+
my @ret;
|
5
|
+
|
6
|
+
print STDERR "\$env = '$env'";
|
7
|
+
while (my ($k, $v) = each %$env) {
|
8
|
+
push(@ret, "<p>key: $k, value: $v.</p>\n");
|
9
|
+
}
|
10
|
+
|
11
|
+
return [
|
12
|
+
'200',
|
13
|
+
[ 'Content-Type' => 'text/plain' ],
|
14
|
+
\@ret, # or IO::Handle-like object
|
15
|
+
];
|
16
|
+
}
|
data/examples/perl.ru
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
my $app = sub {
|
2
|
+
print STDERR "just in app\n";
|
3
|
+
my $env = shift;
|
4
|
+
my @ret;
|
5
|
+
|
6
|
+
print STDERR "\$env = '$env'";
|
7
|
+
while (my ($k, $v) = each %$env) {
|
8
|
+
push(@ret, "<p>key: $k, value: $v.</p>\n");
|
9
|
+
}
|
10
|
+
|
11
|
+
return [
|
12
|
+
'200',
|
13
|
+
[ 'Content-Type' => 'text/plain' ],
|
14
|
+
\@ret, # or IO::Handle-like object
|
15
|
+
];
|
16
|
+
}
|
data/lib/perl.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
require 'perl/ffi_lib'
|
5
|
+
require 'perl/common'
|
6
|
+
require 'perl/interpreter'
|
7
|
+
|
8
|
+
module Perl
|
9
|
+
include Perl::FFILib
|
10
|
+
extend Perl::Common
|
11
|
+
|
12
|
+
@initialized = false
|
13
|
+
@mutex = Mutex.new
|
14
|
+
|
15
|
+
def setup
|
16
|
+
@mutex.synchronize do
|
17
|
+
return if @initialized
|
18
|
+
|
19
|
+
argc, argv = argv_to_ffi
|
20
|
+
|
21
|
+
Perl.Perl_sys_init3(argc, argv, nil)
|
22
|
+
|
23
|
+
at_exit { shutdown }
|
24
|
+
@initialized = true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
module_function :setup
|
28
|
+
|
29
|
+
def shutdown
|
30
|
+
Perl.Perl_sys_term
|
31
|
+
@initialized = false
|
32
|
+
end
|
33
|
+
module_function :shutdown
|
34
|
+
|
35
|
+
def run(args)
|
36
|
+
Interpreter.new.eval(args)
|
37
|
+
end
|
38
|
+
module_function :run
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'perl/ext/hash'
|
42
|
+
require 'perl/ext/object'
|
43
|
+
require 'perl/ext/string'
|
data/lib/perl/common.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Perl
|
2
|
+
module Common
|
3
|
+
PERL_EXIT_EXPECTED = 0x01
|
4
|
+
PERL_EXIT_DESTRUCT_END = 0x02
|
5
|
+
|
6
|
+
def start
|
7
|
+
Perl.setup
|
8
|
+
argc, argv = embedded_argv_to_ffi
|
9
|
+
|
10
|
+
@my_perl = Perl.perl_alloc
|
11
|
+
Perl.perl_construct(@my_perl)
|
12
|
+
|
13
|
+
Perl.curinterp[:Iexit_flags] |= PERL_EXIT_DESTRUCT_END
|
14
|
+
|
15
|
+
Perl.perl_parse(@my_perl, nil, argc, argv, nil)
|
16
|
+
Perl.perl_run(@my_perl)
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
Perl.perl_destruct(@my_perl)
|
21
|
+
Perl.perl_free(@my_perl)
|
22
|
+
|
23
|
+
@my_perl = nil
|
24
|
+
Perl.PL_curinterp = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Returns a C-style tuple of <argc,argv> corresponding to the real
|
29
|
+
# arguments the application was invoked with.
|
30
|
+
#
|
31
|
+
def argv_to_ffi
|
32
|
+
array_to_ffi(ARGV)
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Returns a C-style tuple of <argc,argv> suitable for running an
|
37
|
+
# embedded Perl interpreter.
|
38
|
+
#
|
39
|
+
def embedded_argv_to_ffi
|
40
|
+
array_to_ffi(%w[-e 0])
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
def array_to_ffi(array)
|
45
|
+
strptrs = [].tap do |ptrs|
|
46
|
+
ptrs << FFI::MemoryPointer.from_string("") # XXX
|
47
|
+
array.each do |arg|
|
48
|
+
ptrs << FFI::MemoryPointer.from_string(arg)
|
49
|
+
end
|
50
|
+
ptrs << nil
|
51
|
+
end
|
52
|
+
|
53
|
+
[strptrs.length-1, array_ptr(strptrs)]
|
54
|
+
end
|
55
|
+
|
56
|
+
def array_ptr(list)
|
57
|
+
FFI::MemoryPointer.new(:pointer, list.length).tap do |argv|
|
58
|
+
list.each_with_index do |p, i|
|
59
|
+
argv[i].put_pointer(0, p)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'perl/interpreter'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
#
|
5
|
+
# Evaluate Perl code.
|
6
|
+
#
|
7
|
+
# You can provide the code as a String:
|
8
|
+
#
|
9
|
+
# Perl 'print STDERR "hello world\n"'
|
10
|
+
#
|
11
|
+
# An alternative is to pass a block, which will be evaluated in the context
|
12
|
+
# of a Perl::Interpreter instance. This means all Perl::Interpreter methods
|
13
|
+
# will be available, so you can write:
|
14
|
+
#
|
15
|
+
# Perl do
|
16
|
+
# load 'test.pl'
|
17
|
+
# eval 'sub { ... }'
|
18
|
+
# run 'print "hi there!\n";'
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
def Perl(args = nil, &block)
|
22
|
+
@_perl ||= Perl::Interpreter.new
|
23
|
+
|
24
|
+
if args
|
25
|
+
@_perl.eval(args)
|
26
|
+
else
|
27
|
+
@_perl.instance_eval(&block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|