RubyInline 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,7 +1,23 @@
1
+ *** 3.2.0 / 2004-11-27
2
+
3
+ + 8 minor enhancements
4
+ + Gemified
5
+ + Added #line preprocessor directives to make debugging inside your ruby file practical.
6
+ + Added uninstall rule to Makefile
7
+ + Inline::C now generates classes directly instead of included modules.
8
+ + Better execeptions are thrown on error.
9
+ + Incorporated a bunch of changes from Jonathan Paisley:
10
+ + Generation of inline'd class methods. (c_singleton and c_raw_singleton)
11
+ + Fixed problems with nested module/classes.
12
+ + Inline can now extend the same class multiple times.
13
+ + 2 bug fixes
14
+ + Smarter require/instantiation to accomodate other languages better.
15
+ + Fixed a logic error where running good code, then bad, then bad again ran the original good code.
16
+
1
17
  *** 3.1.0 / 2004-09-24
2
18
 
3
19
  + 2 minor enhancement
4
- Extended API of Inline::C with prefix(code).
20
+ + Extended API of Inline::C with prefix(code).
5
21
  + Documented all public API.
6
22
  + 2 bug fixes
7
23
  + Cleaned a lot of code and tests.
data/Makefile CHANGED
@@ -1,5 +1,6 @@
1
1
  RUBY?=/usr/local/bin/ruby
2
2
  RDOC?=rdoc18
3
+ RUBYLIB=$(shell $(RUBY) -rrbconfig -e 'include Config; print CONFIG["sitelibdir"]')
3
4
 
4
5
  test:
5
6
  $(RUBY) -I. -w ./test_inline.rb
@@ -28,10 +29,14 @@ bench:
28
29
  @$(RUBY) -I. ./example.rb 2 2> /dev/null
29
30
 
30
31
  install:
31
- @where=`$(RUBY) -rrbconfig -e 'include Config; print CONFIG["sitelibdir"]'`; \
32
- echo "installing inline.rb in $$where"; \
33
- cp -f inline.rb $$where; \
32
+ echo "installing inline.rb in $(RUBYLIB)"; \
33
+ cp -f inline.rb $(RUBYLIB);
34
34
  echo Installed
35
35
 
36
+ uninstall:
37
+ echo "Removing inline.rb from $(RUBYLIB)"; \
38
+ rm $(RUBYLIB)/inline.rb;
39
+ echo Removed
40
+
36
41
  clean:
37
42
  rm -rf *~ doc ~/.ruby_inline
data/README.txt CHANGED
@@ -5,22 +5,22 @@
5
5
 
6
6
  ** DESCRIPTION:
7
7
 
8
- Ruby Inline is my quick attempt to create an analog to Perl's
9
- Inline::C. It allows you to embed C or C++ external module code in
10
- your ruby script directly. The code is compiled and run on the fly
11
- when needed. The ruby version isn't near as feature-full as the perl
12
- version, but it is neat!
8
+ Ruby Inline is an analog to Perl's Inline::C. Out of the box, it
9
+ allows you to embed C/++ external module code in your ruby script
10
+ directly. By writing simple builder classes, you can teach how to cope
11
+ with new languages (fortran, perl, whatever). The code is compiled and
12
+ run on the fly when needed.
13
13
 
14
14
  ** FEATURES/PROBLEMS:
15
15
 
16
16
  + Quick and easy inlining of your C or C++ code embedded in your ruby script.
17
- + Rudimentary automatic conversion between ruby and C basic types
18
- (char, unsigned, unsigned int, char *, int, long, unsigned long).
17
+ + Extendable to work with other languages.
18
+ + Automatic conversion between ruby and C basic types
19
+ + char, unsigned, unsigned int, char *, int, long, unsigned long
19
20
  + inline_c_raw exists for when the automatic conversion isn't sufficient.
20
21
  + Only recompiles if the inlined code has changed.
21
22
  + Pretends to be secure.
22
23
  + Only uses standard ruby libraries, nothing extra to download.
23
- + Simple as it can be. Less than 230 lines long... um... sorta simple.
24
24
 
25
25
  ** SYNOPSYS:
26
26
 
@@ -82,10 +82,11 @@ version, but it is neat!
82
82
 
83
83
  ** REQUIREMENTS:
