ruby-perl 0.99.15j
Sign up to get free protection for your applications and to get access to all the features.
- 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/lib/perl/value.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'perl/value'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
class Perl::Value::Array
|
5
|
+
class Av < FFI::Struct
|
6
|
+
class Xnv_u < FFI::Union
|
7
|
+
layout :xnv_nv, :long,
|
8
|
+
:xgv_stash, :pointer,
|
9
|
+
:xpad_cop_seq, :long,
|
10
|
+
:xbm_s, :long
|
11
|
+
end
|
12
|
+
|
13
|
+
layout :xnv_u, Xnv_u,
|
14
|
+
:xav_fill, :long,
|
15
|
+
:xav_max, :long
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"<#{self.class.name} @xav_fill=#{self[:xav_fill].inspect} @xav_max=#{self[:xav_max].inspect}>"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(args)
|
23
|
+
@perl = Perl.PL_curinterp
|
24
|
+
@value = nil
|
25
|
+
@array = nil
|
26
|
+
@av = nil
|
27
|
+
|
28
|
+
case args
|
29
|
+
when Perl::Value::Scalar::SV
|
30
|
+
@array = args[:sv_u][:svu_array]
|
31
|
+
@av = Av.new(args[:sv_any])
|
32
|
+
when nil
|
33
|
+
else
|
34
|
+
raise "Don't know how to handle #{args.class} (#{args.inspect})"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def value
|
39
|
+
return @value if @value
|
40
|
+
if @array
|
41
|
+
@value = @array.get_array_of_pointer(0, @av[:xav_fill]+1).map do |ptr|
|
42
|
+
Perl::Value::Scalar.new(ptr)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def freeze!
|
50
|
+
self.value.each { |v| v.freeze! }
|
51
|
+
@array = nil
|
52
|
+
@av = nil
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'perl/value'
|
2
|
+
require 'perl/value/scalar'
|
3
|
+
require 'ffi'
|
4
|
+
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
class Perl::Value::Hash
|
8
|
+
HV_DISABLE_UVAR_XKEY = 0x01
|
9
|
+
HV_FETCH_ISSTORE = 0x04
|
10
|
+
HV_FETCH_ISEXISTS = 0x08
|
11
|
+
HV_FETCH_LVALUE = 0x10
|
12
|
+
HV_FETCH_JUST_SV = 0x20
|
13
|
+
HV_DELETE = 0x40
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def to_perl(hash)
|
17
|
+
build_hv(Perl.PL_curinterp, hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
def build_hv(perl, hash)
|
22
|
+
new_hv(perl).tap do |hv|
|
23
|
+
hash.each do |k,v|
|
24
|
+
value = value_to_sv(k, v)
|
25
|
+
add_key_value(perl, hv, k.to_s, value) if value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def new_hv(perl)
|
31
|
+
Perl.Perl_newHV(perl)
|
32
|
+
end
|
33
|
+
|
34
|
+
def value_to_sv(key, value)
|
35
|
+
case value
|
36
|
+
when Array, IO
|
37
|
+
puts "Don't know how to handle #{value.class} (#{key} => #{value.inspect})"
|
38
|
+
when FalseClass
|
39
|
+
Perl::Value::Scalar.to_perl(value.to_s) # FIXME
|
40
|
+
when Method
|
41
|
+
puts "Cannot handle value with class=#{value.class} (#{key} => #{value.inspect}), skipping"
|
42
|
+
when String, StringIO
|
43
|
+
Perl::Value::Scalar.to_perl(value)
|
44
|
+
when TrueClass
|
45
|
+
Perl::Value::Scalar.to_perl(value.to_s) # FIXME
|
46
|
+
else
|
47
|
+
raise "Don't know how to handle #{value.class} (#{key} => #{value.inspect})"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_key_value(perl, hv, key, value)
|
52
|
+
Perl.Perl_hv_common_key_len(perl, hv, key, key.length, (HV_FETCH_ISSTORE|HV_FETCH_JUST_SV), value, 0)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(args = nil)
|
57
|
+
@perl = Perl.PL_curinterp
|
58
|
+
@hash = nil
|
59
|
+
@hv = nil
|
60
|
+
|
61
|
+
case args
|
62
|
+
when Hash
|
63
|
+
@hash = args
|
64
|
+
when nil
|
65
|
+
else
|
66
|
+
raise "Don't know how to handle #{args.class} (#{args.inspect})"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_perl
|
71
|
+
@hv ||= self.class.send(:build_hv, @perl, @hash)
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'perl/value'
|
2
|
+
require 'perl/value/array'
|
3
|
+
require 'ffi'
|
4
|
+
|
5
|
+
class Perl::Value::Scalar
|
6
|
+
class SV < FFI::Struct
|
7
|
+
class SvU < FFI::Union
|
8
|
+
layout :svu_iv, :long,
|
9
|
+
:svu_uv, :long, # XXX ?
|
10
|
+
:svu_rv, :pointer,
|
11
|
+
:svu_pv, :string,
|
12
|
+
:svu_array, :pointer,
|
13
|
+
:svu_hash, :pointer,
|
14
|
+
:svu_gp, :pointer
|
15
|
+
end
|
16
|
+
|
17
|
+
layout :sv_any, :pointer,
|
18
|
+
:sv_refcnt, :int32,
|
19
|
+
:sv_flags, :int32,
|
20
|
+
:sv_u, SvU
|
21
|
+
|
22
|
+
SVt_NULL = 0
|
23
|
+
SVt_BIND = 1
|
24
|
+
SVt_IV = 2
|
25
|
+
SVt_NV = 3
|
26
|
+
SVt_RV = 4
|
27
|
+
SVt_PV = 5
|
28
|
+
SVt_PVIV = 6
|
29
|
+
SVt_PVNV = 7
|
30
|
+
SVt_PVMG = 8
|
31
|
+
SVt_PVGV = 9
|
32
|
+
SVt_PVLV = 10
|
33
|
+
SVt_PVAV = 11
|
34
|
+
SVt_PVHV = 12
|
35
|
+
SVt_PVCV = 13
|
36
|
+
SVt_PVFM = 14
|
37
|
+
SVt_PVIO = 15
|
38
|
+
SVTYPEMASK = 0xff
|
39
|
+
|
40
|
+
SVf_IOK = 0x00000100
|
41
|
+
SVf_NOK = 0x00000200
|
42
|
+
SVf_POK = 0x00000400
|
43
|
+
SVf_ROK = 0x00000800
|
44
|
+
|
45
|
+
def value
|
46
|
+
case
|
47
|
+
when (self[:sv_flags] & SVf_POK) == SVf_POK
|
48
|
+
self[:sv_u][:svu_pv]
|
49
|
+
when (self[:sv_flags] & SVf_ROK) == SVf_ROK
|
50
|
+
Perl::Value::Scalar.new(self[:sv_u][:svu_rv])
|
51
|
+
when (self[:sv_flags] & SVTYPEMASK) == SVt_PVAV
|
52
|
+
Perl::Value::Array.new(self)
|
53
|
+
else
|
54
|
+
raise "Don't know how to handle #{self[:sv_u]} (#{self.inspect})"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def reference?
|
59
|
+
(self[:sv_flags] & SVf_ROK) == SVf_ROK
|
60
|
+
end
|
61
|
+
|
62
|
+
def deref
|
63
|
+
raise "Not a reference!" unless (self[:sv_flags] & SVf_ROK) == SVf_ROK
|
64
|
+
|
65
|
+
SV.new(self[:sv_u][:svu_rv]).value
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
"<#{self.class.name} @pointer=#{self.pointer} @sv_any=#{self[:sv_any].inspect} @sv_refcnt=#{self[:sv_refcnt].inspect} @sv_flags=0x#{self[:sv_flags].to_s(16)} @sv_u=#{self[:sv_u].inspect}>"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class << self
|
74
|
+
def to_perl(value)
|
75
|
+
case value
|
76
|
+
when String
|
77
|
+
Perl.Perl_newSVpv(Perl.PL_curinterp, value, value.length)
|
78
|
+
when StringIO
|
79
|
+
value = value.string
|
80
|
+
Perl.Perl_newSVpv(Perl.PL_curinterp, value, value.length)
|
81
|
+
when nil
|
82
|
+
else
|
83
|
+
raise "Don't know how to handle #{value.class} (#{value.inspect})"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def initialize(args = nil)
|
89
|
+
@perl = Perl.PL_curinterp
|
90
|
+
@scalar = nil
|
91
|
+
@sv = nil
|
92
|
+
@deref = nil
|
93
|
+
@is_ref = nil
|
94
|
+
|
95
|
+
case args
|
96
|
+
when FFI::Pointer
|
97
|
+
@sv = SV.new(args)
|
98
|
+
when String
|
99
|
+
@scalar = args
|
100
|
+
when nil
|
101
|
+
else
|
102
|
+
raise "Don't know how to handle #{args.class} (#{args.inspect})"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_perl
|
107
|
+
@sv ||= Perl.Perl_newSVpv(@perl, @scalar, @scalar.length)
|
108
|
+
end
|
109
|
+
|
110
|
+
def value
|
111
|
+
@scalar ||= @sv ? @sv.value : nil
|
112
|
+
end
|
113
|
+
|
114
|
+
def reference?
|
115
|
+
if @is_ref.nil?
|
116
|
+
@is_ref = @sv.reference?
|
117
|
+
else
|
118
|
+
@is_ref
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def deref
|
123
|
+
@deref ||= to_perl.deref
|
124
|
+
end
|
125
|
+
|
126
|
+
def freeze!
|
127
|
+
reference? ? self.deref.freeze! : self.value
|
128
|
+
@sv = nil
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'perl/ext/hash'
|
4
|
+
require 'perl/interpreter'
|
5
|
+
|
6
|
+
describe Hash do
|
7
|
+
describe "#to_perl" do
|
8
|
+
before(:all) do
|
9
|
+
@interpreter = Perl::Interpreter.new
|
10
|
+
end
|
11
|
+
after(:all) do
|
12
|
+
@interpreter.stop
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "on an empty Hash" do
|
16
|
+
let(:subject) { {} }
|
17
|
+
|
18
|
+
it "should return the expected result" do
|
19
|
+
ptr = subject.to_perl
|
20
|
+
ptr.should be_kind_of(FFI::Pointer)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'perl/ext/object'
|
4
|
+
|
5
|
+
class Object
|
6
|
+
def perl_interpreter
|
7
|
+
@_perl
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Object do
|
12
|
+
after(:each) do
|
13
|
+
perl_interpreter.stop
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#Perl" do
|
17
|
+
it "should instance an interpreter" do
|
18
|
+
perl_interpreter.should be_nil
|
19
|
+
Perl("$_")
|
20
|
+
perl_interpreter.should_not be_nil
|
21
|
+
perl_interpreter.should be_kind_of(Perl::Interpreter)
|
22
|
+
end
|
23
|
+
|
24
|
+
# it "should run the provided code" do
|
25
|
+
# ret = capture_stdout_descriptor do
|
26
|
+
# Perl("print \"hi there\";")
|
27
|
+
# end
|
28
|
+
# ret.should == "hi there"
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# it "should run the provided code block" do
|
32
|
+
# ret = capture_stdout_descriptor do
|
33
|
+
# Perl do
|
34
|
+
# run "print \"hi there\";"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# ret.should == "hi there"
|
38
|
+
# end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'perl/ext/string'
|
4
|
+
require 'perl/interpreter'
|
5
|
+
|
6
|
+
describe String do
|
7
|
+
describe "#to_perl" do
|
8
|
+
before(:all) do
|
9
|
+
@interpreter = Perl::Interpreter.new
|
10
|
+
end
|
11
|
+
after(:all) do
|
12
|
+
@interpreter.stop
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "on an empty String" do
|
16
|
+
let(:subject) { "" }
|
17
|
+
|
18
|
+
it "should return the expected result" do
|
19
|
+
ptr = subject.to_perl
|
20
|
+
ptr.should be_kind_of(FFI::Pointer)
|
21
|
+
value = Perl::Value::Scalar.new(ptr)
|
22
|
+
value.value.should == ""
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "on a String" do
|
27
|
+
let(:subject) { "something" }
|
28
|
+
|
29
|
+
it "should return the expected result" do
|
30
|
+
ptr = subject.to_perl
|
31
|
+
ptr.should be_kind_of(FFI::Pointer)
|
32
|
+
value = Perl::Value::Scalar.new(ptr)
|
33
|
+
value.value.should == "something"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'perl/value/hash'
|
4
|
+
require 'perl/interpreter'
|
5
|
+
|
6
|
+
describe Perl::Value::Hash do
|
7
|
+
include PerlValueHelpers
|
8
|
+
|
9
|
+
context "built without arguments" do
|
10
|
+
its(:perl) { should_not be_nil }
|
11
|
+
its(:hash) { should be_nil }
|
12
|
+
its(:hv) { should be_nil }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "built from a String" do
|
16
|
+
let(:input) { "pippo" }
|
17
|
+
it do
|
18
|
+
lambda { described_class.new(input) }.should raise_error
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "built from a Hash" do
|
23
|
+
before(:all) do
|
24
|
+
@interpreter = Perl::Interpreter.new
|
25
|
+
end
|
26
|
+
after(:all) do
|
27
|
+
@interpreter.stop
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:input) { {:a => "b", :c => "d"} }
|
31
|
+
subject { described_class.new(input) }
|
32
|
+
its(:perl) { should_not be_nil }
|
33
|
+
its(:hash) { should_not be_nil }
|
34
|
+
its(:hash) { should eq(input) }
|
35
|
+
its(:hv) { should be_nil }
|
36
|
+
|
37
|
+
describe "when #to_perl is called" do
|
38
|
+
it "should return the expected object" do
|
39
|
+
subject.to_perl.should_not be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should cache the returned object" do
|
43
|
+
subject.to_perl.should == subject.hv
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'perl/interpreter'
|
4
|
+
require 'perl/value/hash'
|
5
|
+
require 'ffi'
|
6
|
+
|
7
|
+
class PerlCommon
|
8
|
+
extend Perl::Common
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Perl::Interpreter do
|
12
|
+
describe "#initialize" do
|
13
|
+
it "should call setup" do
|
14
|
+
original_setup = Perl.setup
|
15
|
+
Perl.should_receive(:setup) do
|
16
|
+
@called = true
|
17
|
+
original_setup
|
18
|
+
end
|
19
|
+
|
20
|
+
described_class.new
|
21
|
+
@called.should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should call perl_alloc and pass its return value to more methods" do
|
25
|
+
Perl.should_receive(:perl_alloc).and_return(42)
|
26
|
+
Perl.should_receive(:perl_construct).with(42)
|
27
|
+
Perl.should_receive(:perl_parse) do |*args|
|
28
|
+
@args = args
|
29
|
+
end
|
30
|
+
Perl.should_receive(:perl_run).with(42)
|
31
|
+
|
32
|
+
described_class.new
|
33
|
+
@args[0].should == 42
|
34
|
+
end
|
35
|
+
|
36
|
+
# XXX this is a bad spec, it should be a spec to fake_args itself
|
37
|
+
it "should call perl_parse with the expected arguments" do
|
38
|
+
argc, argv = PerlCommon.embedded_argv_to_ffi
|
39
|
+
Perl.should_receive(:perl_parse) do |*args|
|
40
|
+
@args = args
|
41
|
+
end
|
42
|
+
|
43
|
+
described_class.new
|
44
|
+
@args[2].should == argc
|
45
|
+
@args[3].should be_kind_of(FFI::MemoryPointer)
|
46
|
+
@args[3].size.should == FFI.type_size(:pointer) * (argc + 1)
|
47
|
+
|
48
|
+
(0..@args[2]).each do |i|
|
49
|
+
entry = @args[3][i].get_pointer(0)
|
50
|
+
entry.should be_kind_of(FFI::Pointer)
|
51
|
+
end
|
52
|
+
@args[3][0].get_pointer(0).read_string.should == ""
|
53
|
+
@args[3][1].get_pointer(0).read_string.should == "-e"
|
54
|
+
@args[3][2].get_pointer(0).read_string.should == "0"
|
55
|
+
@args[3][3].get_pointer(0).address.should == 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#call" do
|
60
|
+
after(:each) do
|
61
|
+
subject.stop
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should prepare a Perl stack" do
|
65
|
+
Perl::Stack.should_receive(:function_stack)
|
66
|
+
|
67
|
+
subject.call("something", [], :void)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should call args_on_stack" do
|
71
|
+
Perl::Stack::Function.should_receive(:new).any_number_of_times do |stack, args|
|
72
|
+
@stack = stack
|
73
|
+
@args = args
|
74
|
+
end
|
75
|
+
|
76
|
+
subject.call("something", [], :void)
|
77
|
+
@args.should == []
|
78
|
+
subject.call("something", [{}, :hash], :void)
|
79
|
+
@args.should == [{}, :hash]
|
80
|
+
end
|
81
|
+
|
82
|
+
# XXX this should be a spec for Perl::Stack::Function
|
83
|
+
# it "should push all the arguments onto the stack" do
|
84
|
+
# @stack = []
|
85
|
+
#
|
86
|
+
# fs = mock(:function_stack).tap do |stack|
|
87
|
+
# stack.should_receive(:push).any_number_of_times do |arg|
|
88
|
+
# @stack << arg
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
# Perl::Stack::Function.should_receive(:new).and_yield(fs)
|
92
|
+
# Perl.should_receive(:Perl_call_pv)
|
93
|
+
#
|
94
|
+
# subject.call("something", [{}, :hash], :void)
|
95
|
+
# @stack.length.should == 1
|
96
|
+
# @stack[0].should be_kind_of(FFI::Pointer)
|
97
|
+
# end
|
98
|
+
|
99
|
+
it "should pass a String to a Perl function" do
|
100
|
+
func = subject.eval("require 'dumpvar.pl'; sub { dumpValue(\\@_); };")
|
101
|
+
|
102
|
+
ret = capture_stdout_descriptor do
|
103
|
+
subject.call(func, "42", :void)
|
104
|
+
end
|
105
|
+
ret = ret.split(/\n/)
|
106
|
+
ret.length.should == 1
|
107
|
+
ret[0].should =~ /^0\s+42/
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should pass a String reference to a Perl function" do
|
111
|
+
func = subject.eval("require 'dumpvar.pl'; sub { dumpValue(\\@_); };")
|
112
|
+
|
113
|
+
ret = capture_stdout_descriptor do
|
114
|
+
subject.call(func, {:ref => "42"}, :void)
|
115
|
+
end
|
116
|
+
ret = ret.split(/\n/)
|
117
|
+
ret.length.should == 2
|
118
|
+
ret[0].should =~ /^0\s+SCALAR/
|
119
|
+
ret[1].should =~ /^\s+-> 42/
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should pass a Hash reference to a Perl function" do
|
123
|
+
func = subject.eval("require 'dumpvar.pl'; sub { dumpValue(\\@_); };")
|
124
|
+
|
125
|
+
ret = capture_stdout_descriptor do
|
126
|
+
subject.call(func, {:ref => {'a' => 'b'}}, :void)
|
127
|
+
end
|
128
|
+
ret = ret.split(/\n/)
|
129
|
+
ret.length.should == 2
|
130
|
+
ret[0].should =~ /^0\s+HASH/
|
131
|
+
ret[1].should =~ /^\s+'a' => 'b'/
|
132
|
+
end
|
133
|
+
|
134
|
+
context "in a void context" do
|
135
|
+
context "when passed a string" do
|
136
|
+
it "should yield nil" do
|
137
|
+
func = subject.eval("sub { return \"string\"; };")
|
138
|
+
|
139
|
+
subject.call(func, [], :void) do |ret|
|
140
|
+
ret.should be_nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it "the return value should be nil" do
|
145
|
+
func = subject.eval("sub { return \"string\"; };")
|
146
|
+
|
147
|
+
subject.call(func, [], :void).should be_nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when passed an array" do
|
152
|
+
it "should yield nil" do
|
153
|
+
func = subject.eval("sub { return [\"1\", \"2\"]; };")
|
154
|
+
|
155
|
+
subject.call(func, [], :void) do |ret|
|
156
|
+
ret.should be_nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it "the return value should be nil" do
|
161
|
+
func = subject.eval("sub { return [\"1\", \"2\"]; };")
|
162
|
+
|
163
|
+
subject.call(func, [], :void).should be_nil
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "in a scalar context" do
|
169
|
+
context "when passed a string" do
|
170
|
+
it "should yield a scalar that acts as a string" do
|
171
|
+
func = subject.eval("sub { return \"string\"; };")
|
172
|
+
|
173
|
+
subject.call(func, [], :scalar) do |ret|
|
174
|
+
ret.value.should == "string"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should return a scalar that acts as a string" do
|
179
|
+
func = subject.eval("sub { return \"string\"; };")
|
180
|
+
|
181
|
+
ret = subject.call(func, [], :scalar)
|
182
|
+
ret.value.should == "string"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "when passed an array" do
|
187
|
+
it "should yield an array reference" do
|
188
|
+
func = subject.eval("sub { return [\"1\", \"2\"]; };")
|
189
|
+
|
190
|
+
subject.call(func, [], :scalar) do |ret|
|
191
|
+
ret.reference?.should be_true
|
192
|
+
ret.deref.should be_kind_of(Perl::Value::Array)
|
193
|
+
|
194
|
+
array = ret.deref.value
|
195
|
+
array.length.should == 2
|
196
|
+
array[0].should be_kind_of(Perl::Value::Scalar)
|
197
|
+
array[0].value.should == "1"
|
198
|
+
array[1].should be_kind_of(Perl::Value::Scalar)
|
199
|
+
array[1].value.should == "2"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
it "the return value should be an array reference" do
|
204
|
+
func = subject.eval("sub { return [\"1\", \"2\"]; };")
|
205
|
+
|
206
|
+
ret = subject.call(func, [], :scalar)
|
207
|
+
ret.reference?.should be_true
|
208
|
+
ret.deref.should be_kind_of(Perl::Value::Array)
|
209
|
+
|
210
|
+
array = ret.deref.value
|
211
|
+
array.length.should == 2
|
212
|
+
array[0].should be_kind_of(Perl::Value::Scalar)
|
213
|
+
array[0].value.should == "1"
|
214
|
+
array[1].should be_kind_of(Perl::Value::Scalar)
|
215
|
+
array[1].value.should == "2"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|