ruby-perl 0.99.15j

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1 @@
1
+ require "autotest/bundler"
data/.rspec ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source :rubygems
2
+
3
+ gem 'ffi'
4
+
5
+ group :development do
6
+ gem 'autotest'
7
+ gem 'passenger'
8
+ gem 'rack'
9
+ gem 'rspec'
10
+ gem 'thin'
11
+ end
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,5 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
@@ -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
@@ -0,0 +1,9 @@
1
+ require 'perl'
2
+
3
+ # you can run a Perl program from a string...
4
+ Perl.run "print 'hello world!\n'"
5
+
6
+ # or better yet, a here-document
7
+ Perl <<-PERL
8
+ ''=~('(?{'.('_/)@^['^'/]@.*{').'"'.('/+<][}}{|'^']^^${;),^').',$/})')
9
+ PERL
@@ -0,0 +1,5 @@
1
+ require 'perl'
2
+
3
+ Perl do
4
+ run "print 'hello world!\n'"
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'perl'
2
+
3
+ Perl <<-PERL
4
+ print 'hello world!\n'
5
+ PERL
@@ -0,0 +1,3 @@
1
+ require 'perl/rack'
2
+
3
+ run Perl::Rack.new("webapp.psgi")
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,4 @@
1
+ $: << 'lib'
2
+ require 'perl/rack'
3
+
4
+ run Perl::Rack.new("examples/webapp.psgi")
@@ -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'
@@ -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,10 @@
1
+ require 'perl/value/hash'
2
+
3
+ class Hash
4
+ #
5
+ # Returns a pointer suitable for passing to Perl.
6
+ #
7
+ def to_perl
8
+ Perl::Value::Hash.to_perl(self)
9
+ end
10
+ 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