RubyInline 3.3.1 → 3.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/README.txt +1 -0
- data/inline.rb +84 -48
- data/test_inline.rb +37 -9
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
*** 3.3.2 / 2005-05-19
|
2
|
+
|
3
|
+
+ 4 bug fixes
|
4
|
+
+ Fixed a line number issue when using c_raw w/ multi-line signatures.
|
5
|
+
+ Inline can now be invoked multiple times per class.
|
6
|
+
+ Filled out rdoc.
|
7
|
+
+ Fixed some old tests.
|
8
|
+
|
1
9
|
*** 3.3.1 / 2005-05-03
|
2
10
|
|
3
11
|
+ 3 bug fixes
|
data/README.txt
CHANGED
data/inline.rb
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
#
|
23
23
|
# = DESCRIPTION
|
24
24
|
#
|
25
|
-
# Inline allows you to write
|
25
|
+
# Inline allows you to write foreign code within your ruby code. It
|
26
26
|
# automatically determines if the code in question has changed and
|
27
27
|
# builds it only when necessary. The extensions are then automatically
|
28
28
|
# loaded into the class/module that defines it.
|
@@ -51,7 +51,7 @@ class CompilationError < RuntimeError; end
|
|
51
51
|
# the current namespace.
|
52
52
|
|
53
53
|
module Inline
|
54
|
-
VERSION = '3.3.
|
54
|
+
VERSION = '3.3.2'
|
55
55
|
|
56
56
|
$stderr.puts "RubyInline v #{VERSION}" if $DEBUG
|
57
57
|
|
@@ -204,7 +204,7 @@ module Inline
|
|
204
204
|
prefix += " #{type} #{arg} = #{ruby2c(type)}(_#{arg});\n"
|
205
205
|
end
|
206
206
|
end
|
207
|
-
# replace the function signature (hopefully) with new
|
207
|
+
# replace the function signature (hopefully) with new sig (prefix)
|
208
208
|
result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
|
209
209
|
result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
|
210
210
|
unless return_type == "void" then
|
@@ -222,8 +222,15 @@ module Inline
|
|
222
222
|
result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
|
223
223
|
end
|
224
224
|
|
225
|
+
delta = if result =~ /\A(static.*?\{)/m then
|
226
|
+
$1.split(/\n/).size
|
227
|
+
else
|
228
|
+
warn "WARNING: Can't find signature in #{result.inspect}\n" unless $TESTING
|
229
|
+
0
|
230
|
+
end
|
231
|
+
|
225
232
|
file, line = caller[1].split(/:/)
|
226
|
-
result = "# line #{line.to_i
|
233
|
+
result = "# line #{line.to_i + delta} \"#{file}\"\n" + result unless $DEBUG
|
227
234
|
|
228
235
|
@src << result
|
229
236
|
@sig[function_name] = [arity,singleton]
|
@@ -231,13 +238,49 @@ module Inline
|
|
231
238
|
return result if $TESTING
|
232
239
|
end # def generate
|
233
240
|
|
241
|
+
def module_name
|
242
|
+
unless defined? @module_name then
|
243
|
+
module_name = @mod.name.gsub('::','__')
|
244
|
+
md5 = Digest::MD5.new
|
245
|
+
@sig.keys.sort_by{|x| x.to_s}.each { |m| md5 << m.to_s }
|
246
|
+
@module_name = "Inline_#{module_name}_#{md5.to_s[0,4]}"
|
247
|
+
end
|
248
|
+
@module_name
|
249
|
+
end
|
250
|
+
|
251
|
+
def so_name
|
252
|
+
unless defined? @so_name then
|
253
|
+
@so_name = "#{Inline.directory}/#{module_name}.#{Config::CONFIG["DLEXT"]}"
|
254
|
+
end
|
255
|
+
@so_name
|
256
|
+
end
|
257
|
+
|
258
|
+
attr_reader :rb_file, :mod
|
234
259
|
attr_accessor :mod, :src, :sig, :flags, :libs if $TESTING
|
235
260
|
|
236
261
|
public
|
237
262
|
|
263
|
+
def initialize(mod)
|
264
|
+
raise ArgumentError, "Class/Module arg is required" unless Module === mod
|
265
|
+
|
266
|
+
real_caller = caller[2] # new -> inline -> real_caller|eval
|
267
|
+
real_caller = caller[5] if real_caller =~ /\(eval\)/
|
268
|
+
@real_caller = real_caller.split(/:/).first
|
269
|
+
@rb_file = File.expand_path(@real_caller)
|
270
|
+
|
271
|
+
@mod = mod
|
272
|
+
@src = []
|
273
|
+
@sig = {}
|
274
|
+
@flags = []
|
275
|
+
@libs = []
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# Attempts to load pre-generated code returning true if it succeeds.
|
280
|
+
|
238
281
|
def load_cache
|
239
282
|
begin
|
240
|
-
file = File.join("inline", File.basename(
|
283
|
+
file = File.join("inline", File.basename(so_name))
|
241
284
|
if require file then
|
242
285
|
dir = Inline.directory
|
243
286
|
warn "WARNING: #{dir} exists but is not being used" if test ?d, dir
|
@@ -248,20 +291,23 @@ module Inline
|
|
248
291
|
return false
|
249
292
|
end
|
250
293
|
|
294
|
+
##
|
295
|
+
# Loads the generated code back into ruby
|
296
|
+
|
251
297
|
def load
|
252
|
-
require "#{
|
298
|
+
require "#{so_name}" or raise LoadError, "require on #{so_name} failed"
|
253
299
|
end
|
254
300
|
|
301
|
+
##
|
302
|
+
# Builds the source file, if needed, and attempts to compile it.
|
303
|
+
|
255
304
|
def build
|
256
|
-
|
257
|
-
|
258
|
-
real_caller = real_caller.split(/:/).first
|
259
|
-
@rb_file = File.expand_path(real_caller) # [MS]
|
260
|
-
so_exists = File.file? @so_name
|
305
|
+
so_name = self.so_name
|
306
|
+
so_exists = File.file? so_name
|
261
307
|
|
262
|
-
unless so_exists and File.mtime(
|
308
|
+
unless so_exists and File.mtime(rb_file) < File.mtime(so_name)
|
263
309
|
|
264
|
-
src_name = "#{Inline.directory}/#{
|
310
|
+
src_name = "#{Inline.directory}/#{module_name}.c"
|
265
311
|
old_src_name = "#{src_name}.old"
|
266
312
|
should_compare = File.write_with_backup(src_name) do |io|
|
267
313
|
io.puts
|
@@ -273,8 +319,9 @@ module Inline
|
|
273
319
|
io.puts "#ifdef __cplusplus"
|
274
320
|
io.puts "extern \"C\" {"
|
275
321
|
io.puts "#endif"
|
276
|
-
io.puts " void Init_#{
|
322
|
+
io.puts " void Init_#{module_name}() {"
|
277
323
|
io.puts " VALUE c = rb_cObject;"
|
324
|
+
# TODO: use rb_class2path
|
278
325
|
@mod.name.split("::").each do |n|
|
279
326
|
io.puts " c = rb_const_get_at(c,rb_intern(\"#{n}\"));"
|
280
327
|
end
|
@@ -305,7 +352,7 @@ module Inline
|
|
305
352
|
# Prevents us from entering this conditional unless the source
|
306
353
|
# file changes again.
|
307
354
|
t = Time.now
|
308
|
-
File.utime(t, t, src_name, old_src_name,
|
355
|
+
File.utime(t, t, src_name, old_src_name, so_name)
|
309
356
|
end
|
310
357
|
|
311
358
|
if recompile then
|
@@ -327,18 +374,18 @@ module Inline
|
|
327
374
|
libs = @libs.join(' ')
|
328
375
|
libs += " #{$INLINE_LIBS}" if defined? $INLINE_LIBS # DEPRECATE
|
329
376
|
|
330
|
-
cmd = "#{Config::CONFIG['LDSHARED']} #{flags} #{Config::CONFIG['CFLAGS']} -I #{hdrdir} -o #{
|
377
|
+
cmd = "#{Config::CONFIG['LDSHARED']} #{flags} #{Config::CONFIG['CFLAGS']} -I #{hdrdir} -o #{so_name} #{src_name} #{libs}"
|
331
378
|
|
332
379
|
case RUBY_PLATFORM
|
333
380
|
when /mswin32/ then
|
334
|
-
cmd += " -link /INCREMENTAL:no /EXPORT:Init_#{
|
381
|
+
cmd += " -link /INCREMENTAL:no /EXPORT:Init_#{module_name}"
|
335
382
|
when /i386-cygwin/ then
|
336
383
|
cmd += ' -L/usr/local/lib -lruby.dll'
|
337
384
|
end
|
338
385
|
|
339
386
|
cmd += " 2> /dev/null" if $TESTING
|
340
387
|
|
341
|
-
$stderr.puts "Building #{
|
388
|
+
$stderr.puts "Building #{so_name} with '#{cmd}'" if $DEBUG
|
342
389
|
`#{cmd}`
|
343
390
|
if $? != 0 then
|
344
391
|
bad_src_name = src_name + ".bad"
|
@@ -349,36 +396,11 @@ module Inline
|
|
349
396
|
end
|
350
397
|
|
351
398
|
else
|
352
|
-
$stderr.puts "#{
|
399
|
+
$stderr.puts "#{so_name} is up to date" if $DEBUG
|
353
400
|
end # unless (file is out of date)
|
354
401
|
end # def build
|
355
402
|
|
356
|
-
|
357
|
-
def initialize(mod)
|
358
|
-
@mod = mod
|
359
|
-
if @mod then
|
360
|
-
# Figure out which script file defined the C code
|
361
|
-
|
362
|
-
real_caller = caller[2]
|
363
|
-
real_caller = caller[5] if real_caller =~ /\(eval\)/
|
364
|
-
real_caller = real_caller.split(/:/).first
|
365
|
-
|
366
|
-
@rb_file = File.expand_path(real_caller) # [MS]
|
367
|
-
|
368
|
-
# Extract the basename of the script and clean it up to be
|
369
|
-
# a valid C identifier
|
370
|
-
rb_script_name = File.basename(@rb_file).gsub(/[^a-zA-Z0-9_]/,'_')
|
371
|
-
# Hash the full path to the script
|
372
|
-
suffix = Digest::MD5.new(@rb_file).to_s[0,4]
|
373
|
-
@mod_name = "Inline_#{@mod.name.gsub('::','__')}_#{rb_script_name}_#{suffix}"
|
374
|
-
@so_name = "#{Inline.directory}/#{@mod_name}.#{Config::CONFIG["DLEXT"]}"
|
375
|
-
end
|
376
|
-
@src = []
|
377
|
-
@sig = {}
|
378
|
-
@flags = []
|
379
|
-
@libs = []
|
380
|
-
end
|
381
|
-
|
403
|
+
##
|
382
404
|
# Adds compiler options to the compiler command line. No
|
383
405
|
# preprocessing is done, so you must have all your dashes and
|
384
406
|
# everything.
|
@@ -387,6 +409,7 @@ module Inline
|
|
387
409
|
@flags.push(*flags)
|
388
410
|
end
|
389
411
|
|
412
|
+
##
|
390
413
|
# Adds linker flags to the link command line. No preprocessing is
|
391
414
|
# done, so you must have all your dashes and everything.
|
392
415
|
|
@@ -394,14 +417,15 @@ module Inline
|
|
394
417
|
@libs.push(*flags)
|
395
418
|
end
|
396
419
|
|
397
|
-
|
398
|
-
#
|
420
|
+
##
|
421
|
+
# Registers C type-casts +r2c+ and +c2r+ for +type+.
|
399
422
|
|
400
423
|
def add_type_converter(type, r2c, c2r)
|
401
424
|
$stderr.puts "WARNING: overridding #{type}" if @@type_map.has_key? type
|
402
425
|
@@type_map[type] = [r2c, c2r]
|
403
426
|
end
|
404
427
|
|
428
|
+
##
|
405
429
|
# Adds an include to the top of the file. Don't forget to use
|
406
430
|
# quotes or angle brackets.
|
407
431
|
|
@@ -409,12 +433,14 @@ module Inline
|
|
409
433
|
@src << "#include #{header}"
|
410
434
|
end
|
411
435
|
|
436
|
+
##
|
412
437
|
# Adds any amount of text/code to the source
|
413
438
|
|
414
439
|
def prefix(code)
|
415
440
|
@src << code
|
416
441
|
end
|
417
442
|
|
443
|
+
##
|
418
444
|
# Adds a C function to the source, including performing automatic
|
419
445
|
# type conversion to arguments and the return value. Unknown type
|
420
446
|
# conversions can be extended by using +add_type_converter+.
|
@@ -423,10 +449,14 @@ module Inline
|
|
423
449
|
self.generate(src,:expand_types=>true)
|
424
450
|
end
|
425
451
|
|
452
|
+
##
|
453
|
+
# Same as +c+, but adds a class function.
|
454
|
+
|
426
455
|
def c_singleton src
|
427
456
|
self.generate(src,:expand_types=>true,:singleton=>true)
|
428
457
|
end
|
429
458
|
|
459
|
+
##
|
430
460
|
# Adds a raw C function to the source. This version does not
|
431
461
|
# perform any type conversion and must conform to the ruby/C
|
432
462
|
# coding conventions.
|
@@ -435,6 +465,9 @@ module Inline
|
|
435
465
|
self.generate(src)
|
436
466
|
end
|
437
467
|
|
468
|
+
##
|
469
|
+
# Same as +c_raw+, but adds a class function.
|
470
|
+
|
438
471
|
def c_raw_singleton src
|
439
472
|
self.generate(src, :singleton=>true)
|
440
473
|
end
|
@@ -516,6 +549,7 @@ end # module Inline
|
|
516
549
|
|
517
550
|
class Module
|
518
551
|
|
552
|
+
##
|
519
553
|
# Extends the Module class to have an inline method. The default
|
520
554
|
# language/builder used is C, but can be specified with the +lang+
|
521
555
|
# parameter.
|
@@ -544,7 +578,8 @@ end
|
|
544
578
|
|
545
579
|
class File
|
546
580
|
|
547
|
-
|
581
|
+
##
|
582
|
+
# Equivalent to +File::open+ with an associated block, but moves
|
548
583
|
# any existing file with the same name to the side first.
|
549
584
|
|
550
585
|
def self.write_with_backup(path) # returns true if file already existed
|
@@ -566,6 +601,7 @@ end # class File
|
|
566
601
|
|
567
602
|
class Dir
|
568
603
|
|
604
|
+
##
|
569
605
|
# +assert_secure+ checks to see that +path+ exists and has minimally
|
570
606
|
# writable permissions. If not, it prints an error and exits. It
|
571
607
|
# only works on +POSIX+ systems. Patches for other systems are
|
data/test_inline.rb
CHANGED
@@ -96,7 +96,7 @@ class TestC < InlineTestCase
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def test_ruby2c
|
99
|
-
x = Inline::C.new(
|
99
|
+
x = Inline::C.new(self.class)
|
100
100
|
assert_equal 'NUM2CHR', x.ruby2c("char")
|
101
101
|
assert_equal 'STR2CSTR', x.ruby2c("char *")
|
102
102
|
assert_equal 'FIX2INT', x.ruby2c("int")
|
@@ -111,7 +111,7 @@ class TestC < InlineTestCase
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def test_c2ruby
|
114
|
-
x = Inline::C.new(
|
114
|
+
x = Inline::C.new(self.class)
|
115
115
|
assert_equal 'CHR2FIX', x.c2ruby("char")
|
116
116
|
assert_equal 'rb_str_new2', x.c2ruby("char *")
|
117
117
|
assert_equal 'INT2FIX', x.c2ruby("int")
|
@@ -125,6 +125,35 @@ class TestC < InlineTestCase
|
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
|
+
def util_module_name(*signatures)
|
129
|
+
md5 = Digest::MD5.new
|
130
|
+
builder = Inline::C.new(self.class)
|
131
|
+
|
132
|
+
signatures.each do |signature|
|
133
|
+
builder.sig[signature] = [nil, 0]
|
134
|
+
md5 << signature.to_s
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_equal("Inline_TestInline__TestC_#{md5.to_s[0,4]}",
|
138
|
+
builder.module_name)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_module_name_0_methods
|
142
|
+
util_module_name
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_module_name_1_method
|
146
|
+
util_module_name :something1
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_module_name_2_methods
|
150
|
+
util_module_name :something2, :something3
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_module_name_2_other_methods
|
154
|
+
util_module_name :something4, :something5
|
155
|
+
end
|
156
|
+
|
128
157
|
def util_parse_signature(src, expected, t=nil, a=nil, b=nil)
|
129
158
|
|
130
159
|
result = nil
|
@@ -549,8 +578,8 @@ class TestModule < InlineTestCase
|
|
549
578
|
def test_nested
|
550
579
|
Object.class_eval $test_module_code
|
551
580
|
fb = Foo::Bar.new
|
552
|
-
assert_equal(fb.forty_two_instance
|
553
|
-
assert_equal(Foo::Bar.twenty_four_class
|
581
|
+
assert_equal(42, fb.forty_two_instance)
|
582
|
+
assert_equal(24, Foo::Bar.twenty_four_class)
|
554
583
|
|
555
584
|
tempfile = Tempfile.new("test_inline_nested")
|
556
585
|
tempfile.write($test_module_code2)
|
@@ -558,8 +587,8 @@ class TestModule < InlineTestCase
|
|
558
587
|
tempfile.rewind
|
559
588
|
`cp #{tempfile.path} #{tempfile.path}.rb`
|
560
589
|
require "#{tempfile.path}.rb"
|
561
|
-
assert_equal(fb.twelve_instance
|
562
|
-
assert_equal(Foo::Bar.twelve_class
|
590
|
+
assert_equal(12, fb.twelve_instance)
|
591
|
+
assert_equal(12, Foo::Bar.twelve_class)
|
563
592
|
`rm "#{tempfile.path}.rb"`
|
564
593
|
end
|
565
594
|
|
@@ -569,9 +598,8 @@ class TestModule < InlineTestCase
|
|
569
598
|
end
|
570
599
|
assert(test(?d, Inline.directory),
|
571
600
|
"inline dir should have been created")
|
572
|
-
matches = Dir[File.join(Inline.directory, "
|
573
|
-
assert_equal(matches.length,
|
574
|
-
"Source should have been created")
|
601
|
+
matches = Dir[File.join(Inline.directory, "Inline_TestModule_*.c")]
|
602
|
+
assert_equal(1, matches.length, "Source should have been created")
|
575
603
|
library_file = matches.first.gsub(/\.c$/) { "." + Config::CONFIG["DLEXT"] }
|
576
604
|
assert(test(?f, library_file),
|
577
605
|
"Library file should have been created")
|
metadata
CHANGED