| |   |
| 1 | # Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com> |
| 2 | # |
| 3 | # Permission is hereby granted, free of charge, to any person obtaining |
| 4 | # a copy of this software and associated documentation files (the |
| 5 | # "Software"), to deal in the Software without restriction, including |
| 6 | # without limitation the rights to use, copy, modify, merge, |
| 7 | # publish, distribute, sublicense, and/or sell copies of the Software, |
| 8 | # and to permit persons to whom the Software is furnished to do so, |
| 9 | # subject to the following conditions: |
| 10 | # |
| 11 | # The above copyright notice and this permission notice shall be |
| 12 | # included in all copies or substantial portions of the Software. |
| 13 | # |
| 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 18 | # BE LIABLE |
| 19 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 20 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 | |
| 23 | require 'pathname' |
| 24 | |
| 25 | # Rust is a Ruby bindings generator, developed by Diego Pettenò |
| 26 | # <flameeyes@gmail.com>, based on a simpler Ruby bindings generator |
| 27 | # that was used for RubyTag++ and ruby-hunspell. |
| 28 | # |
| 29 | # The original bindings generator was designed to permit a 1:1 mapping |
| 30 | # between C++ classes and Ruby classes, as otherwise writing Ruby |
| 31 | # bindings for a C++-based library would have consisted of a long |
| 32 | # series of generic functions to convert the types from one language |
| 33 | # to the other and to call the methods. |
| 34 | # |
| 35 | # Most C bindings, instead, either writes a lot of C code to create |
| 36 | # "fake" Classes out of a vaguely object-oriented C API, or simply |
| 37 | # create a module where to put all the C functions to call. |
| 38 | # |
| 39 | # The objective of Rust is to allow the description of a C or C++ |
| 40 | # interface, through the creation of 1:1 class mappings or the design |
| 41 | # of "fake" classes out of C functions, without the need to actually |
| 42 | # write all the generic code, as that does not really change beside |
| 43 | # names, types and parameters. |
| 44 | module Rust |
| 45 | |
| 46 | # The Template singleton class is used to simulate a big hash of |
| 47 | # templates, loaded with the data from the templates/ subdirectory. |
| 48 | # In truth the templates are loaded only when requested, removing |
| 49 | # the one-line comments found inside the files (as they are usually |
| 50 | # just for documenting that particular template). |
| 51 | class Templates |
| 52 | @cache = { } |
| 53 | @tpls_dir = (Pathname File.dirname(__FILE__)) + "rust/templates" |
| 54 | |
| 55 | def Templates.[](name) |
| 56 | return @cache[name].dup if @cache[name] |
| 57 | |
| 58 | pn = @tpls_dir + "#{name}.rusttpl" |
| 59 | raise "Template #{name} not found." unless pn.exist? |
| 60 | |
| 61 | @cache[name] = pn.read.gsub(/\/\/.*$\n?/, '') |
| 62 | return @cache[name].dup |
| 63 | end |
| 64 | end |
| 65 | end |
| 66 | |
| 67 | require 'rust/bindings' |
| toggle raw diff |
--- /dev/null
+++ b/lib/rust.rb
@@ -0,0 +1,67 @@
+# Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE
+# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'pathname'
+
+# Rust is a Ruby bindings generator, developed by Diego Pettenò
+# <flameeyes@gmail.com>, based on a simpler Ruby bindings generator
+# that was used for RubyTag++ and ruby-hunspell.
+#
+# The original bindings generator was designed to permit a 1:1 mapping
+# between C++ classes and Ruby classes, as otherwise writing Ruby
+# bindings for a C++-based library would have consisted of a long
+# series of generic functions to convert the types from one language
+# to the other and to call the methods.
+#
+# Most C bindings, instead, either writes a lot of C code to create
+# "fake" Classes out of a vaguely object-oriented C API, or simply
+# create a module where to put all the C functions to call.
+#
+# The objective of Rust is to allow the description of a C or C++
+# interface, through the creation of 1:1 class mappings or the design
+# of "fake" classes out of C functions, without the need to actually
+# write all the generic code, as that does not really change beside
+# names, types and parameters.
+module Rust
+
+ # The Template singleton class is used to simulate a big hash of
+ # templates, loaded with the data from the templates/ subdirectory.
+ # In truth the templates are loaded only when requested, removing
+ # the one-line comments found inside the files (as they are usually
+ # just for documenting that particular template).
+ class Templates
+ @cache = { }
+ @tpls_dir = (Pathname File.dirname(__FILE__)) + "rust/templates"
+
+ def Templates.[](name)
+ return @cache[name].dup if @cache[name]
+
+ pn = @tpls_dir + "#{name}.rusttpl"
+ raise "Template #{name} not found." unless pn.exist?
+
+ @cache[name] = pn.read.gsub(/\/\/.*$\n?/, '')
+ return @cache[name].dup
+ end
+ end
+end
+
+require 'rust/bindings' |
| |   |
| 1 | # Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com> |
| 2 | # |
| 3 | # Permission is hereby granted, free of charge, to any person obtaining |
| 4 | # a copy of this software and associated documentation files (the |
| 5 | # "Software"), to deal in the Software without restriction, including |
| 6 | # without limitation the rights to use, copy, modify, merge, |
| 7 | # publish, distribute, sublicense, and/or sell copies of the Software, |
| 8 | # and to permit persons to whom the Software is furnished to do so, |
| 9 | # subject to the following conditions: |
| 10 | # |
| 11 | # The above copyright notice and this permission notice shall be |
| 12 | # included in all copies or substantial portions of the Software. |
| 13 | # |
| 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 18 | # BE LIABLE |
| 19 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 20 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 | |
| 23 | require 'rust/namespace' |
| 24 | |
| 25 | module Rust |
| 26 | # Base class to use to create bindings for ruby. |
| 27 | # You shouldn't instantiate this manually, but rather use the |
| 28 | # create_bindings function. |
| 29 | class Bindings |
| 30 | # Constant to use with Bindings.create_bindings to state that the |
| 31 | # bindings that are to be created are for a C library. |
| 32 | LangC = "c" |
| 33 | |
| 34 | # Constant to use with Bindings.create_bindings to state that the |
| 35 | # bindings that are to be created are for a C++ library. |
| 36 | LangCxx = "cxx" |
| 37 | |
| 38 | # Constant to use with include_header method to state that the |
| 39 | # included header is a system library header. |
| 40 | HeaderGlobal = "global" |
| 41 | |
| 42 | # Constant to use with include_header method to state that the |
| 43 | # included header is a local header. |
| 44 | HeaderLocal = "local" |
| 45 | |
| 46 | def initialize(name, lang) # :notnew: |
| 47 | @name = name |
| 48 | @lang = lang |
| 49 | |
| 50 | @modules = Array.new |
| 51 | @cxx_includes = "" |
| 52 | @c_includes = "" |
| 53 | end |
| 54 | |
| 55 | # This function is called when creating Ruby bindings for a |
| 56 | # library. |
| 57 | # |
| 58 | # The first parameter has to be one between Rust::Bindings::LangC |
| 59 | # or Rust::Bindings::LangCxx, and tells Rust which programming |
| 60 | # language the library to bind is written into. |
| 61 | # |
| 62 | # Please note that Rust always generates C++ code even when |
| 63 | # binding a library written in C, as STL templates are used all |
| 64 | # over the generics code. |
| 65 | def Bindings.create_bindings(lang, name) |
| 66 | bindings = |
| 67 | case lang |
| 68 | when Bindings::LangCxx, Bindings::LangC |
| 69 | bindings = Bindings.new(name, lang) |
| 70 | else |
| 71 | raise ArgumentError, "#{lang} is not a valid value for type parameter" |
| 72 | end |
| 73 | |
| 74 | yield bindings |
| 75 | |
| 76 | header = File.new("#{name}.hh", File::CREAT|File::TRUNC|File::RDWR) |
| 77 | unit = File.new("#{name}.cc", File::CREAT|File::TRUNC|File::RDWR) |
| 78 | |
| 79 | header.puts bindings.header |
| 80 | unit.puts bindings.unit |
| 81 | |
| 82 | header.close |
| 83 | unit.close |
| 84 | end |
| 85 | |
| 86 | # Adds an include header with the specified name. |
| 87 | # This function adds to the list of header files to include the |
| 88 | # one with the specified name. |
| 89 | # |
| 90 | # If the scope paramether is set to Bindings.HeaderLocal, the name of |
| 91 | # the header file will be enclosed in double quotes ("") while |
| 92 | # including it, while it will be included it in angle quotes if |
| 93 | # the parameter is set to Bindings.HeaderGlobal (the default). |
| 94 | def include_header(name, scope = Bindings::HeaderGlobal, lang = @lang) |
| 95 | name = |
| 96 | case scope |
| 97 | when HeaderLocal then "\"#{name}\"" |
| 98 | when HeaderGlobal then "<#{name}>" |
| 99 | else |
| 100 | raise ArgumentError, "#{scope} not a valid value for scope parameter." |
| 101 | end |
| 102 | |
| 103 | case lang |
| 104 | when Bindings::LangCxx |
| 105 | @cxx_includes << "\n#include #{name}" |
| 106 | when Bindings::LangC |
| 107 | @c_includes << "\n#include #{name}" |
| 108 | end |
| 109 | end |
| 110 | |
| 111 | # Binds a new Namespace to a Ruby module; the name parameter is |
| 112 | # used as the name of the module, while the cxxname one (if not |
| 113 | # null) is used to indicate the actual C++ namespace to use; when |
| 114 | # binding a C library, you should rather use the add_module |
| 115 | # function, although that's just a partial wrapper around this one. |
| 116 | def add_namespace(name, cxxname = nil) |
| 117 | cxxname = name if cxxname == nil |
| 118 | |
| 119 | ns = Namespace.new(name, cxxname) |
| 120 | |
| 121 | yield ns |
| 122 | |
| 123 | @modules << ns |
| 124 | end |
| 125 | |
| 126 | # Create a new Ruby module with the given name; this is used when |
| 127 | # binding C libraries, as they don't use namespace, so you have to |
| 128 | # create the modules from scratch. |
| 129 | def add_module(name) |
| 130 | add_namespace(name, "") |
| 131 | end |
| 132 | |
| 133 | # Returns the content of the header for the bindings, recursively |
| 134 | # calling the proper functions to get the declarations for the |
| 135 | # modules bound and so on. |
| 136 | # |
| 137 | # This should *never* be used directly |
| 138 | def header |
| 139 | Templates["BindingsHeader"]. |
| 140 | gsub("!bindings_name!", @name). |
| 141 | gsub("!modules_declaration!", @modules.collect { |ns| ns.declaration }.join("\n")). |
| 142 | gsub("!cxx_includes!", @cxx_includes). |
| 143 | gsub("!c_includes!", @c_includes) |
| 144 | end |
| 145 | |
| 146 | # Returns the content of the unit for the bindings, recursively |
| 147 | # calling the proper functions to get the definitions and the |
| 148 | # initialisation function for the modules bound and so on. |
| 149 | # |
| 150 | # This should *never* be used directly |
| 151 | def unit |
| 152 | Templates["BindingsUnit"]. |
| 153 | gsub("!bindings_name!", @name). |
| 154 | gsub("!modules_initialization!", @modules.collect { |ns| ns.initialization }.join("\n")). |
| 155 | gsub("!modules_definition!", @modules.collect { |ns| ns.definition }.join("\n")) |
| 156 | end |
| 157 | end |
| 158 | |
| 159 | end |
| toggle raw diff |
--- /dev/null
+++ b/lib/rust/bindings.rb
@@ -0,0 +1,159 @@
+# Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE
+# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'rust/namespace'
+
+module Rust
+ # Base class to use to create bindings for ruby.
+ # You shouldn't instantiate this manually, but rather use the
+ # create_bindings function.
+ class Bindings
+ # Constant to use with Bindings.create_bindings to state that the
+ # bindings that are to be created are for a C library.
+ LangC = "c"
+
+ # Constant to use with Bindings.create_bindings to state that the
+ # bindings that are to be created are for a C++ library.
+ LangCxx = "cxx"
+
+ # Constant to use with include_header method to state that the
+ # included header is a system library header.
+ HeaderGlobal = "global"
+
+ # Constant to use with include_header method to state that the
+ # included header is a local header.
+ HeaderLocal = "local"
+
+ def initialize(name, lang) # :notnew:
+ @name = name
+ @lang = lang
+
+ @modules = Array.new
+ @cxx_includes = ""
+ @c_includes = ""
+ end
+
+ # This function is called when creating Ruby bindings for a
+ # library.
+ #
+ # The first parameter has to be one between Rust::Bindings::LangC
+ # or Rust::Bindings::LangCxx, and tells Rust which programming
+ # language the library to bind is written into.
+ #
+ # Please note that Rust always generates C++ code even when
+ # binding a library written in C, as STL templates are used all
+ # over the generics code.
+ def Bindings.create_bindings(lang, name)
+ bindings =
+ case lang
+ when Bindings::LangCxx, Bindings::LangC
+ bindings = Bindings.new(name, lang)
+ else
+ raise ArgumentError, "#{lang} is not a valid value for type parameter"
+ end
+
+ yield bindings
+
+ header = File.new("#{name}.hh", File::CREAT|File::TRUNC|File::RDWR)
+ unit = File.new("#{name}.cc", File::CREAT|File::TRUNC|File::RDWR)
+
+ header.puts bindings.header
+ unit.puts bindings.unit
+
+ header.close
+ unit.close
+ end
+
+ # Adds an include header with the specified name.
+ # This function adds to the list of header files to include the
+ # one with the specified name.
+ #
+ # If the scope paramether is set to Bindings.HeaderLocal, the name of
+ # the header file will be enclosed in double quotes ("") while
+ # including it, while it will be included it in angle quotes if
+ # the parameter is set to Bindings.HeaderGlobal (the default).
+ def include_header(name, scope = Bindings::HeaderGlobal, lang = @lang)
+ name =
+ case scope
+ when HeaderLocal then "\"#{name}\""
+ when HeaderGlobal then "<#{name}>"
+ else
+ raise ArgumentError, "#{scope} not a valid value for scope parameter."
+ end
+
+ case lang
+ when Bindings::LangCxx
+ @cxx_includes << "\n#include #{name}"
+ when Bindings::LangC
+ @c_includes << "\n#include #{name}"
+ end
+ end
+
+ # Binds a new Namespace to a Ruby module; the name parameter is
+ # used as the name of the module, while the cxxname one (if not
+ # null) is used to indicate the actual C++ namespace to use; when
+ # binding a C library, you should rather use the add_module
+ # function, although that's just a partial wrapper around this one.
+ def add_namespace(name, cxxname = nil)
+ cxxname = name if cxxname == nil
+
+ ns = Namespace.new(name, cxxname)
+
+ yield ns
+
+ @modules << ns
+ end
+
+ # Create a new Ruby module with the given name; this is used when
+ # binding C libraries, as they don't use namespace, so you have to
+ # create the modules from scratch.
+ def add_module(name)
+ add_namespace(name, "")
+ end
+
+ # Returns the content of the header for the bindings, recursively
+ # calling the proper functions to get the declarations for the
+ # modules bound and so on.
+ #
+ # This should *never* be used directly
+ def header
+ Templates["BindingsHeader"].
+ gsub("!bindings_name!", @name).
+ gsub("!modules_declaration!", @modules.collect { |ns| ns.declaration }.join("\n")).
+ gsub("!cxx_includes!", @cxx_includes).
+ gsub("!c_includes!", @c_includes)
+ end
+
+ # Returns the content of the unit for the bindings, recursively
+ # calling the proper functions to get the definitions and the
+ # initialisation function for the modules bound and so on.
+ #
+ # This should *never* be used directly
+ def unit
+ Templates["BindingsUnit"].
+ gsub("!bindings_name!", @name).
+ gsub("!modules_initialization!", @modules.collect { |ns| ns.initialization }.join("\n")).
+ gsub("!modules_definition!", @modules.collect { |ns| ns.definition }.join("\n"))
+ end
+ end
+
+end |
| |   |
| 1 | # Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com> |
| 2 | # |
| 3 | # Permission is hereby granted, free of charge, to any person obtaining |
| 4 | # a copy of this software and associated documentation files (the |
| 5 | # "Software"), to deal in the Software without restriction, including |
| 6 | # without limitation the rights to use, copy, modify, merge, |
| 7 | # publish, distribute, sublicense, and/or sell copies of the Software, |
| 8 | # and to permit persons to whom the Software is furnished to do so, |
| 9 | # subject to the following conditions: |
| 10 | # |
| 11 | # The above copyright notice and this permission notice shall be |
| 12 | # included in all copies or substantial portions of the Software. |
| 13 | # |
| 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 18 | # BE LIABLE |
| 19 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 20 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 | |
| 23 | require 'rust/container' |
| 24 | require 'rust/function' |
| 25 | |
| 26 | module Rust |
| 27 | class Class < Container |
| 28 | attr_reader :name, :cname |
| 29 | attr_reader :varname, :varcname, :ptrmap, :function_free, :parent_varname |
| 30 | |
| 31 | # Rust::Namespace object for the class, used to get the proper C++ |
| 32 | # name. |
| 33 | attr_reader :namespace |
| 34 | |
| 35 | # This function initializes the Class instance by setting the |
| 36 | # values to the attributes defining its namespace, name |
| 37 | # and a few other needed information. |
| 38 | # |
| 39 | # Don't call this function directly, use Namespace.add_cxx_class |
| 40 | def initialize(name, namespace) # :notnew: |
| 41 | super() |
| 42 | |
| 43 | @name = name |
| 44 | @namespace = namespace |
| 45 | |
| 46 | @varname = "#{@namespace.name.gsub("::", "_")}_#{@name}" |
| 47 | @parent_varname = "rb_cObject" |
| 48 | |
| 49 | @ptrmap = "#{@namespace.name.gsub("::", "_")}_#{@name}_ptrMap" |
| 50 | @function_free = "#{varname}_free" |
| 51 | |
| 52 | @cname = @namespace.cname ? "#{@namespace.cname}::#{@name}" : @name |
| 53 | @varcname = @cname.sub("*", "Ptr").gsub("::", "_").gsub(' ', '') |
| 54 | |
| 55 | @declaration_template = Templates["ClassDeclarations"] |
| 56 | @initialization_template = Templates["ClassInitialize"] |
| 57 | |
| 58 | add_expansion 'class_varname', 'varname' |
| 59 | add_expansion 'class_varcname', 'varcname' |
| 60 | add_expansion 'c_class_name', 'cname' |
| 61 | add_expansion 'c_class_basename', '@name.split("::").last' |
| 62 | add_expansion 'class_ptrmap', 'ptrmap' |
| 63 | add_expansion 'class_free_function', '@function_free' |
| 64 | add_expansion 'parent_varname', '@parent_varname' |
| 65 | end |
| 66 | |
| 67 | # Adds a new constructor for the class. |
| 68 | # This function creates a new constructor method for the C/C++ |
| 69 | # class to bind, and yields it so that parameters can be added |
| 70 | # afterward. |
| 71 | def add_constructor |
| 72 | constructor = self.class::Constructor.new(self) |
| 73 | |
| 74 | begin |
| 75 | yield constructor |
| 76 | rescue LocalJumpError |
| 77 | # Ignore this, we can easily have methods without parameters |
| 78 | # or other extra informations. |
| 79 | end |
| 80 | |
| 81 | @children << constructor |
| 82 | |
| 83 | return constructor |
| 84 | end |
| 85 | |
| 86 | # Adds a new method for the class. |
| 87 | # This function adds a new generic method for the class. In the |
| 88 | # case of C++ classes, this is an actual method of the bound |
| 89 | # class, while in case of Class Wrappers, this is just a function |
| 90 | # that expects to find a static parameter that is the instance |
| 91 | # pointer itself. |
| 92 | def add_method(name, return_value = "void", bindname = name) |
| 93 | method = self.class::Method.new({ :name => name, |
| 94 | :bindname => bindname, |
| 95 | :return => return_value, |
| 96 | :klass => self |
| 97 | }) |
| 98 | |
| 99 | begin |
| 100 | yield method |
| 101 | rescue LocalJumpError |
| 102 | # Ignore this, we can easily have methods without parameters |
| 103 | # or other extra informations. |
| 104 | end |
| 105 | |
| 106 | @children << method |
| 107 | |
| 108 | return method |
| 109 | end |
| 110 | |
| 111 | # Adds a new variable for the class. It's not an actual variable, |
| 112 | # as hopefully there aren't global or class public variables in |
| 113 | # any library. |
| 114 | # These virtual variables have setter and getter methods, usually |
| 115 | # called 'var' and 'setVar' in C++ (or 'getVar' and 'setVar'), and |
| 116 | # are mapped to 'var' and 'var=' in Ruby, so that setting the |
| 117 | # variable in Ruby will just call the setter method. |
| 118 | def add_variable(name, type, getter = nil, setter = nil) |
| 119 | getter = name unless getter |
| 120 | setter = "set" + name[0..0].capitalize + name[1..-1] unless |
| 121 | setter |
| 122 | |
| 123 | method_get = add_method getter, type |
| 124 | method_get.add_alias name |
| 125 | |
| 126 | method_set = add_method setter, "void" |
| 127 | method_set.add_alias "#{name}=" |
| 128 | |
| 129 | begin |
| 130 | yield method_get, method_set |
| 131 | rescue LocalJumpError |
| 132 | # Ignore this, we can easily have methods without parameters |
| 133 | # or other extra informations. |
| 134 | end |
| 135 | |
| 136 | method_set.add_parameter type, "value" |
| 137 | |
| 138 | return [method_get, method_set] |
| 139 | end |
| 140 | |
| 141 | # This class is used to represent a method for a C/C++ class bound |
| 142 | # in a Ruby extension. Through an object of this class you can add |
| 143 | # parameters and more to the method. |
| 144 | class Method < Function |
| 145 | |
| 146 | # Initialisation function, calls Function.initialize and sets |
| 147 | # the important parameters that differs from a generic function |
| 148 | def initialize(params) # :notnew: |
| 149 | params[:parent] = params[:klass] |
| 150 | super |
| 151 | |
| 152 | @varname = |
| 153 | "f#{@parent.namespace.name.gsub("::","_")}_#{@parent.name}_#{@name}" |
| 154 | |
| 155 | @definition_template = Templates["CxxMethodStub"] |
| 156 | @initialization_template = Templates["MethodInitBinding"] |
| 157 | end |
| 158 | end |
| 159 | |
| 160 | # This class is used to represente the constructor of a C++ class |
| 161 | # bound in a Ruby extension. |
| 162 | class Constructor < Function |
| 163 | |
| 164 | # Initialisation function, calls Function.initialise, but accepts |
| 165 | # only a single parameter, the class the constructor belong to. |
| 166 | def initialize(klass) # :notnew: |
| 167 | super({ |
| 168 | :parent => klass, |
| 169 | :bindname => "initialize", |
| 170 | :name => klass.name |
| 171 | }) |
| 172 | |
| 173 | @definition_template = Templates["ConstructorStub"] |
| 174 | end |
| 175 | |
| 176 | def bind_call(nparam = nil) |
| 177 | "#{raw_call(nparam)};\n" |
| 178 | end |
| 179 | end |
| 180 | |
| 181 | end |
| 182 | end |
| toggle raw diff |
--- /dev/null
+++ b/lib/rust/class.rb
@@ -0,0 +1,182 @@
+# Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE
+# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'rust/container'
+require 'rust/function'
+
+module Rust
+ class Class < Container
+ attr_reader :name, :cname
+ attr_reader :varname, :varcname, :ptrmap, :function_free, :parent_varname
+
+ # Rust::Namespace object for the class, used to get the proper C++
+ # name.
+ attr_reader :namespace
+
+ # This function initializes the Class instance by setting the
+ # values to the attributes defining its namespace, name
+ # and a few other needed information.
+ #
+ # Don't call this function directly, use Namespace.add_cxx_class
+ def initialize(name, namespace) # :notnew:
+ super()
+
+ @name = name
+ @namespace = namespace
+
+ @varname = "#{@namespace.name.gsub("::", "_")}_#{@name}"
+ @parent_varname = "rb_cObject"
+
+ @ptrmap = "#{@namespace.name.gsub("::", "_")}_#{@name}_ptrMap"
+ @function_free = "#{varname}_free"
+
+ @cname = @namespace.cname ? "#{@namespace.cname}::#{@name}" : @name
+ @varcname = @cname.sub("*", "Ptr").gsub("::", "_").gsub(' ', '')
+
+ @declaration_template = Templates["ClassDeclarations"]
+ @initialization_template = Templates["ClassInitialize"]
+
+ add_expansion 'class_varname', 'varname'
+ add_expansion 'class_varcname', 'varcname'
+ add_expansion 'c_class_name', 'cname'
+ add_expansion 'c_class_basename', '@name.split("::").last'
+ add_expansion 'class_ptrmap', 'ptrmap'
+ add_expansion 'class_free_function', '@function_free'
+ add_expansion 'parent_varname', '@parent_varname'
+ end
+
+ # Adds a new constructor for the class.
+ # This function creates a new constructor method for the C/C++
+ # class to bind, and yields it so that parameters can be added
+ # afterward.
+ def add_constructor
+ constructor = self.class::Constructor.new(self)
+
+ begin
+ yield constructor
+ rescue LocalJumpError
+ # Ignore this, we can easily have methods without parameters
+ # or other extra informations.
+ end
+
+ @children << constructor
+
+ return constructor
+ end
+
+ # Adds a new method for the class.
+ # This function adds a new generic method for the class. In the
+ # case of C++ classes, this is an actual method of the bound
+ # class, while in case of Class Wrappers, this is just a function
+ # that expects to find a static parameter that is the instance
+ # pointer itself.
+ def add_method(name, return_value = "void", bindname = name)
+ method = self.class::Method.new({ :name => name,
+ :bindname => bindname,
+ :return => return_value,
+ :klass => self
+ })
+
+ begin
+ yield method
+ rescue LocalJumpError
+ # Ignore this, we can easily have methods without parameters
+ # or other extra informations.
+ end
+
+ @children << method
+
+ return method
+ end
+
+ # Adds a new variable for the class. It's not an actual variable,
+ # as hopefully there aren't global or class public variables in
+ # any library.
+ # These virtual variables have setter and getter methods, usually
+ # called 'var' and 'setVar' in C++ (or 'getVar' and 'setVar'), and
+ # are mapped to 'var' and 'var=' in Ruby, so that setting the
+ # variable in Ruby will just call the setter method.
+ def add_variable(name, type, getter = nil, setter = nil)
+ getter = name unless getter
+ setter = "set" + name[0..0].capitalize + name[1..-1] unless
+ setter
+
+ method_get = add_method getter, type
+ method_get.add_alias name
+
+ method_set = add_method setter, "void"
+ method_set.add_alias "#{name}="
+
+ begin
+ yield method_get, method_set
+ rescue LocalJumpError
+ # Ignore this, we can easily have methods without parameters
+ # or other extra informations.
+ end
+
+ method_set.add_parameter type, "value"
+
+ return [method_get, method_set]
+ end
+
+ # This class is used to represent a method for a C/C++ class bound
+ # in a Ruby extension. Through an object of this class you can add
+ # parameters and more to the method.
+ class Method < Function
+
+ # Initialisation function, calls Function.initialize and sets
+ # the important parameters that differs from a generic function
+ def initialize(params) # :notnew:
+ params[:parent] = params[:klass]
+ super
+
+ @varname =
+ "f#{@parent.namespace.name.gsub("::","_")}_#{@parent.name}_#{@name}"
+
+ @definition_template = Templates["CxxMethodStub"]
+ @initialization_template = Templates["MethodInitBinding"]
+ end
+ end
+
+ # This class is used to represente the constructor of a C++ class
+ # bound in a Ruby extension.
+ class Constructor < Function
+
+ # Initialisation function, calls Function.initialise, but accepts
+ # only a single parameter, the class the constructor belong to.
+ def initialize(klass) # :notnew:
+ super({
+ :parent => klass,
+ :bindname => "initialize",
+ :name => klass.name
+ })
+
+ @definition_template = Templates["ConstructorStub"]
+ end
+
+ def bind_call(nparam = nil)
+ "#{raw_call(nparam)};\n"
+ end
+ end
+
+ end
+end |
| |   |
| 1 | # Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com> |
| 2 | # |
| 3 | # Permission is hereby granted, free of charge, to any person obtaining |
| 4 | # a copy of this software and associated documentation files (the |
| 5 | # "Software"), to deal in the Software without restriction, including |
| 6 | # without limitation the rights to use, copy, modify, merge, |
| 7 | # publish, distribute, sublicense, and/or sell copies of the Software, |
| 8 | # and to permit persons to whom the Software is furnished to do so, |
| 9 | # subject to the following conditions: |
| 10 | # |
| 11 | # The above copyright notice and this permission notice shall be |
| 12 | # included in all copies or substantial portions of the Software. |
| 13 | # |
| 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 18 | # BE LIABLE |
| 19 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 20 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 | |
| 23 | require 'rust/element' |
| 24 | |
| 25 | module Rust |
| 26 | # This class represents a C/C++ constants or enumeration, it is |
| 27 | # simply going to map a Ruby constant with the given name under its |
| 28 | # parent with the given value |
| 29 | class Constant < Element |
| 30 | def initialize(name, value, parent) |
| 31 | super() |
| 32 | |
| 33 | @name = name |
| 34 | @value = value |
| 35 | @parent = parent |
| 36 | |
| 37 | @declaration_template = "" |
| 38 | @definition_template = "" |
| 39 | @initialization_template = |
| 40 | "rb_define_const(r!parent_varname!, \"!name!\", cxx2ruby(!value!));\n" |
| 41 | |
| 42 | add_expansion 'parent_varname', '@parent.varname' |
| 43 | add_expansion 'name', '@name' |
| 44 | add_expansion 'value', '@value' |
| 45 | end |
| 46 | end |
| 47 | |
| 48 | end |
| toggle raw diff |
--- /dev/null
+++ b/lib/rust/constants.rb
@@ -0,0 +1,48 @@
+# Copyright (c) 2005-2007 Diego Pettenò <flameeyes@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE
+# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'rust/element'
+
+module Rust
+ # This class represents a C/C++ constants or enumeration, it is
+ # simply going to map a Ruby constant with the given name under its
+ # parent with the given value
+ class Constant < Element
+ def initialize(name, value, parent)
+ super()
+
+ @name = name
+ @value = value
+ @parent = parent
+
+ @declaration_template = ""
+ @definition_template = ""
+ @initialization_template =
+ "rb_define_const(r!parent_varname!, \"!name!\", cxx2ruby(!value!));\n"
+
+ add_expansion 'parent_varname', '@parent.varname'
+ add_expansion 'name', '@name'
+ add_expansion 'value', '@value'
+ end
+ end
+
+end |
| |   |
| 1 | # Copyright (c) 2007 Diego Pettenò <flameeyes@gmail.com> |
| 2 | # |
| 3 | # Permission is hereby granted, free of charge, to any person obtaining |
| 4 | # a copy of this software and associated documentation files (the |
| 5 | # "Software"), to deal in the Software without restriction, including |
| 6 | # without limitation the rights to use, copy, modify, merge, |
| 7 | # publish, distribute, sublicense, and/or sell copies of the Software, |
| 8 | # and to permit persons to whom the Software is furnished to do so, |
| 9 | # subject to the following conditions: |
| 10 | # |
| 11 | # The above copyright notice and this permission notice shall be |
| 12 | # included in all copies or substantial portions of the Software. |
| 13 | # |
| 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 18 | # BE LIABLE |
| 19 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 20 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 | |
| 23 | require 'rust/element' |
| 24 | require 'rust/enum' |
| 25 | |
| 26 | module Rust |
| 27 | # This class defines a 'container', an element that can contain |
| 28 | # functions, constants and classes. Both modules and classes are |
| 29 | # modules, as you can have singleton methods and constants in both |
| 30 | # of them |
| 31 | class Container < Element |
| 32 | def add_cxx_class(name, parent = nil) |
| 33 | klass = CxxClass.new(name, self, parent) |
| 34 | |
| 35 | yield klass |
| 36 | |
| 37 | @children << klass |
| 38 | return klass |
| 39 | end |
| 40 | |
| 41 | def add_class_wrapper(name, type) |
| 42 | klass = ClassWrapper.new(name, type, self) |
| 43 | |
| 44 | yield klass |
| 45 | |
| 46 | @children << klass |
| 47 | return klass |
| 48 | end |
| 49 | |
| 50 | def add_function(name, return_value = "void", bindname = name) |
| 51 | function = Function.new({ :name => name, |
| 52 | :bindname => bindname, |
| 53 | :return => return_value, |
| 54 | :parent => self |
| 55 | }) |
| 56 | |
| 57 | begin |
| 58 | yield function |
| 59 | rescue LocalJumpError |
| 60 | # Ignore this, we can easily have methods without parameters |
| 61 | # or other extra informations. |
| 62 | end |
| 63 | |
| 64 | @children << function |
| 65 | |
| 66 | return function |
| 67 | end |
| 68 | |
| 69 | def add_constant(name, value = name) |
| 70 | @children << Constant.new(name, value, self) |
| 71 | end |
| 72 | |
| 73 | def add_enum(name, ctype = nil) |
| 74 | enum = Enum.new(name, self, ctype) |
| 75 | |
| 76 | yield enum |
| 77 | |
| 78 | @children << enum |
| 79 | |
| 80 | return enum |
| 81 | end |
| 82 | |
| 83 | def add_namespace(name, cname = name) |
| 84 | ns = Namespace.new(name, cname, self) |
| 85 | |
| 86 | yield ns |
| 87 | |
| 88 | @children << ns |
| 89 | end |
| 90 | |
| 91 | end |
| 92 | end |
| toggle raw diff |
--- /dev/null
+++ b/lib/rust/container.rb
@@ -0,0 +1,92 @@
+# Copyright (c) 2007 Diego Pettenò <flameeyes@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE
+# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'rust/element'
+require 'rust/enum'
+
+module Rust
+ # This class defines a 'container', an element that can contain
+ # functions, constants and classes. Both modules and classes are
+ # modules, as you can have singleton methods and constants in both
+ # of them
+ class Container < Element
+ def add_cxx_class(name, parent = nil)
+ klass = CxxClass.new(name, self, parent)
+
+ yield klass
+
+ @children << klass
+ return klass
+ end
+
+ def add_class_wrapper(name, type)
+ klass = ClassWrapper.new(name, type, self)
+
+ yield klass
+
+ @children << klass
+ return klass
+ end
+
+ def add_function(name, return_value = "void", bindname = name)
+ function = Function.new({ :name => name,
+ :bindname => bindname,
+ :return => return_value,
+ :parent => self
+ })
+
+ begin
+ yield function
+ rescue LocalJumpError
+ # Ignore this, we can easily have methods without parameters
+ # or other extra informations.
+ end
+
+ @children << function
+
+ return function
+ end
+
+ def add_constant(name, value = name)
+ @children << Constant.new(name, value, self)
+ end
+
+ def add_enum(name, ctype = nil)
+ enum = Enum.new(name, self, ctype)
+
+ yield enum
+
+ @children << enum
+
+ return enum
+ end
+
+ def add_namespace(name, cname = name)
+ ns = Namespace.new(name, cname, self)
+
+ yield ns
+
+ @children << ns
+ end
+
+ end
+end |