84
84
 
85
- + Ruby - 1.6.7 & 1.7.2 has been used on FreeBSD 4.6 and MacOSX.
85
+ + Ruby - 1.6.7 & 1.8.2 has been used on FreeBSD 4.6+ and MacOSX.
86
86
  + POSIX compliant system (ie pretty much any UNIX, or Cygwin on MS platforms).
87
87
  + A C/C++ compiler (the same one that compiled your ruby interpreter).
88
88
  + test::unit for running tests ( http://testunit.talbott.ws/ ).
89
+ + rubygems if you'd like.
89
90
 
90
91
  ** INSTALL:
91
92
 
data/example.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  #!/usr/local/bin/ruby -w
2
2
 
3
- require "inline"
3
+ begin
4
+ require 'rubygems'
5
+ require_gem "RubyInline"
6
+ rescue LoadError
7
+ require 'inline'
8
+ end
4
9
 
5
10
  class MyTest
6
11
 
data/inline.gemspec CHANGED
@@ -11,6 +11,7 @@ spec = Gem::Specification.new do |s|
11
11
 
12
12
  paragraphs = File.read("README.txt").split(/\n\n+/)
13
13
  s.description = paragraphs[3]
14
+ puts s.description
14
15
 
15
16
  s.requirements << "A POSIX environment and a compiler for your language."
16
17
  s.files = IO.readlines("Manifest.txt").map {|f| f.chomp }
data/inline.rb CHANGED
@@ -32,16 +32,19 @@
32
32
 
33
33
  require "rbconfig"
34
34
  require "ftools"
35
+ require "digest/md5"
35
36
 
36
37
  $TESTING = false unless defined? $TESTING
37
38
 
39
+ class CompilationError < RuntimeError; end
40
+
38
41
  # The Inline module is the top-level module used. It is responsible
39
42
  # for instantiating the builder for the right language used,
40
43
  # compilation/linking when needed, and loading the inlined code into
41
44
  # the current namespace.
42
45
 
43
46
  module Inline
44
- VERSION = '3.1.0'
47
+ VERSION = '3.2.0'
45
48
 
46
49
  $stderr.puts "RubyInline v #{VERSION}" if $DEBUG
47
50
 
@@ -96,12 +99,12 @@ module Inline
96
99
  }
97
100
 
98
101
  def ruby2c(type)
99
- raise "Unknown type #{type}" unless @@type_map.has_key? type
102
+ raise ArgumentError, "Unknown type #{type}" unless @@type_map.has_key? type
100
103
  @@type_map[type].first
101
104
  end
102
105
 
103
106
  def c2ruby(type)
104
- raise "Unknown type #{type}" unless @@type_map.has_key? type
107
+ raise ArgumentError, "Unknown type #{type}" unless @@type_map.has_key? type
105
108
  @@type_map[type].last
106
109
  end
107
110
 
@@ -152,11 +155,17 @@ module Inline
152
155
  }
153
156
  end
154
157
 
155
- raise "Bad parser exception: #{sig}"
158
+ raise SyntaxError, "Can't parse signature: #{sig}"
156
159
  end # def parse_signature
157
160
 
158
- def generate(src, expand_types=true)
161
+ def generate(src, options={})
162
+
163
+ if not Hash === options then
164
+ options = {:expand_types=>options}
165
+ end
159
166
 
167
+ expand_types = options[:expand_types]
168
+ singleton = options[:singleton]
160
169
  result = self.strip_comments(src)
161
170
 
162
171
  signature = parse_signature(src, !expand_types)
@@ -190,7 +199,7 @@ module Inline
190
199
  result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
191
200
  result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
192
201
  unless return_type == "void" then
193
- raise "couldn't find return statement for #{function_name}" unless
202
+ raise SyntaxError, "Couldn't find return statement for #{function_name}" unless
194
203
  result =~ /return/
195
204
  result.gsub!(/return\s+([^\;\}]+)/) do
196
205
  "return #{c2ruby(return_type)}(#{$1})"
@@ -204,8 +213,11 @@ module Inline
204
213
  result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
205
214
  end
206
215
 
216
+ file, line = caller[1].split(/:/)
217
+ result = "# line #{line.to_i - 1} \"#{file}\"\n" + result
218
+
207
219
  @src << result
