rubber-generate 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +58 -0
- data/bin/rubber-generate +54 -0
- data/lib/rubber/autord.rb +10 -0
- data/lib/rubber/codegen.rb +131 -0
- data/lib/rubber/codegen/class.rb +79 -0
- data/lib/rubber/codegen/enum.rb +231 -0
- data/lib/rubber/codegen/flags.rb +229 -0
- data/lib/rubber/codegen/float.rb +41 -0
- data/lib/rubber/codegen/function.rb +268 -0
- data/lib/rubber/codegen/gboxed.rb +30 -0
- data/lib/rubber/codegen/gcrefpool.rb +53 -0
- data/lib/rubber/codegen/genum.rb +33 -0
- data/lib/rubber/codegen/gflags.rb +38 -0
- data/lib/rubber/codegen/ginterface.rb +25 -0
- data/lib/rubber/codegen/gobject.rb +42 -0
- data/lib/rubber/codegen/integer.rb +41 -0
- data/lib/rubber/codegen/module.rb +63 -0
- data/lib/rubber/codegen/param.rb +92 -0
- data/lib/rubber/codegen/string.rb +41 -0
- data/lib/rubber/codegen/struct.rb +63 -0
- data/lib/rubber/mkextconf.rb +95 -0
- data/lib/rubber/scanner.rb +419 -0
- data/lib/rubber/struct.rb +52 -0
- data/lib/rubber/types.rb +222 -0
- metadata +85 -0
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
Rubber C Binder v0.0.5
|
2
|
+
Template language for generating Ruby bindings for C libraries
|
3
|
+
by Geoff Youngs <g@intersect-uk.co.uk>
|
4
|
+
|
5
|
+
Introduction
|
6
|
+
~~~~~~~~~~~~
|
7
|
+
A simple ruby-style bindings generator for Ruby. It allows bindings to
|
8
|
+
be laid out in a Ruby style, documentation to be included inline and
|
9
|
+
explicit type casts within C code. It's somewhere between SWIG and pyrex.
|
10
|
+
|
11
|
+
It also allows features extconf.rb creation, including checks for headers,
|
12
|
+
pkg-config etc. The modules it creates currently depend on Ruby/GTK, but
|
13
|
+
it is planned to remove this dependency unless they genuinely require Ruby/GTK.
|
14
|
+
|
15
|
+
Other features include custom named type-maps, pre/post code inclusion within
|
16
|
+
functions and some rudimentary understanding of C code.
|
17
|
+
|
18
|
+
|
19
|
+
Dependencies
|
20
|
+
~~~~~~~~~~~~
|
21
|
+
Ruby 1.8
|
22
|
+
Doesn't require any modules which aren't in the Ruby 1.8.0 distribution.
|
23
|
+
Ruby 1.6
|
24
|
+
Has not been tested. Requires at least the StringScanner (C version) and
|
25
|
+
StringIO modules. (See raa.ruby-lang.org for 'strscan' and 'stringio')
|
26
|
+
|
27
|
+
|
28
|
+
Example
|
29
|
+
~~~~~~~
|
30
|
+
Sample file:
|
31
|
+
vte/vte.cr
|
32
|
+
|
33
|
+
Usage:
|
34
|
+
$ ruby rubber.rb vte.cr
|
35
|
+
|
36
|
+
Which should generate
|
37
|
+
vte.c <- Source code for extension
|
38
|
+
vte.rd <- RD documentation from vte.cr
|
39
|
+
extconf.rb <- Config script
|
40
|
+
|
41
|
+
Running extconf.rb should then allow installation of the extension as normal.
|
42
|
+
|
43
|
+
|
44
|
+
Installation
|
45
|
+
~~~~~~~~~~~~
|
46
|
+
There is currently no installation. Rubber will automatically look for it's
|
47
|
+
libraries in the normal path or in the directory where the 'real' rubber script
|
48
|
+
resides. (So the rubber.rb can be symlinked from where you unpacked it to
|
49
|
+
a directory in your path).
|
50
|
+
|
51
|
+
When rubber matures then it will come with a proper install.rb setup.
|
52
|
+
|
53
|
+
|
54
|
+
Credits
|
55
|
+
~~~~~~~
|
56
|
+
Rubber was created by Geoff Youngs
|
57
|
+
|
58
|
+
Contributors: Vincent Isambart
|
data/bin/rubber-generate
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if FileTest.symlink?(__FILE__)
|
4
|
+
file = File::readlink(__FILE__)
|
5
|
+
else
|
6
|
+
file = __FILE__
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rbconfig'
|
10
|
+
require 'ftools'
|
11
|
+
|
12
|
+
dir = File::dirname(file)
|
13
|
+
$:.unshift(dir)
|
14
|
+
#puts dir
|
15
|
+
require 'strscan'
|
16
|
+
#require 'rubygems'
|
17
|
+
#require_gem 'rubber'
|
18
|
+
require 'rubber/codegen'
|
19
|
+
require 'rubber/mkextconf'
|
20
|
+
require 'rubber/scanner'
|
21
|
+
require 'rubber/types'
|
22
|
+
require 'rubber/autord'
|
23
|
+
|
24
|
+
|
25
|
+
args = ARGV.select { |i| i[0] != ?- }
|
26
|
+
switches = ARGV.select { |i| i[0] == ?- }
|
27
|
+
(args.size > 0 && args || Dir.glob('*.cr')).each { |file|
|
28
|
+
|
29
|
+
file = File.expand_path(file)
|
30
|
+
File.mkpath(Config::CONFIG['sitearch'])
|
31
|
+
Dir.chdir(Config::CONFIG['sitearch']) do
|
32
|
+
|
33
|
+
|
34
|
+
scanner = Rubber::CRScanner.new(file)
|
35
|
+
scanner.scan(nil)
|
36
|
+
|
37
|
+
out = File.open(scanner.ext + ".c", 'w')
|
38
|
+
doc = File.open(scanner.ext + ".rd", 'w')
|
39
|
+
|
40
|
+
extconf = File.open('extconf.rb', 'w')
|
41
|
+
Rubber.generate_extconf(scanner, extconf)
|
42
|
+
Rubber.generate_c_source(scanner, out)
|
43
|
+
Rubber.generate_rd(scanner, doc)
|
44
|
+
|
45
|
+
|
46
|
+
doc.close
|
47
|
+
out.close
|
48
|
+
extconf.close
|
49
|
+
|
50
|
+
system('ruby','extconf.rb') if switches.include?('--configure')
|
51
|
+
system('make') if switches.include?("--build")
|
52
|
+
end
|
53
|
+
}
|
54
|
+
#out.close
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rubber/struct'
|
2
|
+
module Rubber
|
3
|
+
def generate_c_source(scanner, io)
|
4
|
+
mod = scanner.stack.first # Pseudo root module for file
|
5
|
+
if scanner.options.gnu
|
6
|
+
io.puts "#define _GNU_SOURCE 1"
|
7
|
+
end
|
8
|
+
io.puts "/* Includes */"
|
9
|
+
io.puts "#include <ruby.h>"
|
10
|
+
io.puts "#include <stdlib.h>"
|
11
|
+
io.puts "#include <stdio.h>"
|
12
|
+
io.puts "#include <string.h>"
|
13
|
+
if scanner.incs
|
14
|
+
scanner.incs.each { |i| io.puts "#include #{i.inspect}"}
|
15
|
+
end
|
16
|
+
io.puts "\n/* Setup types */"
|
17
|
+
io.puts "/* Try not to clash with other definitions of bool... */"
|
18
|
+
io.puts "typedef int rubber_bool;"
|
19
|
+
io.puts "#define bool rubber_bool"
|
20
|
+
io.puts "\n/* Prototypes */"
|
21
|
+
io.puts '#include "rbglib.h"' if scanner.options.glib?
|
22
|
+
|
23
|
+
if scanner.options.glib? and scanner.options.gtk?
|
24
|
+
io.write <<-EOI
|
25
|
+
#include "rbgtk.h"
|
26
|
+
|
27
|
+
#if defined(G_PLATFORM_WIN32) && !defined(RUBY_GTK2_STATIC_COMPILATION)
|
28
|
+
# ifdef RUBY_GTK2_COMPILATION
|
29
|
+
# define RUBY_GTK2_VAR __declspec(dllexport)
|
30
|
+
# else
|
31
|
+
# define RUBY_GTK2_VAR extern __declspec(dllimport)
|
32
|
+
# endif
|
33
|
+
#else
|
34
|
+
# define RUBY_GTK2_VAR extern
|
35
|
+
#endif
|
36
|
+
|
37
|
+
RUBY_GTK2_VAR VALUE mGtk;
|
38
|
+
RUBY_GTK2_VAR VALUE mGdk;
|
39
|
+
|
40
|
+
#define RBGTK_INITIALIZE(obj,gtkobj)\
|
41
|
+
(rbgtk_initialize_gtkobject(obj, GTK_OBJECT(gtkobj)))
|
42
|
+
EOI
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
mod.classes.each { |c|
|
47
|
+
c.declare(io)
|
48
|
+
}
|
49
|
+
if scanner.raw
|
50
|
+
io.puts("\n/* Inline C code */")
|
51
|
+
io.write(scanner.raw)
|
52
|
+
end
|
53
|
+
io.puts "\n/* Code */"
|
54
|
+
mod.classes.each { |c|
|
55
|
+
c.code(io)
|
56
|
+
}
|
57
|
+
io.puts "/* Init */"
|
58
|
+
io.puts "void"
|
59
|
+
io.puts "Init_#{scanner.ext}(void)"
|
60
|
+
io.puts "{"
|
61
|
+
io.puts scanner.pre_init_code if scanner.pre_init_code
|
62
|
+
mod.classes.each { |c|
|
63
|
+
c.register(io)
|
64
|
+
}
|
65
|
+
io.puts scanner.post_init_code if scanner.post_init_code
|
66
|
+
io.puts "}"
|
67
|
+
|
68
|
+
end
|
69
|
+
module_function :generate_c_source
|
70
|
+
|
71
|
+
module RegisterChildren
|
72
|
+
attr_reader :child_names
|
73
|
+
def register_children(io)
|
74
|
+
@child_names = {}
|
75
|
+
contents.each { |f|
|
76
|
+
f.register(io, @child_names.has_key?(f.name))
|
77
|
+
if @child_names.has_key?(f.name)
|
78
|
+
puts "#{self.cname} has duplicate definitiion of #{f.name}"
|
79
|
+
else
|
80
|
+
@child_names[f.name]= f
|
81
|
+
end
|
82
|
+
}
|
83
|
+
if respond_to?(:register_aliases)
|
84
|
+
register_aliases(io)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
def cname
|
88
|
+
if parent && parent.child_names && parent.child_names[name] && parent.child_names[name] != self
|
89
|
+
parent.child_names[name].cname
|
90
|
+
else
|
91
|
+
default_cname()
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
class C_RootModule
|
98
|
+
define_members({:classes => []}, {:methods => []}, {:functions => []}, {:constants => []}, {:includes => []})
|
99
|
+
attr_reader :child_names
|
100
|
+
def cname
|
101
|
+
p "RootModule cName req'd.", caller
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
require 'rubber/codegen/module'
|
107
|
+
require 'rubber/codegen/class'
|
108
|
+
require 'rubber/codegen/param'
|
109
|
+
require 'rubber/codegen/function'
|
110
|
+
|
111
|
+
# Constants
|
112
|
+
require 'rubber/codegen/string'
|
113
|
+
require 'rubber/codegen/integer'
|
114
|
+
require 'rubber/codegen/float'
|
115
|
+
|
116
|
+
# Special
|
117
|
+
require 'rubber/codegen/struct'
|
118
|
+
require 'rubber/codegen/enum'
|
119
|
+
require 'rubber/codegen/flags'
|
120
|
+
# needs int derivative
|
121
|
+
require 'rubber/codegen/genum'
|
122
|
+
require 'rubber/codegen/gflags'
|
123
|
+
require 'rubber/codegen/gboxed'
|
124
|
+
require 'rubber/codegen/ginterface'
|
125
|
+
require 'rubber/codegen/gobject'
|
126
|
+
|
127
|
+
# Utils
|
128
|
+
require 'rubber/codegen/gcrefpool'
|
129
|
+
|
130
|
+
|
131
|
+
end # m Rubber
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rubber/codegen/module'
|
2
|
+
|
3
|
+
module Rubber
|
4
|
+
|
5
|
+
class C_Class < C_Module
|
6
|
+
define_members :name, :superclass, :methods, :functions, :constants, :ctype, {:classes => []}, :includes, :parent
|
7
|
+
attr_accessor :pre_func, :post_func, :doc, :pre_only, :pre_except, :post_only, :post_except
|
8
|
+
attr_reader :child_names
|
9
|
+
|
10
|
+
def fullname()
|
11
|
+
if parent and parent.respond_to?(:fullname)
|
12
|
+
"#{parent.fullname}::#{name}"
|
13
|
+
else
|
14
|
+
name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
def doc_rd(io)
|
18
|
+
id = fullname()
|
19
|
+
id += " < #{superclass}" if superclass
|
20
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
21
|
+
io.puts "=#{'=' * depth} class #{id}"
|
22
|
+
io.puts @doc if @doc
|
23
|
+
contents.each { |f| f.doc_rd(io) }
|
24
|
+
end
|
25
|
+
def get_root(); is_root? ? self : parent.get_root; end
|
26
|
+
def is_root?()
|
27
|
+
not parent.respond_to?(:fullname)
|
28
|
+
end
|
29
|
+
def code(io)
|
30
|
+
contents .each { |f| f.code(io) }
|
31
|
+
end
|
32
|
+
def declare(io)
|
33
|
+
io.puts "static VALUE #{cname};";
|
34
|
+
contents .each { |f| f.declare(io) }
|
35
|
+
end
|
36
|
+
def register(io, already_defined=false)
|
37
|
+
if parent.child_names && parent.child_names[name]
|
38
|
+
io.puts " c#{name} = #{cname};"
|
39
|
+
else
|
40
|
+
if parent and parent.cname
|
41
|
+
io.puts " #{cname} = rb_define_class_under(#{parent.cname}, #{name.inspect}, #{Rubber::find_class(superclass) || 'rb_cObject'});"
|
42
|
+
else
|
43
|
+
io.puts " #{cname} = rb_define_class(#{name.inspect}, #{Rubber::find_class(superclass) || 'rb_cObject'});"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
register_children(io)
|
47
|
+
end
|
48
|
+
include RegisterChildren
|
49
|
+
def default_cname
|
50
|
+
"c"+name
|
51
|
+
end
|
52
|
+
def check_wrap_ok(io, fn, where)
|
53
|
+
case where
|
54
|
+
when :pre
|
55
|
+
code = @pre_func
|
56
|
+
only = @pre_only
|
57
|
+
except = @pre_except
|
58
|
+
when :post
|
59
|
+
code = @post_func
|
60
|
+
only = @post_only
|
61
|
+
except = @post_except
|
62
|
+
end
|
63
|
+
if code && ! fn.singleton
|
64
|
+
return if only && ! only.empty? && ! only.include?(fn.name)
|
65
|
+
return if except && except.include?(fn.name)
|
66
|
+
io.puts code
|
67
|
+
end
|
68
|
+
end
|
69
|
+
def pre_func(io, func)
|
70
|
+
#io.puts @pre_func unless @pre_func.nil? or func.singleton
|
71
|
+
check_wrap_ok(io, func, :pre)
|
72
|
+
end
|
73
|
+
def post_func(io, func)
|
74
|
+
#io.puts @post_func unless @post_func.nil? or func.singleton
|
75
|
+
check_wrap_ok(io, func, :post)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end # Rubber
|
@@ -0,0 +1,231 @@
|
|
1
|
+
module Rubber
|
2
|
+
|
3
|
+
class C_Enum
|
4
|
+
define_members :name, :args, :parent
|
5
|
+
attr_reader :child_names
|
6
|
+
@@declared_base = false
|
7
|
+
@@declared_register = false
|
8
|
+
def init()
|
9
|
+
($custom_maps[name] ||= {})["VALUE"] = "enum_#{name}_to_ruby((%%))"
|
10
|
+
($custom_maps["VALUE"] ||= {})[name] = "enum_ruby_to_#{name}((%%))"
|
11
|
+
STDERR.puts "Auto-adding custom map for #{name}"
|
12
|
+
@splits = strip_prefixes(args)
|
13
|
+
@strip = args.first.length - @splits.first.length
|
14
|
+
end
|
15
|
+
def code(io)
|
16
|
+
end
|
17
|
+
def declare(io)
|
18
|
+
io.puts "static VALUE #{cname};"
|
19
|
+
unless @@declared_base
|
20
|
+
@@declared_base = true
|
21
|
+
io.puts "
|
22
|
+
|
23
|
+
static VALUE enumBaseClass;
|
24
|
+
|
25
|
+
typedef struct {
|
26
|
+
int value;
|
27
|
+
char *name;
|
28
|
+
char *fullname;
|
29
|
+
} EnumData;
|
30
|
+
|
31
|
+
static VALUE make_enum_value(VALUE klass, int value, char *name, char *fullname)
|
32
|
+
{
|
33
|
+
EnumData *data = NULL;
|
34
|
+
|
35
|
+
data = ALLOC(EnumData);
|
36
|
+
data->value = value;
|
37
|
+
data->name = name;
|
38
|
+
data->fullname = fullname;
|
39
|
+
|
40
|
+
return Data_Wrap_Struct(klass, NULL, free, data);
|
41
|
+
}
|
42
|
+
static int value_to_int(VALUE value, VALUE klass)
|
43
|
+
{
|
44
|
+
switch (TYPE(value))
|
45
|
+
{
|
46
|
+
case T_FIXNUM:
|
47
|
+
case T_FLOAT:
|
48
|
+
return NUM2INT(value);
|
49
|
+
break;
|
50
|
+
case T_DATA:
|
51
|
+
if (rb_obj_is_kind_of(value, enumBaseClass))
|
52
|
+
{
|
53
|
+
EnumData *data = NULL;
|
54
|
+
|
55
|
+
if ((klass != Qnil) && (!rb_obj_is_kind_of(value, klass)))
|
56
|
+
{
|
57
|
+
rb_raise(rb_eTypeError, \"Wrong type of enum %s (%s required)\", rb_obj_classname(value), rb_class2name(klass));
|
58
|
+
}
|
59
|
+
|
60
|
+
Data_Get_Struct(value, EnumData, data);
|
61
|
+
return data->value;
|
62
|
+
}
|
63
|
+
break;
|
64
|
+
}
|
65
|
+
return 0;
|
66
|
+
|
67
|
+
}
|
68
|
+
|
69
|
+
static VALUE rubber_enum_inspect(VALUE value)
|
70
|
+
{
|
71
|
+
EnumData *data = NULL;
|
72
|
+
volatile VALUE str = rb_str_new(\"#<\", 2);
|
73
|
+
char number[16] = \"\";
|
74
|
+
|
75
|
+
Data_Get_Struct(value, EnumData, data);
|
76
|
+
|
77
|
+
rb_str_cat2(str, rb_obj_classname(value));
|
78
|
+
rb_str_cat2(str, \" - \");
|
79
|
+
rb_str_cat2(str, data->name);
|
80
|
+
rb_str_cat2(str, \"(\");
|
81
|
+
sprintf(number, \"%i\", data->value);
|
82
|
+
rb_str_cat2(str, number);
|
83
|
+
rb_str_cat2(str, \")>\");
|
84
|
+
|
85
|
+
return str;
|
86
|
+
}
|
87
|
+
|
88
|
+
static VALUE rubber_enum_to_s(VALUE value)
|
89
|
+
{
|
90
|
+
EnumData *data = NULL;
|
91
|
+
|
92
|
+
Data_Get_Struct(value, EnumData, data);
|
93
|
+
|
94
|
+
return rb_str_new2(data->fullname);
|
95
|
+
}
|
96
|
+
static VALUE rubber_enum_name(VALUE value)
|
97
|
+
{
|
98
|
+
EnumData *data = NULL;
|
99
|
+
|
100
|
+
Data_Get_Struct(value, EnumData, data);
|
101
|
+
|
102
|
+
return rb_str_new2(data->name);
|
103
|
+
}
|
104
|
+
|
105
|
+
static VALUE rubber_enum_cmp(VALUE value, VALUE other)
|
106
|
+
{
|
107
|
+
VALUE a,b;
|
108
|
+
a = rb_funcall(value, rb_intern(\"to_i\"), 0);
|
109
|
+
b = rb_funcall(other, rb_intern(\"to_i\"), 0);
|
110
|
+
return rb_num_coerce_cmp(a, b);
|
111
|
+
}
|
112
|
+
|
113
|
+
static VALUE rubber_enum_to_i(VALUE value)
|
114
|
+
{
|
115
|
+
EnumData *data = NULL;
|
116
|
+
|
117
|
+
Data_Get_Struct(value, EnumData, data);
|
118
|
+
|
119
|
+
return INT2FIX(data->value);
|
120
|
+
}
|
121
|
+
|
122
|
+
static VALUE rubber_enum_coerce(VALUE value, VALUE other)
|
123
|
+
{
|
124
|
+
EnumData *data = NULL;
|
125
|
+
|
126
|
+
Data_Get_Struct(value, EnumData, data);
|
127
|
+
|
128
|
+
switch(TYPE(other))
|
129
|
+
{
|
130
|
+
case T_FIXNUM:
|
131
|
+
case T_BIGNUM:
|
132
|
+
return INT2FIX(data->value);
|
133
|
+
case T_FLOAT:
|
134
|
+
return rb_float_new(data->value);
|
135
|
+
default:
|
136
|
+
return Qnil;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
"
|
141
|
+
end
|
142
|
+
args.each do |arg|
|
143
|
+
io.puts "static VALUE #{default_cname}_#{arg} = Qnil;"
|
144
|
+
end
|
145
|
+
io.puts "typedef int #{name};
|
146
|
+
#ifdef __GNUC__
|
147
|
+
// No point in declaring these unless we're using GCC
|
148
|
+
// They're ahead of any code that uses them anyway.
|
149
|
+
static VALUE enum_#{name}_to_ruby(int value)
|
150
|
+
__attribute__ ((unused))
|
151
|
+
;
|
152
|
+
static int enum_ruby_to_#{name}(VALUE val)
|
153
|
+
__attribute__ ((unused))
|
154
|
+
;
|
155
|
+
#endif
|
156
|
+
|
157
|
+
"
|
158
|
+
io.puts "static VALUE enum_#{name}_to_ruby(int value) { switch(value) {"
|
159
|
+
args.each do |arg|
|
160
|
+
io.puts " case #{arg}: return #{default_cname}_#{arg};"
|
161
|
+
end
|
162
|
+
io.puts "}; return Qnil; }"
|
163
|
+
io.puts "static int enum_ruby_to_#{name}(VALUE val) { return value_to_int(val, #{cname}); }"
|
164
|
+
end
|
165
|
+
include RegisterChildren
|
166
|
+
def default_cname
|
167
|
+
"enum"+name
|
168
|
+
end
|
169
|
+
def doc_rd(io)
|
170
|
+
depth = (fullname.gsub(/[^:]/,'').size >> 1)
|
171
|
+
io.puts "=#{'=' * depth} enum #{fullname}"
|
172
|
+
end
|
173
|
+
def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
|
174
|
+
not parent.respond_to?(:fullname)
|
175
|
+
end
|
176
|
+
def fullname()
|
177
|
+
if parent and parent.respond_to?(:fullname)
|
178
|
+
"#{parent.fullname}::#{name}"
|
179
|
+
else
|
180
|
+
name
|
181
|
+
end
|
182
|
+
end
|
183
|
+
def same_prefix(arr)
|
184
|
+
for i in arr
|
185
|
+
return false if arr.first.first != i.first
|
186
|
+
end
|
187
|
+
return true
|
188
|
+
end
|
189
|
+
def strip_prefixes(arr)
|
190
|
+
splits = arr.collect { |i| i.strip.split(/_/) }
|
191
|
+
while (same_prefix(splits))
|
192
|
+
splits.each { |i| i.shift }
|
193
|
+
end
|
194
|
+
splits.collect!{|i| i.join('_') }
|
195
|
+
splits
|
196
|
+
end
|
197
|
+
def get_root(); is_root? ? self : parent.get_root; end;
|
198
|
+
def is_root?()
|
199
|
+
not parent.respond_to?(:fullname)
|
200
|
+
end
|
201
|
+
def register(io, already_defined=false)
|
202
|
+
unless @@declared_register
|
203
|
+
@@declared_register = true
|
204
|
+
io.puts " enumBaseClass = rb_define_class(\"Enum\", rb_cObject);"
|
205
|
+
io.puts ' rb_define_method(enumBaseClass, "inspect", rubber_enum_inspect, 0);'
|
206
|
+
io.puts ' rb_define_method(enumBaseClass, "to_i", rubber_enum_to_i, 0);'
|
207
|
+
io.puts ' rb_define_method(enumBaseClass, "coerce", rubber_enum_coerce, 1);'
|
208
|
+
io.puts ' rb_define_method(enumBaseClass, "to_s", rubber_enum_to_s, 0);'
|
209
|
+
io.puts ' rb_define_method(enumBaseClass, "to_str", rubber_enum_to_s, 0);'
|
210
|
+
io.puts ' rb_define_method(enumBaseClass, "fullname", rubber_enum_to_s, 0);'
|
211
|
+
io.puts ' rb_define_method(enumBaseClass, "name", rubber_enum_name, 0);'
|
212
|
+
io.puts ' rb_define_method(enumBaseClass, "<=>", rubber_enum_cmp, 0);'
|
213
|
+
io.puts ' '
|
214
|
+
end
|
215
|
+
if parent
|
216
|
+
io.puts " #{cname} = rb_define_class_under(#{parent.cname}, #{name.inspect}, enumBaseClass);"
|
217
|
+
else
|
218
|
+
io.puts " #{cname} = rb_define_class(#{name.inspect}, enumBaseClass);"
|
219
|
+
end
|
220
|
+
|
221
|
+
args.each do |arg|
|
222
|
+
uniq = arg[@strip..-1]
|
223
|
+
uniq.sub!(/\A[^a-zA-Z]/,'')
|
224
|
+
io.puts " #{default_cname}_#{arg} = make_enum_value(#{cname}, #{arg}, #{uniq.downcase.gsub(/_/,'-').inspect}, #{arg.inspect});"
|
225
|
+
io.puts " rb_obj_freeze(#{default_cname}_#{arg});"
|
226
|
+
io.puts " rb_define_const(#{cname}, #{uniq.upcase.inspect}, #{default_cname}_#{arg});"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
end # Rubber
|