remogatto-ffi-generator 0.1.0

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.
@@ -0,0 +1,237 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+
3
+ include FFI
4
+
5
+ share_examples_for "All generation specs" do
6
+ after :all do
7
+ remove_xml
8
+ end
9
+ end
10
+
11
+ describe Generator::Parser do
12
+ it_should_behave_like 'All generation specs'
13
+ before :all do
14
+ @node = generate_xml_wrap_from('testlib')
15
+ end
16
+ it 'should generate ruby ffi wrap code' do
17
+ Generator::Parser.generate(@node).should == <<EOC
18
+
19
+ module TestLib
20
+ extend FFI::Library
21
+ CONST_1 = 0x10
22
+ CONST_2 = 0x20
23
+ ENUM_1 = 0
24
+ ENUM_2 = 1
25
+ ENUM_3 = 2
26
+
27
+ class UnionT < FFI::Union
28
+ layout(
29
+ :c, :char,
30
+ :f, :float
31
+ )
32
+ end
33
+ class TestStruct < FFI::Struct
34
+ layout(
35
+ :i, :int,
36
+ :c, :char,
37
+ :b, :uchar
38
+ )
39
+ end
40
+ class TestStruct3 < FFI::Struct
41
+ layout(
42
+ :c, :char
43
+ )
44
+ end
45
+ class TestStruct2 < FFI::Struct
46
+ layout(
47
+ :s, TestStruct,
48
+ :s_3, TestStruct3,
49
+ :e, :int,
50
+ :func, :pointer,
51
+ :u, UnionT
52
+ )
53
+ end
54
+ attach_function :get_int, [ :pointer ], :int
55
+ attach_function :get_char, [ :pointer ], :char
56
+ attach_function :func_with_enum, [ :int ], :int
57
+ attach_function :func_with_enum_2, [ :int ], :int
58
+ attach_function :func_with_typedef, [ ], :uchar
59
+
60
+ end
61
+ EOC
62
+ end
63
+ end
64
+
65
+ describe Generator::Constant do
66
+ it_should_behave_like 'All generation specs'
67
+ before :all do
68
+ @node = generate_xml_wrap_from('constants')
69
+ end
70
+ it 'should return a ruby constant assignment' do
71
+ Generator::Constant.new(@node / 'constant').to_s.should == "CONST_1 = 0x10"
72
+ end
73
+ end
74
+
75
+ describe Generator::Enum do
76
+ before :all do
77
+ @node = generate_xml_wrap_from('enums')
78
+ end
79
+ it 'should generate constants' do
80
+ Generator::Enum.new((@node / 'enum')[0]).to_s.should == <<EOE
81
+ ENUM_1 = 0
82
+ ENUM_2 = 1
83
+ ENUM_3 = 2
84
+ EOE
85
+ end
86
+ it 'should generate constants starting from the latest assignment' do
87
+ Generator::Enum.new((@node / 'enum')[1]).to_s.should == <<EOE
88
+ ENUM_21 = 2
89
+ ENUM_22 = 3
90
+ ENUM_23 = 4
91
+ EOE
92
+ Generator::Enum.new((@node / 'enum')[2]).to_s.should == <<EOE
93
+ ENUM_31 = 0
94
+ ENUM_32 = 5
95
+ ENUM_33 = 6
96
+ EOE
97
+ end
98
+ end
99
+
100
+ describe Generator::Type do
101
+ it_should_behave_like 'All generation specs'
102
+ before :all do
103
+ @node = generate_xml_wrap_from('types')
104
+ end
105
+ it 'should generate string type' do
106
+ Generator::Type.new((@node / 'cdecl')[0]).to_s.should == ':string'
107
+ end
108
+ it 'should generate pointer type' do
109
+ Generator::Type.new((@node / 'cdecl')[1]).to_s.should == ':pointer'
110
+ end
111
+ it 'should generate array type' do
112
+ Generator::Type.new((@node / 'cdecl')[2]).to_s.should == '[:int, 5]'
113
+ Generator::Type.new((@node / 'cdecl')[3]).to_s.should == '[:string, 5]'
114
+ end
115
+ it 'should generate struct type' do
116
+ Generator::Type.new((@node / 'cdecl')[5]).to_s.should == 'TestStruct'
117
+ end
118
+ it 'should generate struct array type' do
119
+ Generator::Type.new((@node / 'cdecl')[6]).to_s.should == '[TestStruct, 5]'
120
+ end
121
+ it 'should generate enum array type' do
122
+ Generator::Type.new((@node / 'cdecl')[7]).to_s.should == '[:int, 5]'
123
+ end
124
+ it 'should generate const type' do
125
+ Generator::Type.new((@node / 'cdecl')[8]).to_s.should == ':int'
126
+ Generator::Type.new((@node / 'cdecl')[9]).to_s.should == ':string'
127
+ end
128
+ Generator::TYPES.sort.each_with_index do |type, i|
129
+ it "should generate #{type[0]} type" do
130
+ Generator::Type.new((@node / 'cdecl')[i + 10]).to_s.should == type[1]
131
+ end
132
+ end
133
+ end
134
+
135
+ describe Generator::Function do
136
+ it_should_behave_like 'All generation specs'
137
+ before :all do
138
+ @node = generate_xml_wrap_from('functions')
139
+ end
140
+ it 'should return a properly generated attach_method' do
141
+ Generator::Function.new((@node / 'cdecl')[0]).to_s.should == "attach_function :func_1, [ :char, :int ], :int"
142
+ end
143
+ it 'should properly generate pointer arguments' do
144
+ Generator::Function.new((@node / 'cdecl')[1]).to_s.should == "attach_function :func_2, [ :pointer, :pointer ], :uint"
145
+ end
146
+ it 'should properly generate string arguments' do
147
+ Generator::Function.new((@node / 'cdecl')[2]).to_s.should == "attach_function :func_3, [ :string ], :void"
148
+ end
149
+ it 'should properly generate return type' do
150
+ Generator::Function.new((@node / 'cdecl')[3]).to_s.should == "attach_function :func_4, [ :int ], :string"
151
+ end
152
+ it 'should properly generate void return type' do
153
+ Generator::Function.new((@node / 'cdecl')[4]).to_s.should == "attach_function :func_5, [ ], :void"
154
+ end
155
+ it 'should properly generate pointer of pointer arguments' do
156
+ Generator::Function.new((@node / 'cdecl')[5]).to_s.should == "attach_function :func_6, [ :pointer ], :void"
157
+ end
158
+ it 'should properly generate enum arguments' do
159
+ Generator::Function.new((@node / 'cdecl')[6]).to_s.should == "attach_function :func_7, [ :int ], :void"
160
+ end
161
+ it 'should properly generate enum return type' do
162
+ Generator::Function.new((@node / 'cdecl')[7]).to_s.should == "attach_function :func_8, [ ], :int"
163
+ end
164
+ it 'should properly generate struct arguments' do
165
+ Generator::Function.new((@node / 'cdecl')[9]).to_s.should == "attach_function :func_9, [ TestStruct ], :void"
166
+ end
167
+ it 'should properly generate struct return type' do
168
+ Generator::Function.new((@node / 'cdecl')[10]).to_s.should == "attach_function :func_10, [ ], TestStruct"
169
+ end
170
+ end
171
+
172
+ describe Generator::Structure do
173
+ it_should_behave_like 'All generation specs'
174
+ before :all do
175
+ @node = generate_xml_wrap_from('structs')
176
+ end
177
+ it 'should properly generate the layout of a FFI::Struct class' do
178
+ Generator::Structure.new((@node / 'class')[0]).to_s.should == <<EOC
179
+ class TestStruct1 < FFI::Struct
180
+ layout(
181
+ :i, :int,
182
+ :c, :char,
183
+ :s, :string,
184
+ :a, [:char, 5]
185
+ )
186
+ end
187
+ EOC
188
+
189
+ end
190
+ it 'should properly generate the layout of a FFI::Struct containing pointer field' do
191
+ Generator::Structure.new((@node / 'class')[1]).to_s.should == <<EOC
192
+ class TestStruct2 < FFI::Struct
193
+ layout(
194
+ :ptr, :pointer
195
+ )
196
+ end
197
+ EOC
198
+ end
199
+ it 'should properly generate the layout of a FFI::Struct containing array field' do
200
+ Generator::Structure.new((@node / 'class')[2]).to_s.should == <<EOC
201
+ class TestStruct3 < FFI::Struct
202
+ layout(
203
+ :c, [:char, 5]
204
+ )
205
+ end
206
+ EOC
207
+
208
+ end
209
+ it 'should properly generate the layout of a FFI::Struct containing array field' do
210
+ Generator::Structure.new((@node / 'class')[3]).to_s.should == <<EOC
211
+ class TestStruct4 < FFI::Struct
212
+ layout(
213
+ :s, [TestStruct3, 5]
214
+ )
215
+ end
216
+ EOC
217
+
218
+ end
219
+ end
220
+
221
+ describe Generator::Union do
222
+ it_should_behave_like 'All generation specs'
223
+ before :all do
224
+ @node = generate_xml_wrap_from('unions')
225
+ end
226
+ it 'should properly generate the layout of a FFI::Union class' do
227
+ Generator::Union.new((@node / 'class')[0]).to_s.should == <<EOC
228
+ class UnionT < FFI::Union
229
+ layout(
230
+ :c, :char,
231
+ :f, :float
232
+ )
233
+ end
234
+ EOC
235
+ end
236
+ end
237
+
@@ -0,0 +1,3 @@
1
+ %module constant_wrap
2
+
3
+ #define CONST_1 0x10
@@ -0,0 +1,5 @@
1
+ %module enum_test
2
+
3
+ enum e { ENUM_1, ENUM_2, ENUM_3 };
4
+ enum e_2 { ENUM_21 = 2, ENUM_22, ENUM_23 };
5
+ enum e_3 { ENUM_31, ENUM_32 = 5, ENUM_33 };
@@ -0,0 +1,22 @@
1
+ %module function_testlib
2
+
3
+ int func_1(char c, int i);
4
+ unsigned int func_2(int* p1, int* p2);
5
+ void func_3(char* str);
6
+ char *func_4(int i);
7
+ extern void func_5();
8
+ void func_6(void** ptr);
9
+ void func_7(enum e e1);
10
+
11
+ enum e { E_1, E_2 };
12
+
13
+ enum e func_8();
14
+
15
+ struct test_struct {
16
+ char c;
17
+ };
18
+
19
+ void func_9(struct test_struct s);
20
+ struct test_struct func_10();
21
+
22
+
@@ -0,0 +1,25 @@
1
+ %module test_struct
2
+
3
+ struct test_struct_1 {
4
+ int i;
5
+ char c;
6
+ const char* s;
7
+ const char a[5];
8
+ };
9
+
10
+ struct test_struct_2 {
11
+ int* ptr;
12
+ };
13
+
14
+ struct test_struct_3 {
15
+ char c[5];
16
+ };
17
+
18
+ struct test_struct_4 {
19
+ struct test_struct_3 s[5];
20
+ };
21
+
22
+ struct test_struct_5 {
23
+ struct test_struct_4 s;
24
+ };
25
+
@@ -0,0 +1,47 @@
1
+ %module testlib
2
+
3
+ %{
4
+ module TestLib
5
+ extend FFI::Library
6
+ %}
7
+
8
+ #define CONST_1 0x10
9
+ #define CONST_2 0x20
10
+
11
+ typedef unsigned char byte;
12
+ typedef void (*PFI)(char*, char*);
13
+ typedef enum e_1 {
14
+ ENUM_1, ENUM_2, ENUM_3
15
+ } enum_t;
16
+
17
+ union union_t {
18
+ char c;
19
+ float f;
20
+ };
21
+
22
+ struct test_struct {
23
+ int i;
24
+ char c;
25
+ byte b;
26
+ };
27
+
28
+ typedef struct {
29
+ char c;
30
+ } test_struct_3;
31
+
32
+ struct test_struct_2 {
33
+ struct test_struct s;
34
+ test_struct_3 s_3;
35
+ enum_t e;
36
+ PFI func;
37
+ union_t u;
38
+ };
39
+
40
+ int get_int(struct test_struct* s);
41
+ char get_char(struct test_struct* s);
42
+ int func_with_enum(enum e_1 e);
43
+ int func_with_enum_2(enum_t e);
44
+ byte func_with_typedef();
45
+ %{
46
+ end
47
+ %}
@@ -0,0 +1,5 @@
1
+ %module test_typedef
2
+
3
+ typedef unsigned char byte;
4
+ byte b;
5
+ typedef int *(PTF)(char*, char*)
@@ -0,0 +1,51 @@
1
+ %module types_test
2
+
3
+ char *string;
4
+ void *ptr;
5
+
6
+ int array[5];
7
+ char* ptr_array[5];
8
+
9
+ struct test_struct {
10
+ char c;
11
+ };
12
+
13
+ enum e { E_1, E_2, E_3 };
14
+
15
+ struct test_struct ts;
16
+ struct test_struct a[5];
17
+ enum e enum_array[5];
18
+
19
+ const int ci;
20
+ const char* cstring;
21
+
22
+ char c;
23
+ double d;
24
+ float f;
25
+ int i;
26
+ long l;
27
+ long int li;
28
+ long long ll;
29
+ long long int lli;
30
+ long unsigned int lui;
31
+ short s;
32
+ signed char sc;
33
+ signed int si;
34
+ signed long sl;
35
+ signed long int sli;
36
+ signed long long sll;
37
+ signed long long int slli;
38
+ signed short ss;
39
+ signed short int ssi;
40
+ unsigned char uc;
41
+ unsigned int ui;
42
+ unsigned long ul;
43
+ unsigned long int uli;
44
+ unsigned long long ull;
45
+ unsigned long long int ulli;
46
+ unsigned short us;
47
+ unsigned short int usi;
48
+ void v;
49
+
50
+
51
+
@@ -0,0 +1,6 @@
1
+ %module union_test
2
+
3
+ union union_t {
4
+ char c;
5
+ float f;
6
+ };
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format
3
+ specdoc
4
+ -D
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.expand_path(
5
+ File.join(File.dirname(__FILE__), %w[.. lib ffi-generator]))
6
+
7
+ Spec::Runner.configure do |config|
8
+ # == Mock Framework
9
+ #
10
+ # RSpec uses it's own mocking framework by default. If you prefer to
11
+ # use mocha, flexmock or RR, uncomment the appropriate line:
12
+ #
13
+ # config.mock_with :mocha
14
+ # config.mock_with :flexmock
15
+ # config.mock_with :rr
16
+ end
17
+
18
+ def generate_xml_wrap_from(fn)
19
+ `swig -xml spec/generator/swig/#{fn + '.i'}`
20
+ Nokogiri::XML(File.open(File.join('spec/generator/swig/', "#{fn}_wrap.xml")))
21
+ end
22
+
23
+ def remove_xml
24
+ FileUtils.rm(Dir.glob('spec/generator/swig/*.xml'))
25
+ end
26
+
27
+ # EOF
data/tasks/ann.rake ADDED
@@ -0,0 +1,80 @@
1
+
2
+ begin
3
+ require 'bones/smtp_tls'
4
+ rescue LoadError
5
+ require 'net/smtp'
6
+ end
7
+ require 'time'
8
+
9
+ namespace :ann do
10
+
11
+ # A prerequisites task that all other tasks depend upon
12
+ task :prereqs
13
+
14
+ file PROJ.ann.file do
15
+ ann = PROJ.ann
16
+ puts "Generating #{ann.file}"
17
+ File.open(ann.file,'w') do |fd|
18
+ fd.puts("#{PROJ.name} version #{PROJ.version}")
19
+ fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
20
+ fd.puts(" #{PROJ.url}") if PROJ.url.valid?
21
+ fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
22
+ fd.puts
23
+ fd.puts("== DESCRIPTION")
24
+ fd.puts
25
+ fd.puts(PROJ.description)
26
+ fd.puts
27
+ fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
28
+ fd.puts
29
+ ann.paragraphs.each do |p|
30
+ fd.puts "== #{p.upcase}"
31
+ fd.puts
32
+ fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
33
+ fd.puts
34
+ end
35
+ fd.puts ann.text if ann.text
36
+ end
37
+ end
38
+
39
+ desc "Create an announcement file"
40
+ task :announcement => ['ann:prereqs', PROJ.ann.file]
41
+
42
+ desc "Send an email announcement"
43
+ task :email => ['ann:prereqs', PROJ.ann.file] do
44
+ ann = PROJ.ann
45
+ from = ann.email[:from] || Array(PROJ.authors).first || PROJ.email
46
+ to = Array(ann.email[:to])
47
+
48
+ ### build a mail header for RFC 822
49
+ rfc822msg = "From: #{from}\n"
50
+ rfc822msg << "To: #{to.join(',')}\n"
51
+ rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
52
+ rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
53
+ rfc822msg << "\n"
54
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
55
+ rfc822msg << "Message-Id: "
56
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
57
+ rfc822msg << File.read(ann.file)
58
+
59
+ params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
60
+ ann.email[key]
61
+ end
62
+
63
+ params[3] = PROJ.email if params[3].nil?
64
+
65
+ if params[4].nil?
66
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
67
+ params[4] = STDIN.gets.chomp
68
+ end
69
+
70
+ ### send email
71
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
72
+ end
73
+ end # namespace :ann
74
+
75
+ desc 'Alias to ann:announcement'
76
+ task :ann => 'ann:announcement'
77
+
78
+ CLOBBER << PROJ.ann.file
79
+
80
+ # EOF
data/tasks/bones.rake ADDED
@@ -0,0 +1,20 @@
1
+
2
+ if HAVE_BONES
3
+
4
+ namespace :bones do
5
+
6
+ desc 'Show the PROJ open struct'
7
+ task :debug do |t|
8
+ atr = if t.application.top_level_tasks.length == 2
9
+ t.application.top_level_tasks.pop
10
+ end
11
+
12
+ if atr then Bones::Debug.show_attr(PROJ, atr)
13
+ else Bones::Debug.show PROJ end
14
+ end
15
+
16
+ end # namespace :bones
17
+
18
+ end # HAVE_BONES
19
+
20
+ # EOF