208
- @sig[function_name] = arity
220
+ @sig[function_name] = [arity,singleton]
209
221
 
210
222
  return result if $TESTING
211
223
  end # def generate
@@ -215,14 +227,14 @@ module Inline
215
227
  public
216
228
 
217
229
  def load
218
- require "#{@so_name}" or raise "require on #{@so_name} failed"
219
- @mod.class_eval "include #{@mod_name}"
230
+ require "#{@so_name}" or raise LoadError, "require on #{@so_name} failed"
220
231
  end
221
232
 
222
233
  def build
223
234
  rb_file = File.expand_path(caller[1].split(/:/).first) # [MS]
235
+ so_exists = File.file? @so_name
224
236
 
225
- unless File.file? @so_name and File.mtime(rb_file) < File.mtime(@so_name)
237
+ unless so_exists and File.mtime(@rb_file) < File.mtime(@so_name)
226
238
 
227
239
  src_name = "#{Inline.directory}/#{@mod_name}.c"
228
240
  old_src_name = "#{src_name}.old"
@@ -233,15 +245,21 @@ module Inline
233
245
  io.puts @src.join("\n\n")
234
246
  io.puts
235
247
  io.puts
236
- io.puts " VALUE c#{@mod_name};"
237
248
  io.puts "#ifdef __cplusplus"
238
249
  io.puts "extern \"C\" {"
239
250
  io.puts "#endif"
240
251
  io.puts " void Init_#{@mod_name}() {"
241
- io.puts " c#{@mod_name} = rb_define_module(\"#{@mod_name}\");"
252
+ io.puts " VALUE c = rb_cObject;"
253
+ @mod.name.split("::").each do |n|
254
+ io.puts " c = rb_const_get_at(c,rb_intern(\"#{n}\"));"
255
+ end
242
256
  @sig.keys.sort.each do |name|
243
- arity = @sig[name]
244
- io.print " rb_define_method(c#{@mod_name}, \"#{name}\", "
257
+ arity, singleton = @sig[name]
258
+ if singleton then
259
+ io.print " rb_define_singleton_method(c, \"#{name}\", "
260
+ else
261
+ io.print " rb_define_method(c, \"#{name}\", "
262
+ end
245
263
  io.puts "(VALUE(*)(ANYARGS))#{name}, #{arity});"
246
264
  end
247
265
  io.puts
@@ -254,13 +272,15 @@ module Inline
254
272
 
255
273
  # recompile only if the files are different
256
274
  recompile = true
257
- if should_compare and File::compare(old_src_name, src_name, $DEBUG) then
275
+ if so_exists and should_compare and
276
+ File::compare(old_src_name, src_name, $DEBUG) then
258
277
  recompile = false
259
278
 
260
279
  # Updates the timestamps on all the generated/compiled files.
261
280
  # Prevents us from entering this conditional unless the source
262
281
  # file changes again.
263
- File.utime(Time.now, Time.now, src_name, old_src_name, @so_name)
282
+ t = Time.now
283
+ File.utime(t, t, src_name, old_src_name, @so_name)
264
284
  end
265
285
 
266
286
  if recompile then
@@ -287,10 +307,16 @@ module Inline
287
307
  if /mswin32/ =~ RUBY_PLATFORM then
288
308
  cmd += " -link /INCREMENTAL:no /EXPORT:Init_#{@mod_name}"
289
309
  end
310
+
311
+ cmd += " 2> /dev/null" if $TESTING
290
312
 
291
313
  $stderr.puts "Building #{@so_name} with '#{cmd}'" if $DEBUG
292
314
  `#{cmd}`
293
- raise "error executing #{cmd}: #{$?}" if $? != 0
315
+ if $? != 0 then
316
+ bad_src_name = src_name + ".bad"
317
+ File.rename src_name, bad_src_name
318
+ raise CompilationError, "error executing #{cmd}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
319
+ end
294
320
  $stderr.puts "Built successfully" if $DEBUG
295
321
  end
296
322
 
@@ -299,10 +325,20 @@ module Inline
299
325
  end # unless (file is out of date)
300
326
  end # def build
301
327
 
328
+ attr_reader :mod
302
329
  def initialize(mod)
303
330
  @mod = mod
