rbind 0.0.1 → 0.0.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.
data/lib/rbind/core.rb CHANGED
@@ -11,3 +11,4 @@ require 'rbind/core/rsetter.rb'
11
11
  require 'rbind/core/rnamespace.rb'
12
12
  require 'rbind/core/rstruct.rb'
13
13
  require 'rbind/core/rclass.rb'
14
+ require 'rbind/core/rvector.rb'
@@ -4,7 +4,7 @@ module Rbind
4
4
  class << self
5
5
  attr_accessor :default_type_names
6
6
  end
7
- self.default_type_names = [:int,:int64,:bool,:double,:float,:void,:char,:size_t]
7
+ self.default_type_names = [:uint64,:int,:int64,:bool,:double,:float,:void,:char,:size_t]
8
8
 
9
9
  attr_reader :operations
10
10
  attr_reader :operation_alias
@@ -121,11 +121,11 @@ module Rbind
121
121
  op.alias
122
122
  elsif op.alias
123
123
  name = "#{op.alias}#{@operations[op.name].size+1}"
124
- ::Rbind.log.info "name clash: aliasing #{op.alias} --> #{name}"
124
+ ::Rbind.log.debug "name clash: aliasing #{op.alias} --> #{name}"
125
125
  name
126
126
  else
127
127
  name = "#{op.name}#{@operations[op.name].size+1}"
128
- ::Rbind.log.info "name clash: #{op.name} --> #{name}"
128
+ ::Rbind.log.debug "name clash: #{op.name} --> #{name}"
129
129
  name
130
130
  end
131
131
  @operations[op.name] << op
@@ -142,7 +142,7 @@ module Rbind
142
142
  current_type = if temp
143
143
  temp
144
144
  else
145
- ::Rbind.log.info "missing namespace: add #{current_type.full_name unless current_type.root?}::#{name}"
145
+ ::Rbind.log.debug "missing namespace: add #{current_type.full_name unless current_type.root?}::#{name}"
146
146
  current_type.add_type(RNamespace.new(name))
147
147
  end
148
148
  end
@@ -167,7 +167,6 @@ module Rbind
167
167
  def add_default_types
168
168
  add_simple_types RNamespace.default_type_names
169
169
  add_type ::Rbind::RDataType.new("uchar").cname("unsigned char")
170
- add_type ::Rbind::RDataType.new("uint64").typedef("unsigned long long")
171
170
  add_type ::Rbind::RDataType.new("c_string").cname("char *")
172
171
  add_type ::Rbind::RDataType.new("const_c_string").cname("const char *")
173
172
  end
@@ -0,0 +1,27 @@
1
+ module Rbind
2
+ class RVector < RStruct
3
+ def initialize(name,root,type)
4
+ @vector_type = type
5
+ super(name)
6
+ add_operation ROperation.new(self.name,nil)
7
+ add_operation ROperation.new(self.name,nil,RParameter.new("other",self))
8
+
9
+ para = Array.new
10
+ para << RParameter.new("size",root.type("size_t"))
11
+ para << RParameter.new("val",type).default_value(type.full_name)
12
+ add_operation ROperation.new("resize",root.type("void"),para)
13
+ add_operation ROperation.new("size",root.type("size_t"))
14
+ add_operation ROperation.new("capacity",root.type("size_t"))
15
+ add_operation ROperation.new("empty",root.type("bool"))
16
+ add_operation ROperation.new("reserve",root.type("void"),RParameter.new("size",root.type("size_t")))
17
+ add_operation ROperation.new("operator[]",type,RParameter.new("size",root.type("size_t")))
18
+ add_operation ROperation.new("at",type,RParameter.new("size",root.type("size_t")))
19
+ add_operation ROperation.new("front",type)
20
+ add_operation ROperation.new("back",type)
21
+ add_operation ROperation.new("data",root.type("void *"))
22
+ add_operation ROperation.new("push_back",root.type("void"),RParameter.new("other",type))
23
+ add_operation ROperation.new("pop_back",root.type("void"))
24
+ add_operation ROperation.new("swap",root.type("void"),RParameter.new("other",self).add_flag(:IO))
25
+ end
26
+ end
27
+ end
@@ -13,7 +13,7 @@ module Rbind
13
13
  def normalize_flags(line_number,flags)
14
14
  flags.map do |flag|
15
15
  if flag =~ /(\w*)(.*)/
16
- DefaultParser.log.info "input line #{line_number}: ignoring flag #{$2}" unless $2.empty?
16
+ DefaultParser.log.debug "input line #{line_number}: ignoring flag #{$2}" unless $2.empty?
17
17
  $1.to_sym
18
18
  else
19
19
  raise "cannot parse flag #{flag.inspect}"
@@ -113,7 +113,9 @@ module Rbind
113
113
  parents = a[1]
114
114
  parent_classes = if parents
115
115
  parents.split(", ").map do |name|
116
- type(RBase.normalize(name),true)
116
+ t = type(RBase.normalize(name),false)
117
+ # auto add parent class
118
+ t ||= add_type(RClass.new(RBase.normalize(name)))
117
119
  end
118
120
  end
119
121
  t = RClass.new(name,*parent_classes)
@@ -291,6 +291,7 @@ module Rbind
291
291
  attr_accessor :library_name
292
292
  attr_accessor :pkg_config
293
293
  attr_accessor :generate_cmake
294
+ attr_accessor :output_path
294
295
 
295
296
  def initialize(root,library_name)
296
297
  raise "wrong type #{root}" unless root.is_a? RNamespace
@@ -310,7 +311,8 @@ module Rbind
310
311
  @generate_cmake = true
311
312
  end
312
313
 
313
- def generate(path = nil)
314
+ def generate(path = @output_path)
315
+ @output_path = path
314
316
  FileUtils.mkdir_p(path) if path && !File.directory?(path)
315
317
  file_types_hdr = File.new(File.join(path,"types.h"),"w")
316
318
  file_types = File.new(File.join(path,"types.cc"),"w")
@@ -31,7 +31,7 @@ module Rbind
31
31
  elsif parameter.type.name == "double"
32
32
  parameter.default_value.gsub(/\.$/,".0")
33
33
  else
