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