rubber-generate 0.0.5
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/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
|