34
- parameter.default_value
34
+ normalize_type_name(parameter.default_value)
35
35
  end
36
36
  else
37
37
  if(parameter.default_value =~ /(\w*)\((.*)\)/)
@@ -282,7 +282,7 @@ module Rbind
282
282
 
283
283
  def add_consts
284
284
  @root.consts.map do |c|
285
- " #{c.name} = #{c.value}\n"
285
+ " #{c.name} = #{GeneratorRuby::normalize_type_name(c.value)}\n"
286
286
  end.join
287
287
  end
288
288
 
@@ -333,6 +333,7 @@ module Rbind
333
333
 
334
334
  attr_accessor :module_name
335
335
  attr_accessor :library_name
336
+ attr_accessor :output_path
336
337
 
337
338
 
338
339
  def initialize(root,module_name ="Rbind",library_name="rbind_lib")
@@ -342,7 +343,8 @@ module Rbind
342
343
  @library_name = library_name
343
344
  end
344
345
 
345
- def generate(path=nil)
346
+ def generate(path=@output_path)
347
+ @output_path = path
346
348
  FileUtils.mkdir_p(path) if path && !File.directory?(path)
347
349
  file_rbind = File.new(File.join(path,"opencv.rb"),"w")
348
350
  file_types = File.new(File.join(path,"opencv_types.rb"),"w")
data/lib/rbind/logger.rb CHANGED
@@ -6,6 +6,7 @@ module Rbind
6
6
  def self.extend_object(o)
7
7
  super
8
8
  o.log = ::Logger.new(STDOUT)
9
+ o.log.level = ::Logger::INFO
9
10
  o.log.progname = o.name
10
11
  end
11
12
  end
data/lib/rbind/rbind.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'open3'
2
+
1
3
  module Rbind
2
4
  class Rbind
3
5
  attr_accessor :parser
@@ -23,16 +25,73 @@ module Rbind
23
25
  end
24
26
  end
25
27
 
28
+ def check_python
29
+ out = IO.popen("which python")
30
+ if(out.read.empty?)
31
+ raise 'Cannot find python interpreter needed for parsing header files'
32
+ end
33
+ in_,out,err = Open3.popen3("python --version")
34
+ str = err.read
35
+ str = if str.empty?
36
+ out.read
37
+ else
38
+ str
39
+ end
40
+ if(str =~ /[a-zA-Z]* (.*)/)
41
+ if $1.to_f < 2.7
42
+ raise "Wrong python version #{$1}. At least python 2.7 is needed for parsing header files"
43
+ end
44
+ else
45
+ raise 'Cannot determine python version needed for parsing header files'
46
+ end
47
+ end
48
+
49
+ def parse_headers(*headers)
50
+ ::Rbind.log.info "parse header files"
51
+ check_python
52
+ headers = if headers.empty?
53
+ includes
54
+ else
55
+ headers
56
+ end
57
+ headers = headers.map do |h|
58
+ "\"#{h}\""
59
+ end
60
+ path = File.join(File.dirname(__FILE__),'tools','hdr_parser.py')
61
+ out = IO.popen("python #{path} #{headers.join(" ")}")
62
+ parser.parse out.read
63
+ end
64
+
65
+ def build
66
+ ::Rbind.log.info "build c wrappers"
67
+ path = File.join(generator_c.output_path,"build")
68
+ FileUtils.mkdir_p(path) if path && !File.directory?(path)
69
+ Dir.chdir(path) do
70
+ if !system("cmake -C ..")
71
+ raise "CMake Configure Error"
72
+ end
73
+ if !system("make")
74
+ raise "Make Build Error"
75
+ end
76
+ end
77
+ if !system("cp #{File.join(path,"lib*.*")} #{generator_ruby.output_path}")
78
+ raise "cannot copy library to #{generator_ruby.output_path}"
79
+ end
80
+ ::Rbind.log.info "all done !"
81
+ end
82
+
26
83
  def generate(c_path = "src",ruby_path = "ruby/lib/#{name.downcase}")
27
84
  generate_c c_path
28
85
  generate_ruby ruby_path
29
86
  end
30
87
 
31
88
  def generate_ruby(path)
89
+ ::Rbind.log.info "generate ruby ffi wrappers"
32
90
  @generator_ruby.generate(path)
33
91
  end
34
92
 
35
93
  def generate_c(path)
94
+ ::Rbind.log.info "generate c wrappers"
36
95
  @generator_c.includes = includes
37
96
  @generator_c.pkg_config = pkg_config
38
97
  @generator_c.generate(path)
@@ -5,7 +5,13 @@ module <%= name %>
5
5
  # low level accessors the wrapped library
6
6
  module Rbind
7
7
  extend FFI::Library
8
- ffi_lib "<%= library_name %>"
8
+
9
+ #load library <%= library_name %>
10
+ path = Dir.chdir(File.dirname(__FILE__)) do
11
+ path = Dir.glob("lib<%= library_name %>.*").first
12
+ File.absolute_path(path) if path
13
+ end
14
+ ffi_lib ["<%= library_name %>", path]
9
15
 
10
16
  #add error checking
11
17
  #rbindCreateMatrix -> create_matrix
