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/lib/perl/value.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Perl
2
+ class Value
3
+ end
4
+ end
@@ -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