RubyInline 3.3.1 → 3.3.2

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.
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
  - "."