crystalizer 0.2.2

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.
Files changed (126) hide show
  1. data/Changelog +27 -0
  2. data/README +79 -0
  3. data/Rakefile +24 -0
  4. data/TODO +14 -0
  5. data/VERSION +1 -0
  6. data/benchmarks/bench.rb +129 -0
  7. data/benchmarks/concretize_test.rb +26 -0
  8. data/benchmarks/extconf.rb +10 -0
  9. data/benchmarks/tak_rb.rb +7 -0
  10. data/benchmarks/tak_so.rb +7 -0
  11. data/benchmarks/tak_source.rb +16 -0
  12. data/bin/rb2cx +162 -0
  13. data/doc/eval2c.txt +246 -0
  14. data/doc/gen_html.rb +26 -0
  15. data/doc/html_template +10 -0
  16. data/doc/index.txt +169 -0
  17. data/doc/limitations.txt +529 -0
  18. data/doc/optimizations.txt +185 -0
  19. data/doc/rb2cx.txt +130 -0
  20. data/doc/style.css +27 -0
  21. data/lib/concretizer.rb +3 -0
  22. data/lib/ruby2cext/c_function.rb +617 -0
  23. data/lib/ruby2cext/common_node_comp.rb +1412 -0
  24. data/lib/ruby2cext/compiler.rb +311 -0
  25. data/lib/ruby2cext/concretize.rb +269 -0
  26. data/lib/ruby2cext/error.rb +15 -0
  27. data/lib/ruby2cext/eval2c.rb +126 -0
  28. data/lib/ruby2cext/parser.rb +36 -0
  29. data/lib/ruby2cext/plugin.rb +24 -0
  30. data/lib/ruby2cext/plugins/builtin_methods.rb +817 -0
  31. data/lib/ruby2cext/plugins/cache_call.rb +293 -0
  32. data/lib/ruby2cext/plugins/case_optimize.rb +102 -0
  33. data/lib/ruby2cext/plugins/const_cache.rb +36 -0
  34. data/lib/ruby2cext/plugins/direct_self_call.rb +70 -0
  35. data/lib/ruby2cext/plugins/inline_builtin.rb +797 -0
  36. data/lib/ruby2cext/plugins/inline_methods.rb +68 -0
  37. data/lib/ruby2cext/plugins/ivar_cache.rb +147 -0
  38. data/lib/ruby2cext/plugins/require_include.rb +69 -0
  39. data/lib/ruby2cext/plugins/util.rb +154 -0
  40. data/lib/ruby2cext/plugins/warnings.rb +121 -0
  41. data/lib/ruby2cext/scopes.rb +225 -0
  42. data/lib/ruby2cext/str_to_c_strlit.rb +12 -0
  43. data/lib/ruby2cext/tools.rb +80 -0
  44. data/lib/ruby2cext/version.rb +22 -0
  45. data/results +68 -0
  46. data/setup.rb +1585 -0
  47. data/stuff/builtin_methods.rb +69 -0
  48. data/stuff/builtin_methods_test.rb +37 -0
  49. data/test/bootstrap.rb +10 -0
  50. data/test/causes_crash_all_opts.rb +1165 -0
  51. data/test/eval2c/test_eval2c.rb +37 -0
  52. data/test/temp_17.rb +16 -0
  53. data/test/temp_18.rb +8 -0
  54. data/test/temp_19.rb +8 -0
  55. data/test/temp_2.rb +7 -0
  56. data/test/temp_20.rb +5 -0
  57. data/test/temp_21.rb +161 -0
  58. data/test/temp_22.rb +7 -0
  59. data/test/temp_23.rb +7 -0
  60. data/test/temp_24.rb +219 -0
  61. data/test/temp_25.rb +7 -0
  62. data/test/temp_26.rb +11 -0
  63. data/test/temp_27.rb +11 -0
  64. data/test/temp_28.rb +9 -0
  65. data/test/temp_29.rb +9 -0
  66. data/test/temp_3.rb +0 -0
  67. data/test/temp_30.rb +0 -0
  68. data/test/temp_31.rb +10 -0
  69. data/test/temp_32.rb +10 -0
  70. data/test/temp_33.rb +15 -0
  71. data/test/temp_34.rb +15 -0
  72. data/test/temp_35.rb +7 -0
  73. data/test/temp_36.rb +7 -0
  74. data/test/temp_37.rb +10 -0
  75. data/test/temp_38.rb +10 -0
  76. data/test/temp_39.rb +0 -0
  77. data/test/temp_4.rb +7 -0
  78. data/test/temp_40.rb +50 -0
  79. data/test/temp_41.rb +50 -0
  80. data/test/temp_42.rb +8 -0
  81. data/test/temp_43.rb +8 -0
  82. data/test/temp_44.rb +0 -0
  83. data/test/temp_48.rb +7 -0
  84. data/test/temp_49.rb +7 -0
  85. data/test/temp_5.rb +7 -0
  86. data/test/temp_59.rb +7 -0
  87. data/test/temp_6.rb +7 -0
  88. data/test/temp_60.rb +7 -0
  89. data/test/temp_68.rb +239 -0
  90. data/test/temp_7.rb +7 -0
  91. data/test/temp_70.rb +7 -0
  92. data/test/temp_71.rb +7 -0
  93. data/test/temp_72.rb +13 -0
  94. data/test/temp_73.rb +7 -0
  95. data/test/temp_74.rb +7 -0
  96. data/test/temp_76.rb +7 -0
  97. data/test/temp_77.rb +13 -0
  98. data/test/temp_79.rb +7 -0
  99. data/test/temp_8.rb +14 -0
  100. data/test/temp_81.rb +14 -0
  101. data/test/temp_83.rb +0 -0
  102. data/test/temp_84.rb +7 -0
  103. data/test/temp_85.rb +7 -0
  104. data/test/temp_86.rb +14 -0
  105. data/test/temp_87.rb +7 -0
  106. data/test/temp_88.rb +7 -0
  107. data/test/temp_89.rb +7 -0
  108. data/test/temp_9.rb +14 -0
  109. data/test/temp_90.rb +0 -0
  110. data/test/temp_91.rb +7 -0
  111. data/test/temp_92.rb +7 -0
  112. data/test/temp_93.rb +7 -0
  113. data/test/temp_94.rb +7 -0
  114. data/test/temp_95.rb +7 -0
  115. data/test/temp_96.rb +0 -0
  116. data/test/temp_97.rb +0 -0
  117. data/test/temp_98.rb +7 -0
  118. data/test/temp_99.rb +7 -0
  119. data/test/test_concretize.rb +132 -0
  120. data/test/test_concretize_all.rb +15 -0
  121. data/test/test_crystalize_block.rb +73 -0
  122. data/test/test_files/test.rb +615 -0
  123. data/test/test_files/vmode_test.rb +73 -0
  124. data/test/test_files/warn_test.rb +35 -0
  125. data/test/test_syntax.rb +25 -0
  126. metadata +268 -0
