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 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