Class: Inline::C

Inherits:
Object
  • Object
show all
Includes:
ZenTestMapping
Defined in:
lib/inline.rb

Overview

Inline::C is the default builder used and the only one provided by Inline. It can be used as a template to write builders for other languages. It understands type-conversions for the basic types and can be extended as needed using #add_type_converter, #alias_type_converter and #remove_type_converter.

Constant Summary collapse

MAGIC_ARITY_THRESHOLD =
15
MAGIC_ARITY =
-1
TYPE_MAP =

Default C to ruby and ruby to C type map

{
  'char'               => [ 'NUM2CHR',        'CHR2FIX'      ],

  'char *'             => [ 'StringValuePtr', 'rb_str_new2'  ],

  'double'             => [ 'NUM2DBL',        'rb_float_new' ],

  'int'                => [ "FI\X2INT",       'INT2FIX'      ],
  'unsigned int'       => [ 'NUM2UINT',       'UINT2NUM'     ],
  'unsigned'           => [ 'NUM2UINT',       'UINT2NUM'     ],

  'long'               => [ 'NUM2LONG',       'LONG2NUM'     ],
  'unsigned long'      => [ 'NUM2ULONG',      'ULONG2NUM'    ],

  'long long'          => [ 'NUM2LL',         'LL2NUM'       ],
  'unsigned long long' => [ 'NUM2ULL',        'ULL2NUM'      ],

  'off_t'              => [ 'NUM2OFFT',       'OFFT2NUM'     ],

  'VALUE'              => [ '',               ''             ],
  # Can't do these converters because they conflict with the above:
  # ID2SYM(x), SYM2ID(x), F\IX2UINT(x)
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mod) ⇒ C

Returns a new instance of C.

Raises:

  • (ArgumentError)


399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/inline.rb', line 399

def initialize(mod)
  raise ArgumentError, "Class/Module arg is required" unless Module === mod
  # new (but not on some 1.8s) -> inline -> real_caller|eval
  stack = caller
  meth = stack.shift until meth =~ /in .(inline|test_|setup)/ or stack.empty?
  raise "Couldn't discover caller" if stack.empty?
  real_caller = stack.first
  real_caller = stack[3] if real_caller =~ /\(eval\)/
  real_caller =~ /(.*):(\d+)/
  real_caller = $1
  @rb_file = File.expand_path real_caller

  @mod = mod
  @pre = []
  @src = []
  @inc = []
  @sig = {}
  @flags = []
  @libs = []
  @init_extra = []
  @include_ruby_first = true
  @inherited_methods = {}
  @struct_name = nil

  @type_map = TYPE_MAP.dup
end

Instance Attribute Details

#flagsObject

Returns the value of attribute flags.



391
392
393
# File 'lib/inline.rb', line 391

def flags
  @flags
end

#init_extraObject

Returns the value of attribute init_extra.



391
392
393
# File 'lib/inline.rb', line 391

def init_extra
  @init_extra
end

#libsObject

Returns the value of attribute libs.



391
392
393
# File 'lib/inline.rb', line 391

def libs
  @libs
end

#modObject

Returns the value of attribute mod.



389
390
391
# File 'lib/inline.rb', line 389

def mod
  @mod
end

#preObject

Returns the value of attribute pre.



391
392
393
# File 'lib/inline.rb', line 391

def pre
  @pre
end

#rb_fileObject (readonly)

Returns the value of attribute rb_file.



389
390
391
# File 'lib/inline.rb', line 389

def rb_file
  @rb_file
end

#sigObject

Returns the value of attribute sig.



391
392
393
# File 'lib/inline.rb', line 391

def sig
  @sig
end

#srcObject

Returns the value of attribute src.



391
392
393
# File 'lib/inline.rb', line 391

def src
  @src
end

#struct_nameObject

Sets the name of the C struct for generating accessors. Used with #accessor, #reader, #writer.



397
398
399
# File 'lib/inline.rb', line 397

def struct_name
  @struct_name
end

Instance Method Details

#accessor(method, type, member = method) ⇒ Object

