RubyInline 3.3.1 → 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/History.txt +8 -0
  2. data/README.txt +1 -0
  3. data/inline.rb +84 -48
  4. data/test_inline.rb +37 -9
  5. metadata +2 -2
@@ -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
@@ -1,6 +1,7 @@
1
1
  ** Ruby Inline
2
2
 
3
3
  http://www.zenspider.com/ZSS/Products/RubyInline/
4
+ http://rubyforge.org/projects/rubyinline/
4
5
  support@zenspider.com
5
6
 
6
7
  ** DESCRIPTION:
data/inline.rb CHANGED
@@ -22,7 +22,7 @@
22
22
  #
23
23
  # = DESCRIPTION
24
24
  #
25
- # Inline allows you to write C/C++ code within your ruby code. It
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.1'
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 signature (prefix)
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 - 1} \"#{file}\"\n" + result
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(@so_name))
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 "#{@so_name}" or raise LoadError, "require on #{@so_name} failed"
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
- real_caller = caller[1]
257
- real_caller = caller[4] if real_caller =~ /\(eval\)/
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(@rb_file) < File.mtime(@so_name)
308
+ unless so_exists and File.mtime(rb_file) < File.mtime(so_name)
263
309
 
264
- src_name = "#{Inline.directory}/#{@mod_name}.c"
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_#{@mod_name}() {"
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, @so_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 #{@so_name} #{src_name} #{libs}"
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_#{@mod_name}"
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 #{@so_name} with '#{cmd}'" if $DEBUG
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 "#{@so_name} is up to date" if $DEBUG
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
- attr_reader :mod
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
- # Registers C type-casts <tt>r2c</tt> and <tt>c2r</tt> for
398
- # <tt>type</tt>.
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
- # Equivalent to <tt>File::open</tt> with an associated block, but moves
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
@@ -96,7 +96,7 @@ class TestC < InlineTestCase
96
96
  end
97
97
 
98
98
  def test_ruby2c
99
- x = Inline::C.new(nil)
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(nil)
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, 42)
553
- assert_equal(Foo::Bar.twenty_four_class, 24)
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,12)
562
- assert_equal(Foo::Bar.twelve_class,12)
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, "Inline_TestModule_test_inline_rb_*.c")]
573
- assert_equal(matches.length,1,
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
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: RubyInline
5
5
  version: !ruby/object:Gem::Version
6
- version: 3.3.1
7
- date: 2005-05-03
6
+ version: 3.3.2
7
+ date: 2005-05-19
8
8
  summary: Multi-language extension coding within ruby.
9
9
  require_paths:
10
10
  - "."