RubyInline 3.1.0 → 3.2.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.
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