@@ -0,0 +1,246 @@
1
+
2
+ h1. Eval2C
3
+
4
+ Eval2C is a class that allows the compilation of Ruby code to a C extension at
5
+ runtime. The compiled C extension will be <code>require</code>d automatically
6
+ and the compiled code will be available as a Proc.
7
+
8
+ It is easy to integrate Eval2C into existing scripts or libraries to improve
9
+ performance. It is also pretty simple to provide fallback code for when
10
+ Ruby2CExtension is not available.
11
+
12
+
13
+ h2. Basic Usage
14
+
15
+ Here is an example:
16
+
17
+ PRE
18
+ require "ruby2cext/eval2c"
19
+
20
+ $e2c = Ruby2CExtension::Eval2C.new
21
+
22
+ $e2c.toplevel_eval("puts 'hello'") # prints hello
23
+ PREEND
24
+
25
+ First you need to create an Eval2C instance, this instance basically stores
26
+ the options/configuration. In the above example no options were given, so the
27
+ defaults are used. The available options are explained below.
28
+
29
+ The last line of the example does what the method name suggests: the string of
30
+ Ruby code is evaluated at the toplevel (i.e. not inside any class scope). To
31
+ be more precise, that last line is equivalent to this Ruby code:
32
+
33
+ PRE
34
+ $some_global_var = proc { puts 'hello' }
35
+ $some_global_var.call
36
+ PREEND
37
+
38
+ The proc is compiled to a C extension, that C expension is then
39
+ <code>require</code>d and finally the proc is called.
40
+
41
+ The implementation of @toplevel_eval@ is actually pretty simple:
42
+
43
+ PRE
44
+ def toplevel_eval(code_str)
45
+ compile_to_proc(code_str).call
46
+ end
47
+ PREEND
48
+
49
+ So the main work is done by @compile_to_proc@, which can also be used
50
+ directly:
51
+
52
+ PRE
53
+ $e2c.compile_to_proc("|a,b| a+b").call(2, 3) # => 5
54
+ PREEND
55
+
56
+ There are some things to note: The proc won't have access to local variables
57
+ and it will be defined at toplevel, which is important for constant lookup:
58
+
59
+ PRE
60
+ SOME_CONST = :toplevel
61
+
62
+ class A
63
+ SOME_CONST = :A
64
+ $e2c.compile_to_proc("SOME_CONST").call # => :toplevel, not :A!
65
+ end
66
+ PREEND
67
+
68
+ Eval2C also offers equivalents to Ruby's @module_eval@/@class_eval@ and
69
+ @instance_eval@:
70
+
71
+ PRE
72
+ class A
73
+ $e2c.module_eval(self, %{
74
+ def initialize(x)
75
+ @x = x
76
+ end
77
+ def foo(y)
78
+ @x + y
79
+ end
80
+ })
81
+ end
82
+
83
+ A.new(5).foo(6) # => 11
84
+
85
+ $e2c.instance_eval("4321", "reverse") # => "1234"
86
+ PREEND
87
+
88
+ Their implementations also use @compile_to_proc@ and they are very similar to
89
+ the implementation of @toplevel_eval@:
90
+
91
+ PRE
92
+ def module_eval(mod, code_str)
93
+ mod.module_eval(&compile_to_proc(code_str))
94
+ end
95
+ alias :class_eval :module_eval
96
+
97
+ def instance_eval(object, code_str)
98
+ object.instance_eval(&compile_to_proc(code_str))
99
+ end
100
+ PREEND
101
+
102
+ With @module_eval@/@class_eval@ it is possible to selectively compile some
103
+ performance critical methods to C and leave the rest in Ruby.
104
+
105
+ But there is one more thing: @compile_methods@.
106
+
107
+ Defining the methods using @module_eval@ as in the last example, has at least
108
+ one downside: it won't play nice with syntax-highlighting text editors,
109
+ because the code of the methods is actually in a string. It would be much
110
+ nicer to @def@ the methods the normal way and then just compile them
111
+ afterwards.
112
+
113
+ Thanks to @compile_methods@ this is possible:
114
+
115
+ PRE
116
+ class A
117
+ def initialize(x)
118
+ @x = x
119
+ end
120
+ def foo(y)
121
+ @x + y
122
+ end
123
+
124
+ $e2c.compile_methods(self, :initialize, :foo)
125
+ end
126
+
127
+ A.new(5).foo(6) # => 11
128
+ PREEND
129
+
130
+ @compile_methods@ will grab the methods' node trees using RubyNode, compile
131
+ them to C and then replace the old methods with the C versions. The visibility
132
+ of the old methods will be preserved.
133
+
134
+ There are some limitations: @compile_methods@ only works with methods defined
135
+ using @def@ and the methods must not need a cref (for more informations on
136
+ what crefs are please see the respective section in
137
+ "limitations":limitations.html). This mainly means that constants must be
138
+ prefixed with a double colon: @Array@ needs a cref, while @::Array@ does not.
139
+
140
+
141
+ h2. Options
142
+
143
+ Eval2C is configured with an option hash, the available options are:
144
+
145
+ * @:path@: this is the path where the compiled extensions are stored, the
146
+ default is the directory @.ruby2cext@ in the current users home dir.
147
+ * @:prefix@: this is the prefix for the names of the generated extensions, the
148
+ names of the extensions are generated from this prefix and a SHA1 digest of
149
+ the code and options. The default is @"eval2c"@ and it is generally not
150
+ necessary to change it.
151
+ * @:plugins@: this is used to configure the options for the compilation
152
+ (compare "rb2cx":rb2cx.html) and it is another option hash. The default is
153
+ <code>{:optimizations => :all}</code>, but all of the following keys are
154
+ possible:
155
+ ** @:warnings@: if set to @true@, then warnings about possible problems will
156
+ be sent to the logger (see below).
157
+ ** @:require_include@: can be set to a single search path or an array of
158
+ search paths (equivalent to the @-I@ option of @rb2cx@).
159
+ ** @:optimizations@: yet another option hash to configure the
160
+ "optimizations":optimizations.html. The valid keys are @:const_cache@,
161
+ @:builtin_methods@, @:inline_methods@ and @:case_optimize@, each with
162
+ @true@ or @false@ as value. To just use all optimizations it is also
163
+ possible to just use the symbol @:all@ instead of the hash.
164
+ * @:logger@: used for log messages, can be either @nil@ or an instance of
165
+ @Logger@ (<code>require "logger"</code>). The default is @nil@, which means
166
+ that no output is generated.
167
+ * @:force_recompile@: if this is set to @true@, then each generated extension
168
+ is (re)compiled, even if it is already available from a previous run. The
169
+ default is @false@.
170
+
171
+ Some examples:
172
+
173
+ PRE
174
+ Eval2C.new(:path => ".", :plugins => {})
175
+ Eval2C.new(:plugins => {:require_include=>[".", "../lib"], :optimizations=>:all})
176
+ Eval2C.new(:plugins => {:warnings=>true, :optimizations=>{:builtin_methods=>true}})
177
+ Eval2C.new(:prefix => "my_lib_name", :logger => Logger.new(STDOUT))
178
+ PREEND
179
+
180
+
181
+ h2. Implementation Details
182
+
183
+ The @compile_to_proc@ method works as follows:
184
+
185
+ # The name of the extension is determined from the given prefix combined with
186
+ the SHA1 digest of the Ruby code and some extra data (Ruby version,
187
+ Ruby2CExtension version and plugin options). So the code determines the
188
+ extension name and if the same code is compiled with the same version and
189
+ settings, the name will be the same. This allows very simple and efficient
190
+ caching of the compiled extensions.
191
+ # From the extension name a global variable name is constructed. The compiled
192
+ proc will be stored in that global variable by the generated C extension.
193
+ # If the extension with the generated name already exists, then we are
194
+ basically done and can skip this step. Otherwise the Ruby proc code is
195
+ translated to C and compiled to a C extension in the specified path.
196
+ # The generated or already existing C extension is <code>require</code>d.
197
+ # The global variable that now contains the compiled proc is read and the
198
+ result is returned.
199
+
200
+ The @compile_methods@ method works similar.
201
+
202
+ As mentioned above, this scheme allows very efficient caching of the C
203
+ extensions. Basically each extension is only compiled once when the
204
+ program/library is executed for the first time. In later runs the extension
205
+ will already exist and just be <code>require</code>d.
206
+
207
+ Adding the Ruby version and the Ruby2CExtension version to the digest avoids
208
+ problems if multiple versions of Ruby or Ruby2CExtension are installed and
209
+ used in parallel and it also guarantees that the extensions are automatically
210
+ recompiled if Ruby or Ruby2CExtension are updated.
211
+
212
+
213
+ h2. Using Eval2C Only When It Is Available
214
+
215
+ Having Ruby2CExtension as a hard dependency just for some speedup might not
216
+ be acceptable for many projects, in particular since Ruby2CExtension requires
217
+ that a C compiler is available at runtime.
218
+
219
+ An alternative that avoids the hard dependency is to use Ruby2CExtension only
220
+ if it is installed anyway and otherwise just execute the Ruby code as usual.
221
+ This works works very well if Eval2C and @compile_methods@ is used, for
222
+ example:
223
+
224
+ PRE
225
+ begin
226
+ require "ruby2cext/eval2c"
227
+ $e2c = Ruby2CExtension::Eval2C.new
228
+ rescue LoadError
229
+ $e2c = nil
230
+ end
231
+
232
+ class A
233
+ def initialize(x)
234
+ @x = x
235
+ end
236
+ def foo(y)
237
+ @x + y
238
+ end
239
+
240
+ $e2c && $e2c.compile_methods(self, :initialize, :foo)
241
+ end
242
+ PREEND
243
+
244
+ So if Ruby2CExtension is available, then the methods will be compiled and
245
+ fast, otherwise the Ruby code will just work as usual (but it might be a bit
246
+ slower of course).
@@ -0,0 +1,26 @@
1
+ require "redcloth"
2
+
3
+ Dir.chdir(File.dirname(__FILE__))
4
+
5
+ template = File.read("html_template")
6
+
7
+ Dir["*.txt"].each { |fn|
8
+ txt = File.read(fn)
9
+ title = txt[/^h1. (.+?)$/, 1]
10
+ txt.gsub!(/^PRE\n/m, "<pre><code>")
11
+ txt.gsub!(/^PREEND$/, "</code></pre>")
12
+ cnt = 0
13
+ sections = []
14
+ txt.gsub!(/^h2\.\s(.+)$/) { sections << $1; "h2(#section#{cnt+=1}). #$1" }
15
+ unless sections.empty?
16
+ sect_list = "\nSections: "
17
+ cnt = 0
18
+ sect_list << sections.map { |s| "\"#{s}\":#section#{cnt+=1}" }.join(", ")
19
+ sect_list << ".\n\n"
20
+ txt.sub!(/\nh2\(/m, sect_list << "h2(")
21
+ end
22
+ html = RedCloth.new(txt).to_html
23
+ File.open("#{File.basename(fn, ".txt")}.html", "w") { |f|
24
+ f.puts(template % [title, html])
25
+ }
26
+ }
@@ -0,0 +1,10 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2
+ <html>
3
+ <head>
4
+ <title>%s</title>
5
+ <link href="style.css" media="all" rel="Stylesheet" type="text/css">
6
+ </head>
7
+ <body>
8
+ %s
9
+ </body>
10
+ </html>
@@ -0,0 +1,169 @@
1
+
2
+ h1. Ruby2CExtension
3
+
4
+ Ruby2CExtension is a Ruby to C extension translator/compiler. It takes any
5
+ Ruby source file, parses it using Ruby's builtin parser and then translates
6
+ the abstract syntax tree into "equivalent" C extension code.
7
+
8
+ Let's say you have a Ruby file @foo.rb@. To translate it to a C extension and
9
+ then compile it, just run:
10
+
11
+ PRE
12
+ rb2cx foo.rb
13
+ PREEND
14
+
15
+ This will produce the files @foo.c@ and @foo.so@ (on Linux). @foo.c@ is the
16
+ generated C extension source code and @foo.so@ is the compiled C extension.
17
+
18
+ If @foo.rb@ is a library, you can just rename, move or delete @foo.rb@ (only
19
+ if you have a backup, of course) and your Ruby program will just use @foo.so@
20
+ instead.
21
+
22
+ If @foo.rb@ is a script, then it isn't possible to just run @foo.so@, because
23
+ Ruby does not support running C extensions directly, but you can do this:
24
+
25
+ PRE
26
+ ruby -r foo.so -e ""
27
+ PREEND
28
+
29
+ which should produce the same output as
30
+
31
+ PRE
32
+ ruby -r foo.rb -e ""
33
+ PREEND
34
+
35
+
36
+ h2. Why?
37
+
38
+ Well, like everybody else I wanted a faster Ruby and I also wanted to learn
39
+ about Ruby's internals, so I thought translating Ruby to C might be worth a
40
+ try...
41
+
42
+ The initial results were not as good as I had hoped, but they weren't bad
43
+ either: without optimizations the generated C extension is practically never
44
+ slower than the Ruby code and I found cases where it is more than twice as
45
+ fast, usually it is somewhere in between. But, starting from version 0.2.0,
46
+ Ruby2CExtension can use "optimizations":optimizations.html to *significantly
47
+ speedup* execution in many cases (*sometimes more than five times faster* than
48
+ normal Ruby).
49
+
50
+ Of course Ruby2CExtension can also be used as an obfuscator for Ruby code,
51
+ though this was not my main motivation.
52
+
53
+
54
+ h2. Requirements
55
+
56
+ Ruby2CExtension is developed for the Ruby 1.8 versions (only 1.8.4 and later).
57
+ It is currently tested with *Ruby 1.8.4, 1.8.5 and 1.8.6*. Only those versions
58
+ should be used, because Ruby2CExtension depends on Ruby internals that can
59
+ change between Ruby versions. If an untested Ruby version is used, then there
60
+ will be a warning. It might work for later 1.8 versions, but it definitely
61
+ won't work with Ruby 1.9.
62
+
63
+ Ruby2CExtension requires RubyNode to access Ruby's node trees (the AST).
64
+ RubyNode is available at
65
+ "http://rubynode.rubyforge.org/":http://rubynode.rubyforge.org/.
66
+
67
+ Ruby2CExtension is pure Ruby code, so it should work on all platforms that
68
+ Ruby supports, but it is currently only tested on Linux. There might be
69
+ problems with the automatic compilation of the generated C code on some
70
+ platforms (in particular on Windows).
71
+
72
+
73
+ h2. Download
74
+
75
+ * "Project page":http://rubyforge.org/projects/ruby2cext/
76
+ * "Download":http://rubyforge.org/frs/?group_id=1799
77
+
78
+
79
+ h2. Installation
80
+
81
+ Just run (as root):
82
+
83
+ PRE
84
+ gem install ruby2cext
85
+ PREEND
86
+
87
+ Or if you do not use the gem:
88
+
89
+ PRE
90
+ ruby setup.rb
91
+ PREEND
92
+
93
+ This will install Ruby2CExtension to the default locations. Optionally you
94
+ can supply some options to @setup.rb@ to customize the installation (see
95
+ @"ruby setup.rb --help"@).
96
+
97
+
98
+ h2. Features
99
+
100
+ Ruby2CExtension supports a very large subset of Ruby's features:
101
+
102
+ * all the basics (classes, methods, ...)
103
+ * blocks, closures
104
+ * @instance_eval@, @define_method@, ... (only when the block is given directly)
105
+ * correct constant and class variable lookup
106
+ * @raise@, @rescue@, @retry@, @ensure@
107
+ * ...
108
+
109
+ Things that (currently) don't work:
110
+
111
+ * @break@ with a value from inside a block
112
+ * @return@ from inside a block
113
+ * @return@, @break@, @next@, @redo@ inside @ensure@
114
+ * @defined?@ is not implemented for all cases
115
+ * block pass (passing a proc as block to a method) works, but only through a
116
+ hack and it doesn't work (correctly) for things like @instance_eval@
117
+
118
+ Some of the above things might be fixed in future versions.
119
+
120
+ Things that don't work as expected and probably never will:
121
+
122
+ * methods like @local_variables@, that depend on a Ruby SCOPE
123
+ * interoperability with @eval(str)@ and similar methods that parse a string and
124
+ eval it; these methods work, but they might not behave as expected (i.e.
125
+ access to local variables and similar things won't work, see above)
126
+ * @callcc@ works but might behave strangely (in particular local variables
127
+ might behave wrong)
128
+ * some more things, please see "limitations":limitations.html
129
+
130
+ Ruby2CExtension will translate and compile Ruby files using one or more of the
131
+ above functionalities without a warning (for some cases warnings can be
132
+ enabled, see "rb2cx":rb2cx.html), so if your Ruby code uses such
133
+ functionality, please verify that the compiled C extension works as expected.
134
+
135
+ For more details please see "limitations":limitations.html.
136
+
137
+
138
+ h2. Usage
139
+
140
+ There are two "interfaces" to use Ruby2CExtension:
141
+
142
+ * "rb2cx":rb2cx.html: the command line compiler.
143
+ * "Eval2C":eval2c.html: a class that allows dynamic compilation of Ruby code
144
+ at runtime.
145
+
146
+ Please see their respective documentations.
147
+
148
+
149
+ h2. Feedback
150
+
151
+ If you find a bug, think that something doesn't work as it should or have
152
+ other suggestions, then please don't hesitate to "contact
153
+ me":mailto:dbatml@remove_nospam.gmx.de and tell me about it.
154
+
155
+ I am also interested to know if Ruby2CExtension works under Windows (or other
156
+ non Linux platforms).
157
+
158
+
159
+ h2. Thanks
160
+
161
+ I would like to thank Eric Mahurin for various good ideas for
162
+ "optimizations":optimizations.html and for inspiring "Eval2C":eval2c.html.
163
+
164
+
165
+ h2. License
166
+
167
+ Copyright 2006-2007 "Dominik Bathon":mailto:dbatml@remove_nospam.gmx.de.
168
+
169
+ Ruby2CExtension is licensed under the same terms as Ruby.