Adds a #reader and #writer for a C struct member wrapped via Data_Wrap_Struct. method is the ruby name to give the accessor, type is the C type. Unless the C member name is overridden with member, the method name is used as the struct member.

builder.struct_name = 'MyStruct'
builder.accessor :title,        'char *'
builder.accessor :stream_index, 'int',   :index

The latter accesses MyStruct->index via the stream_index method.



438
439
440
441
# File 'lib/inline.rb', line 438

def accessor(method, type, member = method)
  reader method, type, member
  writer method, type, member
end

#add_compile_flags(*flags) ⇒ Object

Adds compiler options to the compiler command line. No preprocessing is done, so you must have all your dashes and everything.



668
669
670
# File 'lib/inline.rb', line 668

def add_compile_flags(*flags)
  @flags.push(*flags)
end

#add_id(name) ⇒ Object

Registers a static id_name for the symbol :name.



675
676
677
# File 'lib/inline.rb', line 675

def add_id name
  self.add_static "id_#{name}", "rb_intern(\"#{name}\")"
end

Adds linker flags to the link command line. No preprocessing is done, so you must have all your dashes and everything.



683
684
685
# File 'lib/inline.rb', line 683

def add_link_flags(*flags)
  @libs.push(*flags)
end

#add_static(name, init, type = "VALUE") ⇒ Object

Create a static variable and initialize it to a value.



690
691
692
693
# File 'lib/inline.rb', line 690

def add_static name, init, type = "VALUE"
  prefix      "static #{type} #{name};"
  add_to_init "#{name} = #{init};"
end

#add_to_init(*src) ⇒ Object

Adds custom content to the end of the init function.



698
699
700
# File 'lib/inline.rb', line 698

def add_to_init(*src)
  @init_extra.push(*src)
end

#add_type_converter(type, r2c, c2r) ⇒ Object

Registers C type-casts r2c and c2r for type.



705
706
707
708
# File 'lib/inline.rb', line 705

def add_type_converter(type, r2c, c2r)
  warn "WAR\NING: overridding #{type} on #{caller[0]}" if @type_map.has_key? type
  @type_map[type] = [r2c, c2r]
end

#alias_type_converter(existing_type, alias_type) ⇒ Object

Registers C type alias_type as an alias of existing_type



713
714
715
716
717
718
# File 'lib/inline.rb', line 713

def alias_type_converter(existing_type, alias_type)
  warn "WAR\NING: overridding #{type} on #{caller[0]}" if
    @type_map.has_key? alias_type

  @type_map[alias_type] = @type_map[existing_type]
end

#buildObject

Builds the source file, if needed, and attempts to compile it.



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
# File 'lib/inline.rb', line 529