304
- @mod_name = "Mod_#{@mod}"
305
- @so_name = "#{Inline.directory}/#{@mod_name}.#{Config::CONFIG["DLEXT"]}"
331
+ if @mod then
332
+ # Figure out which script file defined the C code
333
+ @rb_file = File.expand_path(caller[2].split(/:/).first) # [MS]
334
+ # Extract the basename of the script and clean it up to be
335
+ # a valid C identifier
336
+ rb_script_name = File.basename(@rb_file).gsub(/[^a-zA-Z0-9_]/,'_')
337
+ # Hash the full path to the script
338
+ suffix = Digest::MD5.new(@rb_file).to_s[0,4]
339
+ @mod_name = "Inline_#{@mod.name.gsub('::','__')}_#{rb_script_name}_#{suffix}"
340
+ @so_name = "#{Inline.directory}/#{@mod_name}.#{Config::CONFIG["DLEXT"]}"
341
+ end
306
342
  @src = []
307
343
  @sig = {}
308
344
  @flags = []
@@ -350,7 +386,11 @@ module Inline
350
386
  # conversions can be extended by using +add_type_converter+.
351
387
 
352
388
  def c src
353
- self.generate(src)
389
+ self.generate(src,:expand_types=>true)
390
+ end
391
+
392
+ def c_singleton src
393
+ self.generate(src,:expand_types=>true,:singleton=>true)
354
394
  end
355
395
 
356
396
  # Adds a raw C function to the source. This version does not
@@ -358,7 +398,11 @@ module Inline
358
398
  # coding conventions.
359
399
 
360
400
  def c_raw src
361
- self.generate(src, false)
401
+ self.generate(src)
402
+ end
403
+
404
+ def c_raw_singleton src
405
+ self.generate(src, :singleton=>true)
362
406
  end
363
407
 
364
408
  end # class Inline::C
@@ -371,8 +415,15 @@ class Module
371
415
  # parameter.
372
416
 
373
417
  def inline(lang = :C, testing=false)
374
- require "inline/#{lang}" unless lang == :C
375
- builder = Inline.const_get(lang).new self
418
+
419
+ begin
420
+ builder_class = Inline.const_get(lang)
421
+ rescue NameError
422
+ require "inline/#{lang}"
423
+ builder_class = Inline.const_get(lang)
424
+ end
425
+
426
+ builder = builder_class.new self
376
427
 
377
428
  yield builder
378
429
 
@@ -417,9 +468,9 @@ class Dir
417
468
  mode = File.stat(path).mode
418
469
  unless ((mode % 01000) & 0022) == 0 then
419
470
  if $TESTING then
420
- raise 'InsecureDir'
471
+ raise SecurityError, "Directory #{path} is insecure"
421
472
  else
422
- $stderr.puts "#{path} is insecure (#{sprintf('%o', mode)}), needs 0700 for perms"
473
+ $stderr.puts "#{path} is insecure (#{sprintf('%o', mode)}), needs 0700 for perms. Exiting."
423
474
  exit 1
424
475
  end
425
476
  end
data/test_inline.rb CHANGED
@@ -1,16 +1,13 @@
1
- #!/usr/bin/ruby -w
1
+ #!/usr/local/bin/ruby -w
2
2
 
3
3
  $TESTING = true
4
4
 
5
5
  require 'inline'
6
+ require 'tempfile'
6
7
  require 'test/unit'
7
8
 
8
9
  File.umask(0)
9
10
 
10
- #class TestFile < Test::Unit::TestCase
11
- # TODO def test_write_with_backup
12
- #end
13
-
14
11
  class TestDir < Test::Unit::TestCase
15
12
 
16
13
  def setup
@@ -32,7 +29,7 @@ class TestDir < Test::Unit::TestCase
32
29
  Dir.assert_secure path
33
30
  end
34
31
  else
35
- assert_raises(perms.nil? ? Errno::ENOENT : RuntimeError) do
32
+ assert_raises(perms.nil? ? Errno::ENOENT : SecurityError) do
36
33
  Dir.assert_secure path
37
34
  end
38
35
  end
@@ -103,7 +100,7 @@ class TestC < Test::Unit::TestCase
103
100
  assert_equal 'NUM2UINT', x.ruby2c("unsigned long")