@@ -0,0 +1,870 @@
1
+ #!/usr/bin/env python
2
+
3
+ import os, sys, re, string
4
+
5
+ # the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
6
+ opencv_hdr_list = [
7
+ "../../core/include/opencv2/core.hpp",
8
+ "../../flann/include/opencv2/flann/miniflann.hpp",
9
+ "../../ml/include/opencv2/ml.hpp",
10
+ "../../imgproc/include/opencv2/imgproc.hpp",
11
+ "../../calib3d/include/opencv2/calib3d.hpp",
12
+ "../../features2d/include/opencv2/features2d.hpp",
13
+ "../../video/include/opencv2/video/tracking.hpp",
14
+ "../../video/include/opencv2/video/background_segm.hpp",
15
+ "../../objdetect/include/opencv2/objdetect.hpp",
16
+ "../../contrib/include/opencv2/contrib.hpp",
17
+ "../../highgui/include/opencv2/highgui.hpp"
18
+ ]
19
+
20
+ """
21
+ Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>],
22
+ where each element of <list_of_arguments> is 4-element list itself:
23
+ [argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
24
+ where the list of modifiers is yet another nested list of strings
25
+ (currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
26
+ and "/A value" for the plain C arrays with counters)
27
+ """
28
+
29
+ class CppHeaderParser(object):
30
+
31
+ def __init__(self):
32
+ self.BLOCK_TYPE = 0
33
+ self.BLOCK_NAME = 1
34
+ self.PROCESS_FLAG = 2
35
+ self.PUBLIC_SECTION = 3
36
+ self.CLASS_DECL = 4
37
+
38
+ def batch_replace(self, s, pairs):
39
+ for before, after in pairs:
40
+ s = s.replace(before, after)
41
+ return s
42
+
43
+ def get_macro_arg(self, arg_str, npos):
44
+ npos2 = npos3 = arg_str.find("(", npos)
45
+ if npos2 < 0:
46
+ print "Error: no arguments for the macro at %d" % (self.lineno,)
47
+ sys.exit(-1)
48
+ balance = 1
49
+ while 1:
50
+ t, npos3 = self.find_next_token(arg_str, ['(', ')'], npos3+1)
51
+ if npos3 < 0:
52
+ print "Error: no matching ')' in the macro call at %d" % (self.lineno,)
53
+ sys.exit(-1)
54
+ if t == '(':
55
+ balance += 1
56
+ if t == ')':
57
+ balance -= 1
58
+ if balance == 0:
59
+ break
60
+
61
+ return arg_str[npos2+1:npos3].strip(), npos3
62
+
63
+ def parse_arg(self, arg_str, argno):
64
+ """
65
+ Parses <arg_type> [arg_name]
66
+ Returns arg_type, arg_name, modlist, argno, where
67
+ modlist is the list of wrapper-related modifiers (such as "output argument", "has counter", ...)
68
+ and argno is the new index of an anonymous argument.
69
+ That is, if no arg_str is just an argument type without argument name, the argument name is set to
70
+ "arg" + str(argno), and then argno is incremented.
71
+ """
72
+ modlist = []
73
+
74
+ # pass 0: extracts the modifiers
75
+ if "CV_OUT" in arg_str:
76
+ modlist.append("/O")
77
+ arg_str = arg_str.replace("CV_OUT", "")
78
+
79
+ if "CV_IN_OUT" in arg_str:
80
+ modlist.append("/IO")
81
+ arg_str = arg_str.replace("CV_IN_OUT", "")
82
+
83
+ isarray = False
84
+ npos = arg_str.find("CV_CARRAY")
85
+ if npos >= 0:
86
+ isarray = True
87
+ macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
88
+
89
+ modlist.append("/A " + macro_arg)
90
+ arg_str = arg_str[:npos] + arg_str[npos3+1:]
91
+
92
+ npos = arg_str.find("CV_CUSTOM_CARRAY")
93
+ if npos >= 0:
94
+ isarray = True
95
+ macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
96
+
97
+ modlist.append("/CA " + macro_arg)
98
+ arg_str = arg_str[:npos] + arg_str[npos3+1:]
99
+
100
+ arg_str = arg_str.strip()
101
+ word_start = 0
102
+ word_list = []
103
+ npos = -1
104
+
105
+ #print self.lineno, ":\t", arg_str
106
+
107
+ # pass 1: split argument type into tokens
108
+ while 1:
109
+ npos += 1
110
+ t, npos = self.find_next_token(arg_str, [" ", "&", "*", "<", ">", ","], npos)
111
+ w = arg_str[word_start:npos].strip()
112
+ if w == "operator":
113
+ word_list.append("operator " + arg_str[npos:].strip())
114
+ break
115
+ if w not in ["", "const"]:
116
+ word_list.append(w)
117
+ if t not in ["", " ", "&"]:
118
+ word_list.append(t)
119
+ if not t:
120
+ break
121
+ word_start = npos+1
122
+ npos = word_start - 1
123
+
124
+ arg_type = ""
125
+ arg_name = ""
126
+ angle_stack = []
127
+
128
+ #print self.lineno, ":\t", word_list
129
+
130
+ # pass 2: decrypt the list
131
+ wi = -1
132
+ prev_w = ""
133
+ for w in word_list:
134
+ wi += 1
135
+ if w == "*":
136
+ if prev_w == "char" and not isarray:
137
+ arg_type = arg_type[:-len("char")] + "c_string"
138
+ else:
139
+ arg_type += w
140
+ continue
141
+ elif w == "<":
142
+ arg_type += "_"
143
+ angle_stack.append(0)
144
+ elif w == "," or w == '>':
145
+ if not angle_stack:
146
+ print "Error at %d: argument contains ',' or '>' not within template arguments" % (self.lineno,)
147
+ sys.exit(-1)
148
+ if w == ",":
149
+ arg_type += "_and_"
150
+ elif w == ">":
151
+ if angle_stack[0] == 0:
152
+ print "Error at %s:%d: template has no arguments" % (self.hname, self.lineno)
153
+ sys.exit(-1)
154
+ if angle_stack[0] > 1:
155
+ arg_type += "_end_"
156
+ angle_stack[-1:] = []
157
+ elif angle_stack:
158
+ arg_type += w
159
+ angle_stack[-1] += 1
160
+ elif arg_type == "struct":
161
+ arg_type += " " + w
162
+ elif arg_type and arg_type != "~":
163
+ arg_name = " ".join(word_list[wi:])
164
+ break
165
+ else:
166
+ arg_type += w
167
+ prev_w = w
168
+
169
+ counter_str = ""
170
+ add_star = False
171
+ if ("[" in arg_name) and not ("operator" in arg_str):
172
+ #print arg_str
173
+ p1 = arg_name.find("[")
174
+ p2 = arg_name.find("]",p1+1)
175
+ if p2 < 0:
176
+ print "Error at %d: no closing ]" % (self.lineno,)
177
+ sys.exit(-1)
178
+ counter_str = arg_name[p1+1:p2].strip()
179
+ if counter_str == "":
180
+ counter_str = "?"
181
+ if not isarray:
182
+ modlist.append("/A " + counter_str.strip())
183
+ arg_name = arg_name[:p1]
184
+ add_star = True
185
+
186
+ if not arg_name:
187
+ if arg_type.startswith("operator"):
188
+ arg_type, arg_name = "", arg_type
189
+ else:
190
+ arg_name = "arg" + str(argno)
191
+ argno += 1
192
+
193
+ while arg_type.endswith("_end_"):
194
+ arg_type = arg_type[:-len("_end_")]
195
+
196
+ if add_star:
197
+ arg_type += "*"
198
+
199
+ arg_type = self.batch_replace(arg_type, [("std::", ""), ("cv::", ""), ("::", "_")])
200
+
201
+ return arg_type, arg_name, modlist, argno
202
+
203
+ def parse_enum(self, decl_str):
204
+ l = decl_str
205
+ ll = l.split(",")
206
+ prev_val = ""
207
+ prev_val_delta = -1
208
+ decl = []
209
+ for pair in ll:
210
+ pv = pair.split("=")
211
+ if len(pv) == 1:
212
+ prev_val_delta += 1
213
+ val = ""
214
+ if prev_val:
215
+ val = prev_val + "+"
216
+ val += str(prev_val_delta)
217
+ else:
218
+ prev_val_delta = 0
219
+ prev_val = val = pv[1].strip()
220
+ decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], []])
221
+ return decl
222
+
223
+ def parse_class_decl(self, decl_str):
224
+ """
225
+ Parses class/struct declaration start in the form:
226
+ {class|struct} [CV_EXPORTS] <class_name> [: public <base_class1> [, ...]]
227
+ Returns class_name1, <list of base_classes>
228
+ """
229
+ l = decl_str
230
+ modlist = []
231
+ if "CV_EXPORTS_W_MAP" in l:
232
+ l = l.replace("CV_EXPORTS_W_MAP", "")
233
+ modlist.append("/Map")
234
+ if "CV_EXPORTS_W_SIMPLE" in l:
235
+ l = l.replace("CV_EXPORTS_W_SIMPLE", "")
236
+ modlist.append("/Simple")
237
+ npos = l.find("CV_EXPORTS_AS")
238
+ if npos >= 0:
239
+ macro_arg, npos3 = self.get_macro_arg(l, npos)
240
+ modlist.append("=" + macro_arg)
241
+ l = l[:npos] + l[npos3+1:]
242
+
243
+ l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public virtual ", " "), ("public ", " "), ("::", ".")]).strip()
244
+ ll = re.split(r'\s*[,:]?\s*', l)
245
+ ll = [le for le in ll if le]
246
+ classname = ll[1]
247
+ bases = ll[2:]
248
+ return classname, bases, modlist
249
+
250
+ def parse_func_decl_no_wrap(self, decl_str, static_method = False):
251
+ decl_str = (decl_str or "").strip()
252
+ virtual_method = False
253
+ explicit_method = False
254
+ if decl_str.startswith("explicit"):
255
+ decl_str = decl_str[len("explicit"):].lstrip()
256
+ explicit_method = True
257
+ if decl_str.startswith("virtual"):
258
+ decl_str = decl_str[len("virtual"):].lstrip()
259
+ virtual_method = True
260
+ if decl_str.startswith("static"):
261
+ decl_str = decl_str[len("static"):].lstrip()
262
+ static_method = True
263
+
264
+ fdecl = decl_str.replace("CV_OUT", "").replace("CV_IN_OUT", "")
265
+ fdecl = fdecl.strip().replace("\t", " ")
266
+ while " " in fdecl:
267
+ fdecl = fdecl.replace(" ", " ")
268
+ fname = fdecl[:fdecl.find("(")].strip()
269
+ fnpos = fname.rfind(" ")
270
+ if fnpos < 0:
271
+ fnpos = 0
272
+ fname = fname[fnpos:].strip()
273
+ rettype = fdecl[:fnpos].strip()
274
+
275
+ if rettype.endswith("operator"):
276
+ fname = ("operator " + fname).strip()
277
+ rettype = rettype[:rettype.rfind("operator")].strip()
278
+ if rettype.endswith("::"):
279
+ rpos = rettype.rfind(" ")
280
+ if rpos >= 0:
281
+ fname = rettype[rpos+1:].strip() + fname
282
+ rettype = rettype[:rpos].strip()
283
+ else:
284
+ fname = rettype + fname
285
+ rettype = ""
286
+
287
+ apos = fdecl.find("(")
288
+ if fname.endswith("operator"):
289
+ fname += " ()"
290
+ apos = fdecl.find("(", apos+1)
291
+
292
+ fname = "cv." + fname.replace("::", ".")
293
+ decl = [fname, rettype, [], []]
294
+
295
+ # inline constructor implementation
296
+ implmatch = re.match(r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+", fdecl[apos:])
297
+ if bool(implmatch):
298
+ fdecl = fdecl[:apos] + implmatch.group(1)
299
+
300
+ args0str = fdecl[apos+1:fdecl.rfind(")")].strip()
301
+
302
+ if args0str != "" and args0str != "void":
303
+ args0str = re.sub(r"\([^)]*\)", lambda m: m.group(0).replace(',', "@comma@"), args0str)
304
+ args0 = args0str.split(",")
305
+
306
+ args = []
307
+ narg = ""
308
+ for arg in args0:
309
+ narg += arg.strip()
310
+ balance_paren = narg.count("(") - narg.count(")")
311
+ balance_angle = narg.count("<") - narg.count(">")
312
+ if balance_paren == 0 and balance_angle == 0:
313
+ args.append(narg.strip())
314
+ narg = ""
315
+
316
+ for arg in args:
317
+ dfpos = arg.find("=")
318
+ defval = ""
319
+ if dfpos >= 0:
320
+ defval = arg[dfpos+1:].strip()
321
+ else:
322
+ dfpos = arg.find("CV_DEFAULT")
323
+ if dfpos >= 0:
324
+ defval, pos3 = self.get_macro_arg(arg, dfpos)
325
+ else:
326
+ dfpos = arg.find("CV_WRAP_DEFAULT")
327
+ if dfpos >= 0:
328
+ defval, pos3 = self.get_macro_arg(arg, dfpos)
329
+ if dfpos >= 0:
330
+ defval = defval.replace("@comma@", ",")
331
+ arg = arg[:dfpos].strip()
332
+ pos = len(arg)-1
333
+ while pos >= 0 and (arg[pos] in "_[]" or arg[pos].isalpha() or arg[pos].isdigit()):
334
+ pos -= 1
335
+ if pos >= 0:
336
+ aname = arg[pos+1:].strip()
337
+ atype = arg[:pos+1].strip()
338
+ if aname.endswith("&") or aname.endswith("*") or (aname in ["int", "String", "Mat"]):
339
+ atype = (atype + " " + aname).strip()
340
+ aname = ""
341
+ else:
342
+ atype = arg
343
+ aname = ""
344
+ if aname.endswith("]"):
345
+ bidx = aname.find('[')
346
+ atype += aname[bidx:]
347
+ aname = aname[:bidx]
348
+ decl[3].append([atype, aname, defval, []])
349
+
350
+ if static_method:
351
+ decl[2].append("/S")
352
+ if virtual_method:
353
+ decl[2].append("/V")
354
+ if explicit_method:
355
+ decl[2].append("/E")
356
+ if bool(re.match(r".*\)\s*(const)?\s*=\s*0", decl_str)):
357
+ decl[2].append("/A")
358
+ if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
359
+ decl[2].append("/C")
360
+ if "virtual" in decl_str:
361
+ print decl_str
362
+ return decl
363
+
364
+ def parse_func_decl(self, decl_str):
365
+ """
366
+ Parses the function or method declaration in the form:
367
+ [([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
368
+ [~]<function_name>
369
+ (<arg_type1> <arg_name1>[=<default_value1>] [, <arg_type2> <arg_name2>[=<default_value2>] ...])
370
+ [const] {; | <function_body>}
371
+
372
+ Returns the function declaration entry:
373
+ [<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (see above)
374
+ """
375
+
376
+ if self.wrap_mode:
377
+ if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
378
+ ("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
379
+ return []
380
+
381
+ # ignore old API in the documentation check (for now)
382
+ if "CVAPI(" in decl_str and self.wrap_mode:
383
+ return []
384
+
385
+ top = self.block_stack[-1]
386
+ func_modlist = []
387
+
388
+ npos = decl_str.find("CV_EXPORTS_AS")
389
+ if npos >= 0:
390
+ arg, npos3 = self.get_macro_arg(decl_str, npos)
391
+ func_modlist.append("="+arg)
392
+ decl_str = decl_str[:npos] + decl_str[npos3+1:]
393
+ npos = decl_str.find("CV_WRAP_AS")
394
+ if npos >= 0:
395
+ arg, npos3 = self.get_macro_arg(decl_str, npos)
396
+ func_modlist.append("="+arg)
397
+ decl_str = decl_str[:npos] + decl_str[npos3+1:]
398
+
399
+ # filter off some common prefixes, which are meaningless for Python wrappers.
400
+ # note that we do not strip "static" prefix, which does matter;
401
+ # it means class methods, not instance methods
402
+ decl_str = self.batch_replace(decl_str, [("virtual", ""), ("static inline", ""), ("inline", ""),\
403
+ ("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""), ("CV_WRAP ", " "), ("CV_INLINE", "")]).strip()
404
+
405
+ static_method = False
406
+ context = top[0]
407
+ if decl_str.startswith("static") and (context == "class" or context == "struct"):
408
+ decl_str = decl_str[len("static"):].lstrip()
409
+ static_method = True
410
+
411
+ args_begin = decl_str.find("(")
412
+ if decl_str.startswith("CVAPI"):
413
+ rtype_end = decl_str.find(")", args_begin+1)
414
+ if rtype_end < 0:
415
+ print "Error at %d. no terminating ) in CVAPI() macro: %s" % (self.lineno, decl_str)
416
+ sys.exit(-1)
417
+ decl_str = decl_str[args_begin+1:rtype_end] + " " + decl_str[rtype_end+1:]
418
+ args_begin = decl_str.find("(")
419
+ if args_begin < 0:
420
+ print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
421
+ sys.exit(-1)
422
+
423
+ decl_start = decl_str[:args_begin].strip()
424
+ # handle operator () case
425
+ if decl_start.endswith("operator"):
426
+ args_begin = decl_str.find("(", args_begin+1)
427
+ if args_begin < 0:
428
+ print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
429
+ sys.exit(-1)
430
+ decl_start = decl_str[:args_begin].strip()
431
+ # TODO: normalize all type of operators
432
+ if decl_start.endswith("()"):
433
+ decl_start = decl_start[0:-2].rstrip() + " ()"
434
+
435
+ # constructor/destructor case
436
+ if bool(re.match(r'^(\w+::)*(?P<x>\w+)::~?(?P=x)$', decl_start)):
437
+ decl_start = "void " + decl_start
438
+
439
+ rettype, funcname, modlist, argno = self.parse_arg(decl_start, -1)
440
+
441
+ if argno >= 0:
442
+ classname = top[1]
443
+ if rettype == classname or rettype == "~" + classname:
444
+ rettype, funcname = "", rettype
445
+ else:
446
+ if bool(re.match('\w+\s+\(\*\w+\)\s*\(.*\)', decl_str)):
447
+ return [] # function typedef
448
+ elif bool(re.match('\w+\s+\(\w+::\*\w+\)\s*\(.*\)', decl_str)):
449
+ return [] # class method typedef
450
+ elif bool(re.match('[A-Z_]+', decl_start)):
451
+ return [] # it seems to be a macro instantiation
452
+ elif "__declspec" == decl_start:
453
+ return []
454
+ elif bool(re.match(r'\w+\s+\(\*\w+\)\[\d+\]', decl_str)):
455
+ return [] # exotic - dynamic 2d array
456
+ else:
457
+ #print rettype, funcname, modlist, argno
458
+ print "Error at %s:%d the function/method name is missing: '%s'" % (self.hname, self.lineno, decl_start)
459
+ sys.exit(-1)
460
+
461
+ if self.wrap_mode and (("::" in funcname) or funcname.startswith("~")):
462
+ # if there is :: in function name (and this is in the header file),
463
+ # it means, this is inline implementation of a class method.
464
+ # Thus the function has been already declared within the class and we skip this repeated
465
+ # declaration.
466
+ # Also, skip the destructors, as they are always wrapped
467
+ return []
468
+
469
+ funcname = self.get_dotted_name(funcname)
470
+
471
+ if not self.wrap_mode:
472
+ decl = self.parse_func_decl_no_wrap(decl_str, static_method)
473
+ decl[0] = funcname
474
+ return decl
475
+
476
+ arg_start = args_begin+1
477
+ npos = arg_start-1
478
+ balance = 1
479
+ angle_balance = 0
480
+ # scan the argument list; handle nested parentheses
481
+ args_decls = []
482
+ args = []
483
+ argno = 1
484
+
485
+ while balance > 0:
486
+ npos += 1
487
+ t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
488
+ if not t:
489
+ print "Error: no closing ')' at %d" % (self.lineno,)
490
+ print decl_str
491
+ print decl_str[arg_start:]
492
+ sys.exit(-1)
493
+ if t == "<":
494
+ angle_balance += 1
495
+ if t == ">":
496
+ angle_balance -= 1
497
+ if t == "(":
498
+ balance += 1
499
+ if t == ")":
500
+ balance -= 1
501
+
502
+ if (t == "," and balance == 1 and angle_balance == 0) or balance == 0:
503
+ # process next function argument
504
+ a = decl_str[arg_start:npos].strip()
505
+ #print "arg = ", a
506
+ arg_start = npos+1
507
+ if a:
508
+ eqpos = a.find("=")
509
+ defval = ""
510
+ modlist = []
511
+ if eqpos >= 0:
512
+ defval = a[eqpos+1:].strip()
513
+ else:
514
+ eqpos = a.find("CV_DEFAULT")
515
+ if eqpos >= 0:
516
+ defval, pos3 = self.get_macro_arg(a, eqpos)
517
+ else:
518
+ eqpos = a.find("CV_WRAP_DEFAULT")
519
+ if eqpos >= 0:
520
+ defval, pos3 = self.get_macro_arg(a, eqpos)
521
+ if defval == "NULL":
522
+ defval = "0"
523
+ if eqpos >= 0:
524
+ a = a[:eqpos].strip()
525
+ arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
526
+ if self.wrap_mode:
527
+ if arg_type == "InputArray":
528
+ arg_type = "Mat"
529
+ elif arg_type == "InputOutputArray":
530
+ arg_type = "Mat"
531
+ modlist.append("/IO")
532
+ elif arg_type == "OutputArray":
533
+ arg_type = "Mat"
534
+ modlist.append("/O")
535
+ elif arg_type == "InputArrayOfArrays":
536
+ arg_type = "vector_Mat"
537
+ elif arg_type == "InputOutputArrayOfArrays":
538
+ arg_type = "vector_Mat"
539
+ modlist.append("/IO")
540
+ elif arg_type == "OutputArrayOfArrays":
541
+ arg_type = "vector_Mat"
542
+ modlist.append("/O")
543
+ defval = self.batch_replace(defval, [("InputArrayOfArrays", "vector<Mat>"),
544
+ ("InputOutputArrayOfArrays", "vector<Mat>"),
545
+ ("OutputArrayOfArrays", "vector<Mat>"),
546
+ ("InputArray", "Mat"),
547
+ ("InputOutputArray", "Mat"),
548
+ ("OutputArray", "Mat"),
549
+ ("noArray", arg_type)]).strip()
550
+ args.append([arg_type, arg_name, defval, modlist])
551
+ npos = arg_start-1
552
+
553
+ npos = decl_str.replace(" ", "").find("=0", npos)
554
+ if npos >= 0:
555
+ # skip pure virtual functions
556
+ return []
557
+
558
+ if static_method:
559
+ func_modlist.append("/S")
560
+
561
+ return [funcname, rettype, func_modlist, args]
562
+
563
+ def get_dotted_name(self, name):
564
+ """
565
+ adds the dot-separated container class/namespace names to the bare function/class name, e.g. when we have
566
+
567
+ namespace cv {
568
+ class A {
569
+ public:
570
+ f(int);
571
+ };
572
+ }
573
+
574
+ the function will convert "A" to "cv.A" and "f" to "cv.A.f".
575
+ """
576
+ if not self.block_stack:
577
+ return name
578
+ if name.startswith("cv."):
579
+ return name
580
+ n = ""
581
+ for b in self.block_stack:
582
+ block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
583
+ if block_type in ["file", "enum"]:
584
+ continue
585
+ if block_type not in ["struct", "class", "namespace"]:
586
+ print "Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack)
587
+ sys.exit(-1)
588
+ if block_name:
589
+ n += block_name + "."
590
+ return n + name.replace("::", ".")
591
+
592
+ def parse_stmt(self, stmt, end_token):
593
+ """
594
+ parses the statement (ending with ';' or '}') or a block head (ending with '{')
595
+
596
+ The function calls parse_class_decl or parse_func_decl when necessary. It returns
597
+ <block_type>, <block_name>, <parse_flag>, <declaration>
598
+ where the first 3 values only make sense for blocks (i.e. code blocks, namespaces, classes, enums and such)
599
+ """
600
+ stack_top = self.block_stack[-1]
601
+ context = stack_top[self.BLOCK_TYPE]
602
+
603
+ stmt_type = ""
604
+ if end_token == "{":
605
+ stmt_type = "block"
606
+
607
+ if context == "block":
608
+ print "Error at %d: should not call parse_stmt inside blocks" % (self.lineno,)
609
+ sys.exit(-1)
610
+
611
+ if context == "class" or context == "struct":
612
+ while 1:
613
+ colon_pos = stmt.find(":")
614
+ if colon_pos < 0:
615
+ break
616
+ w = stmt[:colon_pos].strip()
617
+ if w in ["public", "protected", "private"]:
618
+ if w == "public" or (not self.wrap_mode and w == "protected"):
619
+ stack_top[self.PUBLIC_SECTION] = True
620
+ else:
621
+ stack_top[self.PUBLIC_SECTION] = False
622
+ stmt = stmt[colon_pos+1:].strip()
623
+ break
624
+
625
+ # do not process hidden class members and template classes/functions
626
+ if not stack_top[self.PUBLIC_SECTION] or stmt.startswith("template"):
627
+ return stmt_type, "", False, None
628
+
629
+ if end_token == "{":
630
+ if not self.wrap_mode and stmt.startswith("typedef struct"):
631
+ stmt_type = "struct"
632
+ try:
633
+ classname, bases, modlist = self.parse_class_decl(stmt[len("typedef "):])
634
+ except:
635
+ print "Error at %s:%d" % (self.hname, self.lineno)
636
+ exit(1)
637
+ if classname.startswith("_Ipl"):
638
+ classname = classname[1:]
639
+ decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
640
+ if bases:
641
+ decl[1] = ": " + ", ".join([b if "::" in b else self.get_dotted_name(b).replace(".","::") for b in bases])
642
+ return stmt_type, classname, True, decl
643
+
644
+ if stmt.startswith("class") or stmt.startswith("struct"):
645
+ stmt_type = stmt.split()[0]
646
+ if stmt.strip() != stmt_type:
647
+ try:
648
+ classname, bases, modlist = self.parse_class_decl(stmt)
649
+ except:
650
+ print "Error at %s:%d" % (self.hname, self.lineno)
651
+ exit(1)
652
+ decl = []
653
+ if ("CV_EXPORTS_W" in stmt) or ("CV_EXPORTS_AS" in stmt) or (not self.wrap_mode):# and ("CV_EXPORTS" in stmt)):
654
+ decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
655
+ if bases:
656
+ decl[1] = ": " + ", ".join([b if "::" in b else self.get_dotted_name(b).replace(".","::") for b in bases])
657
+ return stmt_type, classname, True, decl
658
+
659
+ if stmt.startswith("enum"):
660
+ return "enum", "", True, None
661
+
662
+ if stmt.startswith("namespace"):
663
+ stmt_list = stmt.split()
664
+ if len(stmt_list) < 2:
665
+ stmt_list.append("<unnamed>")
666
+ return stmt_list[0], stmt_list[1], True, None
667
+ if stmt.startswith("extern") and "\"C\"" in stmt:
668
+ return "namespace", "", True, None
669
+
670
+ if end_token == "}" and context == "enum":
671
+ decl = self.parse_enum(stmt)
672
+ return "enum", "", False, decl
673
+
674
+ if end_token == ";" and stmt.startswith("typedef"):
675
+ # TODO: handle typedef's more intelligently
676
+ return stmt_type, "", False, None
677
+
678
+ paren_pos = stmt.find("(")
679
+ if paren_pos >= 0:
680
+ # assume it's function or method declaration,
681
+ # since we filtered off the other places where '(' can normally occur:
682
+ # - code blocks
683
+ # - function pointer typedef's
684
+ decl = self.parse_func_decl(stmt)
685
+ # we return parse_flag == False to prevent the parser to look inside function/method bodies
686
+ # (except for tracking the nested blocks)
687
+ return stmt_type, "", False, decl
688
+
689
+ if (context == "struct" or context == "class") and end_token == ";" and stmt:
690
+ # looks like it's member declaration; append the members to the class declaration
691
+ class_decl = stack_top[self.CLASS_DECL]
692
+ if ("CV_PROP" in stmt): # or (class_decl and ("/Map" in class_decl[2])):
693
+ var_modlist = []
694
+ if "CV_PROP_RW" in stmt:
695
+ var_modlist.append("/RW")
696
+ stmt = self.batch_replace(stmt, [("CV_PROP_RW", ""), ("CV_PROP", "")]).strip()
697
+ var_list = stmt.split(",")
698
+ var_type, var_name1, modlist, argno = self.parse_arg(var_list[0], -1)
699
+ var_list = [var_name1] + [i.strip() for i in var_list[1:]]
700
+
701
+ for v in var_list:
702
+ class_decl[3].append([var_type, v, "", var_modlist])
703
+ return stmt_type, "", False, None
704
+
705
+ # something unknown
706
+ return stmt_type, "", False, None
707
+
708
+ def find_next_token(self, s, tlist, p=0):
709
+ """
710
+ Finds the next token from the 'tlist' in the input 's', starting from position 'p'.
711
+ Returns the first occured token and its position, or ("", len(s)) when no token is found
712
+ """
713
+ token = ""
714
+ tpos = len(s)
715
+ for t in tlist:
716
+ pos = s.find(t, p)
717
+ if pos < 0:
718
+ continue
719
+ if pos < tpos:
720
+ tpos = pos
721
+ token = t
722
+ return token, tpos
723
+
724
+ def parse(self, hname, wmode=True):
725
+ """
726
+ The main method. Parses the input file.
727
+ Returns the list of declarations (that can be print using print_decls)
728
+ """
729
+ self.hname = hname
730
+ decls = []
731
+ f = open(hname, "rt")
732
+ linelist = list(f.readlines())
733
+ f.close()
734
+
735
+ # states:
736
+ SCAN = 0 # outside of a comment or preprocessor directive
737
+ COMMENT = 1 # inside a multi-line comment
738
+ DIRECTIVE = 2 # inside a multi-line preprocessor directive
739
+
740
+ state = SCAN
741
+
742
+ self.block_stack = [["file", hname, True, True, None]]
743
+ block_head = ""
744
+ self.lineno = 0
745
+ self.wrap_mode = wmode
746
+
747
+ for l0 in linelist:
748
+ self.lineno += 1
749
+ #print self.lineno
750
+
751
+ l = l0.strip()
752
+
753
+ if state == SCAN and l.startswith("#"):
754
+ state = DIRECTIVE
755
+ # fall through to the if state == DIRECTIVE check
756
+
757
+ if state == DIRECTIVE:
758
+ if not l.endswith("\\"):
759
+ state = SCAN
760
+ continue
761
+
762
+ if state == COMMENT:
763
+ pos = l.find("*/")
764
+ if pos < 0:
765
+ continue
766
+ l = l[pos+2:]
767
+ state = SCAN
768
+
769
+ if state != SCAN:
770
+ print "Error at %d: invlid state = %d" % (self.lineno, state)
771
+ sys.exit(-1)
772
+
773
+ while 1:
774
+ token, pos = self.find_next_token(l, [";", "\"", "{", "}", "//", "/*"])
775
+
776
+ if not token:
777
+ block_head += " " + l
778
+ break
779
+
780
+ if token == "//":
781
+ block_head += " " + l[:pos]
782
+ break
783
+
784
+ if token == "/*":
785
+ block_head += " " + l[:pos]
786
+ pos = l.find("*/", pos+2)
787
+ if pos < 0:
788
+ state = COMMENT
789
+ break
790
+ l = l[pos+2:]
791
+ continue
792
+
793
+ if token == "\"":
794
+ pos2 = pos + 1
795
+ while 1:
796
+ t2, pos2 = self.find_next_token(l, ["\\", "\""], pos2)
797
+ if t2 == "":
798
+ print "Error at %d: no terminating '\"'" % (self.lineno,)
799
+ sys.exit(-1)
800
+ if t2 == "\"":
801
+ break
802
+ pos2 += 2
803
+
804
+ block_head += " " + l[:pos2+1]
805
+ l = l[pos2+1:]
806
+ continue
807
+
808
+ stmt = (block_head + " " + l[:pos]).strip()
809
+ stmt = " ".join(stmt.split()) # normalize the statement
810
+ stack_top = self.block_stack[-1]
811
+
812
+ if stmt.startswith("@"):
813
+ # Objective C ?
814
+ break
815
+
816
+ decl = None
817
+ if stack_top[self.PROCESS_FLAG]:
818
+ # even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
819
+ # since it can start with "public:"
820
+ stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token)
821
+ if decl:
822
+ if stmt_type == "enum":
823
+ for d in decl:
824
+ decls.append(d)
825
+ else:
826
+ decls.append(decl)
827
+ else:
828
+ stmt_type, name, parse_flag = "block", "", False
829
+
830
+ if token == "{":
831
+ if stmt_type == "class":
832
+ public_section = False
833
+ else:
834
+ public_section = True
835
+ self.block_stack.append([stmt_type, name, parse_flag, public_section, decl])
836
+
837
+ if token == "}":
838
+ if not self.block_stack:
839
+ print "Error at %d: the block stack is empty" % (self.lineno,)
840
+ self.block_stack[-1:] = []
841
+ if pos+1 < len(l) and l[pos+1] == ';':
842
+ pos += 1
843
+
844
+ block_head = ""
845
+ l = l[pos+1:]
846
+
847
+ return decls
848
+
849
+ def print_decls(self, decls):
850
+ """
851
+ Prints the list of declarations, retrieived by the parse() method
852
+ """
853
+ for d in decls:
854
+ print d[0], d[1], ";".join(d[2])
855
+ for a in d[3]:
856
+ print " ", a[0], a[1], a[2],
857
+ if a[3]:
858
+ print "; ".join(a[3])
859
+ else:
860
+ print
861
+
862
+ if __name__ == '__main__':
863
+ parser = CppHeaderParser()
864
+ decls = []
865
+ # for hname in opencv_hdr_list:
866
+ # decls += parser.parse(hname)
867
+ for hname in sys.argv[1:]:
868
+ decls += parser.parse(hname)
869
+ parser.print_decls(decls)
870
+ print len(decls)
data/rbind.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rbind'
3
- s.version = '0.0.1'
3
+ s.version = '0.0.2'
4
4
  s.date = '2013-06-17'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ['Alexander Duda']
metadata CHANGED
@@ -1,35 +1,25 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rbind
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
4
5
  prerelease:
5
- version: 0.0.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Alexander Duda
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2013-06-17 00:00:00 Z
12
+ date: 2013-06-17 00:00:00.000000000 Z
14
13
  dependencies: []
15
-
16
- description: ""
17
- email:
14
+ description: ''
15
+ email:
18
16
  - Alexander.Duda@dfki.de
19
17
  executables: []
20
-
21
18
  extensions: []
22
-
23
19
  extra_rdoc_files: []
24
-
25
- files:
20
+ files:
26
21
  - lib/rbind.rb
27
- - lib/rbind/.default_parser.rb.swp
28
- - lib/rbind/.generator_c.rb.swp
29
22
  - lib/rbind/core.rb
30
- - lib/rbind/core/.rbase.rb.swp
31
- - lib/rbind/core/.rclass.rb.swp
32
- - lib/rbind/core/.rdata_type.rb.swp
33
23
  - lib/rbind/core/.roperation.rb.swp
34
24
  - lib/rbind/core/rattribute.rb
35
25
  - lib/rbind/core/rbase.rb
@@ -43,6 +33,7 @@ files:
43
33
  - lib/rbind/core/rparameter.rb
44
34
  - lib/rbind/core/rsetter.rb
45
35
  - lib/rbind/core/rstruct.rb
36
+ - lib/rbind/core/rvector.rb
46
37
  - lib/rbind/default_parser.rb
47
38
  - lib/rbind/generator_c.rb
48
39
  - lib/rbind/generator_ruby.rb
@@ -69,33 +60,31 @@ files:
69
60
  - lib/rbind/templates/ruby/rstatic_method.rb
70
61
  - lib/rbind/templates/ruby/rtype.rb
71
62
  - lib/rbind/templates/ruby/rtype_constructor.rb
63
+ - lib/rbind/tools/hdr_parser.py
72
64
  - rbind.gemspec
73
65
  homepage: http://github.com/
74
66
  licenses: []
75
-
76
67
  post_install_message:
77
68
  rdoc_options: []
78
-
79
- require_paths:
69
+ require_paths:
80
70
  - lib
81
- required_ruby_version: !ruby/object:Gem::Requirement
71
+ required_ruby_version: !ruby/object:Gem::Requirement
82
72
  none: false
83
- requirements:
84
- - - ">="
85
- - !ruby/object:Gem::Version
86
- version: "0"
87
- required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
78
  none: false
89
- requirements:
90
- - - ">="
91
- - !ruby/object:Gem::Version
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
92
82
  version: 1.3.6
93
83
  requirements: []
94
-
95
84
  rubyforge_project:
96
85
  rubygems_version: 1.8.23
97
86
  signing_key:
98
87
  specification_version: 3
99
88
  summary: Library for genereating automated ffi-bindings for c/c++ libraries
100
89
  test_files: []
101
-
90
+ has_rdoc:
Binary file
Binary file
Binary file
Binary file
Binary file