def build
  so_name = self.so_name
  so_exists = File.file? so_name
  unless so_exists and File.mtime(rb_file) < File.mtime(so_name) then

    unless File.directory? Inline.directory then
      warn "NOTE: creating #{Inline.directory} for RubyInline" if $DEBUG
      FileUtils.mkdir_p Inline.directory, :mode => 0700
    end

    src_name = "#{Inline.directory}/#{module_name}.c"
    old_src_name = "#{src_name}.old"
    should_compare = File.write_with_backup(src_name) do |io|
      io.puts generate_ext
    end

    # recompile only if the files are different
    recompile = true
    if so_exists and should_compare and
        FileUtils.compare_file(old_src_name, src_name) then
      recompile = false

      # Updates the timestamps on all the generated/compiled files.
      # Prevents us from entering this conditional unless the source
      # file changes again.
      t = Time.now
      File.utime(t, t, src_name, old_src_name, so_name)
    end

    if recompile then

      hdrdir = %w(srcdir includedir archdir rubyhdrdir).map { |name|
        RbConfig::CONFIG[name]
      }.find { |dir|
        dir and File.exist? File.join(dir, "ruby.h")
      } or abort "ERROR: Can't find header dir for ruby. Exiting..."

      flags = @flags.join(' ')
      libs  = @libs.join(' ')

      config_hdrdir = if RbConfig::CONFIG['rubyarchhdrdir'] then
                        "-I #{RbConfig::CONFIG['rubyarchhdrdir']}"
                      elsif RUBY_VERSION > '1.9' then
                        "-I #{File.join hdrdir, RbConfig::CONFIG['arch']}"
                      else
                        nil
                      end

      windoze = WINDOZE and RUBY_PLATFORM =~ /mswin/
      sane = ! windoze
      cmd = [ RbConfig::CONFIG['LDSHARED'],
              flags,
              (RbConfig::CONFIG['DLDFLAGS']         if sane),
              (RbConfig::CONFIG['CCDLFLAGS']        if sane),
              RbConfig::CONFIG['CFLAGS'],
              (RbConfig::CONFIG['LDFLAGS']          if sane),
              '-I', hdrdir,
              config_hdrdir,
              '-I', RbConfig::CONFIG['includedir'],
              ("-L#{RbConfig::CONFIG['libdir']}"    if sane),
              (['-o', so_name.inspect]              if sane),
              File.expand_path(src_name).inspect,
              libs,
              crap_for_windoze,
              (RbConfig::CONFIG['LDFLAGS']          if windoze),
              (RbConfig::CONFIG['CCDLFLAGS']        if windoze),
            ].compact.join(' ')

      # odd compilation error on clang + freebsd 10. Ruby built w/ rbenv.
      cmd = cmd.gsub(/-Wl,-soname,\$@/, "-Wl,-soname,#{File.basename so_name}")

      # strip off some makefile macros for mingw 1.9
      cmd = cmd.gsub(/\$\(.*\)/, '') if RUBY_PLATFORM =~ /mingw/

      cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG

      warn "Building #{so_name} with '#{cmd}'" if $DEBUG

      result = if WINDOZE
                 Dir.chdir(Inline.directory) { `#{cmd}` }
               else
                 `#{cmd}`
               end

      warn "Output:\n#{result}" if $DEBUG

      if $? != 0 then
        bad_src_name = src_name + ".bad"
        File.rename src_name, bad_src_name
        raise CompilationError, "error executing #{cmd.inspect}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
      end

      # NOTE: manifest embedding is only required when using VC8 ruby
      # build or compiler.
      # Errors from this point should be ignored if RbConfig::CONFIG['arch']
      # (RUBY_PLATFORM) matches 'i386-mswin32_80'
      if WINDOZE and RUBY_PLATFORM =~ /_80$/ then
        Dir.chdir Inline.directory do
          cmd = "mt /manifest lib.so.manifest /outputresource:so.dll;#2"
          warn "Embedding manifest with '#{cmd}'" if $DEBUG
          result = `#{cmd}`
          warn "Output:\n#{result}" if $DEBUG
          if $? != 0 then
            raise CompilationError, "error executing #{cmd}: #{$?}"
          end
        end
      end

      warn "Built successfully" if $DEBUG
    end

  else
    warn "#{so_name} is up to date" if $DEBUG
  end # unless (file is out of date)
end

#c(src, options = {}) ⇒ Object

Adds a C function to the source, including performing automatic type conversion to arguments and the return value. The Ruby method name can be overridden by providing method_name. Unknown type conversions can be extended by using add_type_converter.



783
784
785
786
787
788
# File 'lib/inline.rb', line 783

def c src, options = {}
  options = {
    :expand_types => true,
  }.merge options
  self.generate src, options
end

#c2ruby(type) ⇒ Object

Converts C type type to a ruby type

Raises:

  • (ArgumentError)


498
499
500
501
# File 'lib/inline.rb', line 498

def c2ruby(type)
  raise ArgumentError, "Unknown type #{type.inspect}" unless @type_map.has_key? type
  @type_map[type].last
end

#c_raw(src, options = {}) ⇒ Object

Adds a raw C function to the source. This version does not perform any type conversion and must conform to the ruby/C coding conventions. The Ruby method name can be overridden by providing method_name.



807
808
809
# File 'lib/inline.rb', line 807

def c_raw src, options = {}
  self.generate src, options
end

#c_raw_singleton(src, options = {}) ⇒ Object

Same as c_raw, but adds a class function.



814
815
816
817
818
819
# File 'lib/inline.rb', line 814