104
101
  assert_equal 'NUM2UINT', x.ruby2c("unsigned")
105
102
 
106
- assert_raises RuntimeError do
103
+ assert_raises ArgumentError do
107
104
  x.ruby2c('blah')
108
105
  end
109
106
  end
@@ -118,7 +115,7 @@ class TestC < Test::Unit::TestCase
118
115
  assert_equal 'UINT2NUM', x.c2ruby("unsigned long")
119
116
  assert_equal 'UINT2NUM', x.c2ruby("unsigned")
120
117
 
121
- assert_raises RuntimeError do
118
+ assert_raises ArgumentError do
122
119
  x.c2ruby('blah')
123
120
  end
124
121
  end
@@ -216,6 +213,8 @@ class TestC < Test::Unit::TestCase
216
213
  inline do |builder|
217
214
  result = builder.generate src, expand_types
218
215
  end
216
+ result.gsub!(/\# line \d+/, '# line N')
217
+ expected = '# line N "./test_inline.rb"' + "\n" + expected
219
218
  assert_equal(expected, result)
220
219
  end
221
220
 
@@ -425,7 +424,9 @@ puts(s); return rb_str_new2(s)}"
425
424
  result = builder.c "int add(int a, int b) { return a + b; }"
426
425
  end
427
426
 
428
- expected = "static VALUE add(VALUE self, VALUE _a, VALUE _b) {\n int a = FIX2INT(_a);\n int b = FIX2INT(_b);\n return INT2FIX(a + b); }"
427
+ expected = "# line N \"./test_inline.rb\"\nstatic VALUE add(VALUE self, VALUE _a, VALUE _b) {\n int a = FIX2INT(_a);\n int b = FIX2INT(_b);\n return INT2FIX(a + b); }"
428
+
429
+ result.gsub!(/\# line \d+/, '# line N')
429
430
 
430
431
  assert_equal expected, result
431
432
  assert_equal [expected], builder.src
@@ -439,19 +440,103 @@ puts(s); return rb_str_new2(s)}"
439
440
  result = builder.c_raw src.dup
440
441
  end
441
442
 