def c_raw_singleton src, options = {}
  options = {
    :singleton => true,
  }.merge options
  self.generate src, options
end

#c_singleton(src, options = {}) ⇒ Object

Same as c, but adds a class function.



793
794
795
796
797
798
799
# File 'lib/inline.rb', line 793

def c_singleton src, options = {}
  options = {
    :expand_types => true,
    :singleton    => true,
  }.merge options
  self.generate src, options
end

#crap_for_windozeObject

Returns extra compilation flags for windoze platforms. Ugh.



648
649
650
651
652
653
654
655
656
657
658
659
660
661
# File 'lib/inline.rb', line 648

def crap_for_windoze
  # gawd windoze land sucks
  case RUBY_PLATFORM
  when /mswin32/ then
    " -link /OUT:\"#{self.so_name}\" /LIBPATH:\"#{RbConfig::CONFIG['libdir']}\" /DEFAULTLIB:\"#{RbConfig::CONFIG['LIBRUBY']}\" /INCREMENTAL:no /EXPORT:Init_#{module_name}"
  when /mingw32/ then
    c = RbConfig::CONFIG
    " -Wl,--enable-auto-import -L#{c['libdir']} -l#{c['RUBY_SO_NAME']} -o #{so_name.inspect}"
  when /i386-cygwin/ then
    ' -L/usr/local/lib -lruby.dll'
  else
    ''
  end
end

#generate(src, options = {}) ⇒ Object

def parse_signature

Raises:

  • (ArgumentError)


239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/inline.rb', line 239

def generate(src, options={})
  options = {:expand_types=>options} unless Hash === options

  expand_types = options[:expand_types]
  singleton = options[:singleton]
  result = self.strip_comments(src)

  signature = parse_signature(src, !expand_types)
  function_name = signature['name']
  method_name = options[:method_name]
  method_name ||= test_to_normal function_name
  return_type = signature['return']
  arity = options[:arity] || signature['arity']

  raise ArgumentError, "too many arguments" if arity > MAGIC_ARITY_THRESHOLD

  if expand_types then
    prefix = "static VALUE #{function_name}("
    if arity <= MAGIC_ARITY then
      prefix += "int argc, VALUE *argv, VALUE self"
    else
      prefix += "VALUE self"
      prefix += signature['args'].map { |arg, type| ", VALUE _#{arg}"}.join
    end
    prefix += ") {\n"
    prefix += signature['args'].map { |arg, type|
      "  #{type} #{arg} = #{ruby2c(type)}(_#{arg});\n"
    }.join

    # replace the function signature (hopefully) with new sig (prefix)
    result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
    result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
    unless return_type == "void" then
      raise SyntaxError, "Couldn't find return statement for #{function_name}" unless
        result =~ /return/
      result.gsub!(/return\s+([^\;\}]+)/) do
        "return #{c2ruby(return_type)}(#{$1})"
      end
    else
      result.sub!(/\s*\}\s*\Z/, "\nreturn Qnil;\n}")
    end
  else
    prefix = "static #{return_type} #{function_name}("
    result.sub!(/[^;\/\"\>]+#{function_name}\s*\(/, prefix)
    result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
  end

  delta = if result =~ /\A(static.*?\{)/m then
            $1.split(/\n/).size
          else
            msg = "WAR\NING: Can't find signature in #{result.inspect}\n"
            warn msg unless $TESTING
            0
          end

  file, line = $1, $2 if caller[1] =~ /(.*?):(\d+)/

  result = "# line #{line.to_i + delta} \"#{file}\"\n" + result unless
    $DEBUG and not $TESTING

  @src << result
  @sig[function_name] = [arity,singleton,method_name]

  return result if $TESTING
end

#generate_extObject

Builds a complete C extension suitable for writing to a file and compiling.



309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/inline.rb', line 309

def generate_ext
  ext = []

  if @include_ruby_first
    @inc.unshift "#include \"ruby.h\""
  else
    @inc.push "#include \"ruby.h\""
  end

  ext << @inc
  ext << nil
  unless @pre.empty? then
    ext << @pre.join("\n\n")
    ext << nil
  end
  ext << @src.join("\n\n")
  ext << nil
  ext << nil
  ext << "#ifdef __cplusplus"
  ext << "extern \"C\" {"
  ext << "#endif"
  ext << "  __declspec(dllexport)" if WINDOZE
  ext << "  void Init_#{module_name}() {"
  ext << "    VALUE c = rb_cObject;"

  # TODO: use rb_class2path
  # ext << "    VALUE c = rb_path2class(#{@mod.name.inspect});"
  ext << @mod.name.split("::").map { |n|
    "    c = rb_const_get(c, rb_intern(\"#{n}\"));"
  }.join("\n")

  ext << nil

  @sig.keys.sort.each do |name|
    method = ''
    arity, singleton, method_name = @sig[name]
    if singleton then
      if method_name == 'allocate' then
        raise "#{@mod}::allocate must have an arity of zero" if arity > 0
        ext << "    rb_define_alloc_func(c, (VALUE(*)(VALUE))#{name});"
        next
      end
      method << "    rb_define_singleton_method(c, \"#{method_name}\", "
    else
      method << "    rb_define_method(c, \"#{method_name}\", "
    end
    method << "(VALUE(*)(ANYARGS))#{name}, #{arity});"
    ext << method
  end

  ext << @init_extra.join("\n") unless @init_extra.empty?

  ext << nil
  ext << "  }"
  ext << "#ifdef __cplusplus"
  ext << "}"
  ext << "#endif"
  ext << nil

  ext.join "\n"
end

#include(header) ⇒ Object

Adds an include to the top of the file. Don’t forget to use quotes or angle brackets.



758
759
760
# File 'lib/inline.rb', line 758

def include(header)
  @inc << "#include #{header}"
end

#include_ruby_lastObject

Specifies that the the ruby.h header should be included after custom header(s) instead of before them.



766
767
768
# File 'lib/inline.rb', line 766

def include_ruby_last
  @include_ruby_first = false
end

#loadObject

Loads the generated code back into ruby



522
523
524
# File 'lib/inline.rb', line 522

def load
  require "#{so_name}" or raise LoadError, "require on #{so_name} failed"
end

#load_cacheObject

Attempts to load pre-generated code returning true if it succeeds.



506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/inline.rb', line 506

def load_cache
  begin
    file = File.join("inline", File.basename(so_name))
    if require file then
      dir = Inline.directory
      warn "WAR\NING: #{dir} exists but is not being used" if test ?d, dir and $VERBOSE
      return true
    end
  rescue LoadError
  end
  return false
end

#map_c_const(names_and_types) ⇒ Object

Maps a C constant to ruby. names_and_types is a hash that maps the name of the constant to its C type.

builder.map_c_const :C_NAME => :int

If you wish to give the constant a different ruby name:

builder.map_c_const :C_NAME => [:int, :RUBY_NAME]


747
748
749
750
751
752
# File 'lib/inline.rb', line 747

def map_c_const(names_and_types)
  names_and_types.each do |name, typ|
    typ, ruby_name = Array === typ ? typ : [typ, name]
    self.add_to_init "    rb_define_const(c, #{ruby_name.to_s.inspect}, #{c2ruby(typ.to_s)}(#{name}));"
  end
end

#map_ruby_const(*names) ⇒ Object

Maps RubyConstants to cRubyConstants.



730
731
732
733
734
735
# File 'lib/inline.rb', line 730

def map_ruby_const(*names)
  names.each do |name|
    self.prefix "static VALUE c#{name};"
    self.add_to_init "    c#{name} = rb_const_get(c, rb_intern(#{name.to_s.inspect}));"
  end
end

#module_nameObject



371
372
373
374
375
376
377
378
379
380
# File 'lib/inline.rb', line 371

def module_name
  unless defined? @module_name then
    module_name = @mod.name.gsub('::','__')
    md5 = Digest::MD5.new
    @pre.each { |m| md5 << m.to_s }
    @sig.keys.sort_by { |x| x.to_s }.each { |m| md5 << m.to_s }
    @module_name = "Inline_#{module_name}_#{md5}"
  end
  @module_name
end

#parse_signature(src, raw = false) ⇒ Object

Raises:

  • (SyntaxError)


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/inline.rb', line 196

def parse_signature(src, raw=false)

  sig = self.strip_comments(src)
  # strip preprocessor directives
  sig.gsub!(/^\s*\#.*(\\\n.*)*/, '')
  # strip {}s
  sig.gsub!(/\{[^\}]*\}/, '{ }')
  # clean and collapse whitespace
  sig.gsub!(/\s+/, ' ')

  unless defined? @types then
    @types = 'void|' + @type_map.keys.map{|x| Regexp.escape(x)}.join('|')
  end

  if /(#{@types})\s*(\w+)\s*\(([^)]*)\)/ =~ sig then
    return_type, function_name, arg_string = $1, $2, $3
    args = []
    arg_string.split(',').each do |arg|

      # helps normalize into 'char * varname' form
      arg = arg.gsub(/\s*\*\s*/, ' * ').strip

      if /(((#{@types})\s*\*?)+)\s+(\w+)\s*$/ =~ arg then
        args.push([$4, $1])
      elsif arg != "void" then
        warn "WAR\NING: '#{arg}' not understood"
      end
    end

    arity = args.size
    arity = MAGIC_ARITY if raw

    return {
      'return' => return_type,
      'name'   => function_name,
      'args'   => args,
      'arity'  => arity
    }
  end

  raise SyntaxError, "Can't parse signature: #{sig}"
end

#prefix(code) ⇒ Object

Adds any amount of text/code to the source



773
774
775
# File 'lib/inline.rb', line 773

def prefix(code)
  @pre << code
end

#reader(method, type, member = method) ⇒ Object

Adds a reader for a C struct member wrapped via Data_Wrap_Struct. method is the ruby name to give the reader, type is the C type. Unless the C member name is overridden with member, the method name is used as the struct member. See #accessor for an example.



449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/inline.rb', line 449

def reader(method, type, member = method)
  raise "struct name not set for reader #{method} #{type}" unless
    @struct_name

  c <<-C
VALUE #{method}() {
  #{@struct_name} *pointer;

  Data_Get_Struct(self, #{@struct_name}, pointer);

  return #{c2ruby type}(pointer->#{member});
}
  C
end

#remove_type_converter(type) ⇒ Object

Unregisters C type-casts for type.



723
724
725
# File 'lib/inline.rb', line 723

def remove_type_converter(type)
  @type_map.delete type
end

#ruby2c(type) ⇒ Object

Converts ruby type type to a C type

Raises:

  • (ArgumentError)


490
491
492
493
# File 'lib/inline.rb', line 490

def ruby2c(type)
  raise ArgumentError, "Unknown type #{type.inspect}" unless @type_map.has_key? type
  @type_map[type].first
end

#so_nameObject



382
383
384
385
386
387
# File 'lib/inline.rb', line 382

def so_name
  unless defined? @so_name then
    @so_name = "#{Inline.directory}/#{module_name}.#{RbConfig::CONFIG["DLEXT"]}"
  end
  @so_name
end

#strip_comments(src) ⇒ Object



187
188
189
190
191
192
193
194
# File 'lib/inline.rb', line 187

def strip_comments(src)
  # strip c-comments
  src = src.gsub(%r%\s*/\*.*?\*/%m, '')
  # strip cpp-comments
  src = src.gsub(%r%^\s*//.*?\n%, '')
  src = src.gsub(%r%[ \t]*//[^\n]*%, '')
  src
end

#writer(method, type, member = method) ⇒ Object

Adds a writer for a C struct member wrapped via Data_Get_Struct. method is the ruby name to give the writer, type is the C type. Unless the C member name is overridden with member, the method name is used as the struct member. See #accessor for an example.



470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
# File 'lib/inline.rb', line 470

def writer(method, type, member = method)
  raise "struct name not set for writer #{method} #{type}" unless
    @struct_name

  c <<-C
VALUE #{method}_equals(VALUE value) {
  #{@struct_name} *pointer;

  Data_Get_Struct(self, #{@struct_name}, pointer);

  pointer->#{member} = #{ruby2c type}(value);

  return value;
}
  C
end