442
- expected = src
443
+ result.gsub!(/\# line \d+/, '# line N')
444
+ expected = "# line N \"./test_inline.rb\"\n" + src
443
445
 
444
446
  assert_equal expected, result
445
447
  assert_equal [expected], builder.src
446
448
  end
447
449
 
448
- # I have _no_ idea how to test these
449
- # TODO def test_build
450
- # TODO def test_load
450
+ def util_simple_code(klassname, c_src)
451
+ result = "
452
+ require 'inline'
453
+
454
+ class #{klassname}
455
+ inline do |builder|
456
+ builder.c <<-EOC
457
+ #{c_src}
458
+ EOC
459
+ end
460
+ end"
461
+ result
462
+ end
463
+
464
+ def util_test_build(src)
465
+ tempfile = Tempfile.new("util_test_build")
466
+ tempfile.write src
467
+ tempfile.flush
468
+ tempfile.rewind
469
+ rb_file = tempfile.path + ".rb"
470
+ File.rename tempfile.path, rb_file
471
+ begin
472
+ Kernel.module_eval { require rb_file }
473
+ yield if block_given?
474
+ rescue Exception => err
475
+ raise err
476
+ ensure
477
+ File.unlink rb_file
478
+ end
479
+ end
480
+
481
+ def test_build_good
482
+ code = util_simple_code(:DumbTest1, "long dumbpi() { return 314; }")
483
+ util_test_build(code) do
484
+ result = DumbTest1.new.dumbpi
485
+ assert_equal(314, result)
486
+ end
487
+ end
488
+
489
+ def test_build_bad
490
+ code = util_simple_code(:DumbTest2, "void should_puke() { 1+1 2+2 }")
491
+ assert_raises(CompilationError) do
492
+ util_test_build(code) do
493
+ flunk
494
+ end
495
+ end
496
+ end
497
+
498
+ def test_load
499
+ # totally tested by test_build
500
+ end
451
501
 
452
502
  end # class TestC
453
503
  end # class TestInline
454
504
 
505
+ $test_module_code = <<-EOR
506
+ module Foo
507
+ class Bar
508
+ inline do |builder|
509
+ builder.c <<-EOC
510
+ static int forty_two_instance() { return 42; }
511
+ EOC
512
+ builder.c_singleton <<-EOC
513
+ static int twenty_four_class() { return 24; }
514
+ EOC
515
+ end
516
+ end
517
+ end
518
+ EOR
519
+
520
+ $test_module_code2 = <<-EOR
521
+ require 'inline'
522
+
523
+ # Demonstrates native functions in nested classes and
524
+ # extending a class more than once from different ruby
525
+ # source files
526
+ module Foo
527
+ class Bar
528
+ inline do |builder|
529
+ builder.c <<-EOC
530
+ int twelve_instance() { return 12; }
531
+ EOC
532
+ builder.c_singleton <<-EOC
533
+ int twelve_class() { return 12; }
534
+ EOC
535
+ end
536
+ end
537
+ end
538
+ EOR
539
+
455
540
  class TestModule < Test::Unit::TestCase
456
541
 
457
542
  def setup
@@ -463,19 +548,35 @@ class TestModule < Test::Unit::TestCase
463
548
  `rm -rf #{@rootdir}` unless $DEBUG
464
549
  end
465
550
 
551
+ def test_nested
552
+ Object.class_eval $test_module_code
553
+ fb = Foo::Bar.new
554
+ assert_equal(fb.forty_two_instance, 42)
555
+ assert_equal(Foo::Bar.twenty_four_class, 24)
556
+
557
+ tempfile = Tempfile.new("test_inline_nested")
558
+ tempfile.write($test_module_code2)
559
+ tempfile.flush
560
+ tempfile.rewind
561
+ `cp #{tempfile.path} #{tempfile.path}.rb`
562
+ require "#{tempfile.path}.rb"
563
+ assert_equal(fb.twelve_instance,12)
564
+ assert_equal(Foo::Bar.twelve_class,12)
565
+ `rm "#{tempfile.path}.rb"`
566
+ end
567
+
466
568
  def test_inline
467
569
  self.class.inline(:C) do |builder|
468
570
  builder.c "int add(int a, int b) { return a + b; }"
469
571
  end
470
572
  assert(test(?d, Inline.directory),
471
573
  "inline dir should have been created")
472
- assert(test(?f, File.join(Inline.directory, "Mod_TestModule.c")),
473
- "Source should have been created")
474
- assert(test(?f, File.join(Inline.directory,
475
- "Mod_TestModule.#{Config::CONFIG["DLEXT"]}")),
574
+ matches = Dir[File.join(Inline.directory, "Inline_TestModule_test_inline_rb_*.c")]
575
+ assert_equal(matches.length,1,
476
576
  "Source should have been created")
577
+ library_file = matches.first.gsub(/\.c$/) { "." + Config::CONFIG["DLEXT"] }
578
+ assert(test(?f, library_file),
579
+ "Library file should have been created")
477
580
  end
478
581
 
479
582
  end
480
-
481
- # Number of errors detected: 4
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.1
3
3
  specification_version: 1
4
4
  name: RubyInline
5
5
  version: !ruby/object:Gem::Version
6
- version: 3.1.0
7
- date: 2004-11-19
6
+ version: 3.2.0
7
+ date: 2004-11-27
8
8
  summary: Multi-language extension coding within ruby.
9
9
  require_paths:
10
10
  - "."
@@ -12,10 +12,10 @@ author: Ryan Davis
12
12
  email: ryand-ruby@zenspider.com
13
13
  homepage: http://www.zenspider.com/ZSS/Products/RubyInline/
14
14
  rubyforge_project: rubyinline
15
- description: "Ruby Inline is my quick attempt to create an analog to Perl's Inline::C. It
16
- allows you to embed C or C++ external module code in your ruby script directly.
17
- The code is compiled and run on the fly when needed. The ruby version isn't near
18
- as feature-full as the perl version, but it is neat!"
15
+ description: "Ruby Inline is an analog to Perl's Inline::C. Out of the box, it allows you to
16
+ embed C/++ external module code in your ruby script directly. By writing simple
17
+ builder classes, you can teach how to cope with new languages (fortran, perl,
18
+ whatever). The code is compiled and run on the fly when needed."
19
19
  autorequire: inline
20
20
  default_executable:
21
21
  bindir: bin