rbind 0.0.16 → 0.0.17
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.rb +1 -0
- data/lib/rbind/clang/clang.rb +3699 -0
- data/lib/rbind/clang/clang_types.rb +327 -0
- data/lib/rbind/clang_parser.rb +451 -0
- data/lib/rbind/core.rb +7 -4
- data/lib/rbind/core/rattribute.rb +17 -21
- data/lib/rbind/core/rbase.rb +98 -64
- data/lib/rbind/core/rcallback.rb +15 -0
- data/lib/rbind/core/rclass.rb +79 -16
- data/lib/rbind/core/rdata_type.rb +40 -39
- data/lib/rbind/core/renum.rb +18 -0
- data/lib/rbind/core/rnamespace.rb +189 -52
- data/lib/rbind/core/roperation.rb +52 -20
- data/lib/rbind/core/rparameter.rb +43 -8
- data/lib/rbind/core/rpointer.rb +70 -0
- data/lib/rbind/core/rreference.rb +54 -0
- data/lib/rbind/core/rtemplate_class.rb +49 -0
- data/lib/rbind/core/rtype_qualifier.rb +60 -0
- data/lib/rbind/default_parser.rb +48 -36
- data/lib/rbind/generator_c.rb +2 -2
- data/lib/rbind/generator_extern.rb +1 -3
- data/lib/rbind/generator_ruby.rb +201 -47
- data/lib/rbind/logger.rb +3 -0
- data/lib/rbind/rbind.rb +25 -9
- data/lib/rbind/templates/c/CMakeLists.txt +6 -6
- data/lib/rbind/templates/ruby/rbind.rb +1 -1
- data/lib/rbind/templates/ruby/rmethod.rb +4 -1
- data/lib/rbind/templates/ruby/rnamespace.rb +2 -1
- data/lib/rbind/templates/ruby/roverloaded_method.rb +3 -1
- data/lib/rbind/templates/ruby/roverloaded_method_call.rb +1 -0
- data/lib/rbind/templates/ruby/roverloaded_static_method.rb +3 -2
- data/lib/rbind/templates/ruby/rstatic_method.rb +4 -1
- data/lib/rbind/templates/ruby/rtype.rb +19 -16
- data/lib/rbind/templates/ruby/rtype_template.rb +7 -0
- data/lib/rbind/{core/rstring.rb → types/std_string.rb} +8 -8
- data/lib/rbind/types/std_vector.rb +100 -0
- data/rbind.gemspec +2 -2
- data/test/headers/cfunctions.h +7 -0
- data/test/headers/classes.hpp +29 -0
- data/test/headers/constants.hpp +14 -0
- data/test/headers/enums.hpp +22 -0
- data/test/headers/std_string.hpp +26 -0
- data/test/headers/std_vector.hpp +31 -0
- data/test/headers/structs.hpp +34 -0
- data/test/headers/templates.hpp +20 -0
- data/test/test_clang_parser.rb +146 -0
- data/test/test_generator_ruby.rb +0 -5
- data/test/test_roperation.rb +144 -0
- data/test/test_rparameter.rb +88 -0
- metadata +24 -7
- data/lib/rbind/core/.roperation.rb.swp +0 -0
- data/lib/rbind/core/rconst.rb +0 -35
- data/lib/rbind/core/rstruct.rb +0 -87
- data/lib/rbind/core/rvector.rb +0 -27
@@ -6,36 +6,19 @@ module Rbind
|
|
6
6
|
attr_accessor :invalid_value
|
7
7
|
attr_accessor :cdelete_method
|
8
8
|
attr_accessor :check_type
|
9
|
-
attr_accessor :extern_package_name
|
10
9
|
|
11
|
-
def initialize(name
|
10
|
+
def initialize(name)
|
12
11
|
super
|
13
12
|
@invalid_value = 0
|
14
13
|
@check_type = true
|
15
14
|
end
|
16
15
|
|
17
|
-
def extern?
|
18
|
-
@flags.include? :Extern
|
19
|
-
end
|
20
|
-
|
21
|
-
def valid_flags
|
22
|
-
super << :Extern
|
23
|
-
end
|
24
|
-
|
25
16
|
def ==(other)
|
26
|
-
other.
|
27
|
-
end
|
28
|
-
|
29
|
-
def generate_signatures
|
30
|
-
if ref?
|
31
|
-
["#{full_name} &","#{cname} &"]
|
32
|
-
elsif ptr?
|
33
|
-
["#{full_name} *","#{cname} *"]
|
34
|
-
else
|
35
|
-
super
|
36
|
-
end
|
17
|
+
other.generate_signatures[0] == generate_signatures[0]
|
37
18
|
end
|
38
19
|
|
20
|
+
# indicates of the type shall be checked before
|
21
|
+
# casting
|
39
22
|
def check_type?
|
40
23
|
@check_type
|
41
24
|
end
|
@@ -63,42 +46,60 @@ module Rbind
|
|
63
46
|
!!@typedef
|
64
47
|
end
|
65
48
|
|
49
|
+
def template?
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
66
53
|
# elementar type of c
|
67
54
|
def basic_type?
|
68
55
|
true
|
69
56
|
end
|
70
57
|
|
71
|
-
# holds
|
58
|
+
# holds other operations, types or consts
|
72
59
|
def container?
|
73
60
|
false
|
74
61
|
end
|
75
62
|
|
76
|
-
def
|
77
|
-
|
63
|
+
def to_raw
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_single_ptr
|
68
|
+
t = to_raw
|
69
|
+
t = t.to_const if const?
|
70
|
+
t.to_ptr
|
78
71
|
end
|
79
72
|
|
80
73
|
def to_ptr
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
74
|
+
RPointer.new(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_ref
|
78
|
+
RReference.new(self)
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_const
|
82
|
+
RTypeQualifier.new(self,:const => true)
|
83
|
+
end
|
84
|
+
|
85
|
+
def remove_const
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def raw?
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
93
|
+
def const?
|
94
|
+
false
|
94
95
|
end
|
95
96
|
|
96
97
|
def ptr?
|
97
|
-
|
98
|
+
false
|
98
99
|
end
|
99
100
|
|
100
101
|
def ref?
|
101
|
-
|
102
|
+
false
|
102
103
|
end
|
103
104
|
end
|
104
105
|
end
|
data/lib/rbind/core/renum.rb
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
|
2
2
|
module Rbind
|
3
3
|
class REnum < RDataType
|
4
|
+
attr_accessor :values
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
super(name)
|
8
|
+
@values = Hash.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate_signatures
|
12
|
+
["#{full_name} = #{values}","const #{cname} = #{values}"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def basic_type?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_value(name,val)
|
20
|
+
@values[name] = val
|
21
|
+
end
|
4
22
|
end
|
5
23
|
end
|
@@ -1,26 +1,58 @@
|
|
1
|
+
require 'hooks'
|
1
2
|
|
2
3
|
module Rbind
|
3
4
|
class RNamespace< RDataType
|
5
|
+
include Hooks
|
6
|
+
define_hook :on_type_not_found
|
7
|
+
define_hook :on_type_look_up
|
8
|
+
define_hook :on_add_type
|
9
|
+
define_hook :on_add_operation
|
10
|
+
define_hook :on_add_const
|
11
|
+
|
4
12
|
class << self
|
5
13
|
attr_accessor :default_type_names
|
14
|
+
attr_accessor :default_type_alias
|
6
15
|
end
|
7
|
-
|
16
|
+
# TODO move somewhere else
|
17
|
+
self.default_type_names = [:int,:int8,:int32,:int64,:uint,:uint8,:uint32,:uint64,
|
18
|
+
:int8_t,:int32_t,:int64_t,:uint8_t,:uint32_t,:uint64_t,
|
19
|
+
:bool,:double,:float,:void,:char,:size_t,:long,
|
20
|
+
:uchar, :char16, :char32, :ushort, :ulong, :ulong_long,
|
21
|
+
:uint128, :short, :long_long, :int128, :long_double,
|
22
|
+
:c_string,:constant_array]
|
23
|
+
self.default_type_alias= { :u_char => :uchar, :u_short => :ushort, :u_long => :ulong,
|
24
|
+
:u_long_long => :ulong_long,:u_int => :uint, :uint128 => :uint128,
|
25
|
+
:char_s => :char}
|
8
26
|
|
9
27
|
attr_reader :operations
|
10
28
|
attr_reader :operation_alias
|
11
29
|
attr_reader :consts
|
12
30
|
attr_reader :used_namespaces
|
13
|
-
|
14
|
-
|
31
|
+
attr_reader :type_alias
|
32
|
+
attr_reader :root
|
15
33
|
|
16
|
-
def initialize(name
|
34
|
+
def initialize(name=nil,root = nil)
|
17
35
|
@consts = Hash.new
|
18
36
|
@types = Hash.new
|
19
|
-
@
|
37
|
+
@type_alias = Hash.new
|
20
38
|
@operations = Hash.new{|hash,key| hash[key] = Array.new}
|
21
39
|
@operation_alias = Hash.new{|hash,key| hash[key] = Array.new}
|
22
|
-
@used_namespaces =
|
23
|
-
|
40
|
+
@used_namespaces = Array.new
|
41
|
+
name ||= begin
|
42
|
+
@root = true
|
43
|
+
"root"
|
44
|
+
end
|
45
|
+
if root
|
46
|
+
#share varaibales accross root namesapces
|
47
|
+
raise "#{root} is not a root namespace" unless root.root?
|
48
|
+
@consts = root.instance_variable_get(:@consts)
|
49
|
+
@types = root.instance_variable_get(:@types)
|
50
|
+
@type_alias = root.instance_variable_get(:@type_alias)
|
51
|
+
@operations = root.instance_variable_get(:@operations)
|
52
|
+
@operation_alias =root.instance_variable_get(:@operation_alias)
|
53
|
+
@used_namespaces = root.instance_variable_get(:@used_namespaces)
|
54
|
+
end
|
55
|
+
super(name)
|
24
56
|
end
|
25
57
|
|
26
58
|
def root?
|
@@ -45,13 +77,23 @@ module Rbind
|
|
45
77
|
end
|
46
78
|
|
47
79
|
def use_namespace(namespace)
|
48
|
-
|
80
|
+
# Check if there is another root embedded
|
81
|
+
# and add the corresponding namespace.
|
82
|
+
# This is needed to support multiple roots providing
|
83
|
+
# types to the same namespace
|
84
|
+
@used_namespaces.each do |ns|
|
85
|
+
next unless ns.root?
|
86
|
+
if (ns2 = ns.type(namespace.full_name,false))
|
87
|
+
@used_namespaces << ns2 if ns.object_id != namespace.object_id
|
88
|
+
end
|
89
|
+
end
|
90
|
+
@used_namespaces << namespace
|
49
91
|
end
|
50
92
|
|
51
93
|
def each_type(childs=true,all=false,&block)
|
52
94
|
if block_given?
|
53
95
|
types.each do |t|
|
54
|
-
next if !all && (t.ignore? || t.extern?)
|
96
|
+
next if !all && (t.ignore? || t.extern? || t.template?)
|
55
97
|
yield t
|
56
98
|
t.each_type(childs,all,&block) if childs && t.respond_to?(:each_type)
|
57
99
|
end
|
@@ -60,8 +102,8 @@ module Rbind
|
|
60
102
|
end
|
61
103
|
end
|
62
104
|
|
63
|
-
def each_container(all=false,&block)
|
64
|
-
each_type(
|
105
|
+
def each_container(childs=true,all=false,&block)
|
106
|
+
each_type(childs,all) do |t|
|
65
107
|
next unless t.container?
|
66
108
|
yield t
|
67
109
|
end
|
@@ -81,7 +123,7 @@ module Rbind
|
|
81
123
|
end
|
82
124
|
end
|
83
125
|
c ||= begin
|
84
|
-
used_namespaces.
|
126
|
+
used_namespaces.each do |ns|
|
85
127
|
c = ns.const(name,false,false)
|
86
128
|
break if c
|
87
129
|
end
|
@@ -91,6 +133,7 @@ module Rbind
|
|
91
133
|
owner.const(name,false)
|
92
134
|
end
|
93
135
|
raise RuntimeError,"#{full_name} has no const called #{name}" if raise_ && !c
|
136
|
+
c
|
94
137
|
end
|
95
138
|
|
96
139
|
def each_const(childs=true,all=false,&block)
|
@@ -100,7 +143,7 @@ module Rbind
|
|
100
143
|
yield c
|
101
144
|
end
|
102
145
|
return unless childs
|
103
|
-
each_container(all) do |t|
|
146
|
+
each_container(false,all) do |t|
|
104
147
|
t.each_const(childs,all,&block)
|
105
148
|
end
|
106
149
|
else
|
@@ -109,7 +152,7 @@ module Rbind
|
|
109
152
|
end
|
110
153
|
|
111
154
|
def extern?
|
112
|
-
return super
|
155
|
+
return super if self.is_a? RClass
|
113
156
|
|
114
157
|
# check if self is container holding only
|
115
158
|
# extern objects
|
@@ -122,7 +165,6 @@ module Rbind
|
|
122
165
|
each_operation do |t|
|
123
166
|
return false
|
124
167
|
end
|
125
|
-
true
|
126
168
|
end
|
127
169
|
|
128
170
|
def each_operation(all=false,&block)
|
@@ -162,9 +204,15 @@ module Rbind
|
|
162
204
|
!!operation(name,false)
|
163
205
|
end
|
164
206
|
|
165
|
-
def add_operation(op)
|
166
|
-
op.
|
207
|
+
def add_operation(op,&block)
|
208
|
+
if op.is_a? String
|
209
|
+
op = ROperation.new(op,void)
|
210
|
+
op.owner = self
|
211
|
+
instance_exec(op,&block) if block
|
212
|
+
return add_operation(op)
|
213
|
+
end
|
167
214
|
|
215
|
+
op.owner = self
|
168
216
|
# make sure there is no name clash
|
169
217
|
other = @operations[op.name].find do |o|
|
170
218
|
o.cname == op.cname
|
@@ -190,8 +238,9 @@ module Rbind
|
|
190
238
|
op
|
191
239
|
end
|
192
240
|
|
193
|
-
|
194
|
-
|
241
|
+
# TODO rename to add_namespace_name
|
242
|
+
def add_namespace(namespace_name)
|
243
|
+
names = namespace_name.split("::")
|
195
244
|
current_type = self
|
196
245
|
while !names.empty?
|
197
246
|
name = names.shift
|
@@ -207,8 +256,14 @@ module Rbind
|
|
207
256
|
end
|
208
257
|
|
209
258
|
def add_const(const)
|
210
|
-
|
211
|
-
|
259
|
+
const.const!
|
260
|
+
if(c = const(const.full_name,false,false))
|
261
|
+
if c.type.full_name == const.type.full_name && c.default_value == const.default_value
|
262
|
+
::Rbind.log.warn "A const with the name #{const.full_name} already exists"
|
263
|
+
return c
|
264
|
+
else
|
265
|
+
raise ArgumentError,"#A different const with the name #{const.full_name} already exists: #{const} != #{c}"
|
266
|
+
end
|
212
267
|
end
|
213
268
|
if const.namespace? && self.full_name != const.namespace
|
214
269
|
t=type(const.namespace,false)
|
@@ -223,9 +278,13 @@ module Rbind
|
|
223
278
|
|
224
279
|
def add_default_types
|
225
280
|
add_simple_types RNamespace.default_type_names
|
226
|
-
|
227
|
-
|
228
|
-
|
281
|
+
type("uchar").cname("unsigned char")
|
282
|
+
type("c_string").cname("char *")
|
283
|
+
RNamespace.default_type_alias.each_pair do |key,val|
|
284
|
+
next if @type_alias.has_key?(key)
|
285
|
+
@type_alias[key.to_s] = type(val)
|
286
|
+
end
|
287
|
+
self
|
229
288
|
end
|
230
289
|
|
231
290
|
def add_simple_type(name)
|
@@ -239,9 +298,8 @@ module Rbind
|
|
239
298
|
end
|
240
299
|
end
|
241
300
|
|
242
|
-
def add_type(type)
|
243
|
-
|
244
|
-
if type(type.full_name,false,false)
|
301
|
+
def add_type(type,check_exist = true)
|
302
|
+
if check_exist && type(type.full_name,false,false)
|
245
303
|
raise ArgumentError,"A type with the name #{type.full_name} already exists"
|
246
304
|
end
|
247
305
|
# if self is not the right namespace
|
@@ -252,28 +310,31 @@ module Rbind
|
|
252
310
|
else
|
253
311
|
type.owner = self
|
254
312
|
if type.alias
|
255
|
-
if type(type.alias,false,false)
|
313
|
+
if check_exist && type(type.alias,false,false)
|
256
314
|
raise ArgumentError,"A type with the name alias #{type.alias} already exists"
|
257
315
|
end
|
258
|
-
|
316
|
+
raise ArgumentError,"A type alias with the name #{t.alias} already exists" if(t = @type_alias[type.alias])
|
317
|
+
@type_alias[type.alias] = type.to_raw
|
259
318
|
end
|
260
|
-
@types[type.name]
|
319
|
+
raise ArgumentError,"A type with the name #{t.full_name} already exists" if(t = @types[type.name])
|
320
|
+
@types[type.name] = type.to_raw
|
261
321
|
end
|
262
322
|
type
|
263
323
|
end
|
264
324
|
|
265
325
|
def type(name,raise_ = true,search_owner = true)
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
name = name.
|
326
|
+
name = name.to_s
|
327
|
+
constant = if name =~ /const /
|
328
|
+
true
|
329
|
+
else
|
330
|
+
false
|
331
|
+
end
|
332
|
+
name = name.gsub("unsigned ","u").gsub("const ","").gsub(" ","").gsub(">>","> >")
|
333
|
+
|
273
334
|
t = if @types.has_key?(name)
|
274
335
|
@types[name]
|
275
|
-
elsif @
|
276
|
-
@
|
336
|
+
elsif @type_alias.has_key?(name)
|
337
|
+
@type_alias[name]
|
277
338
|
else
|
278
339
|
if !!(ns = RBase.namespace(name))
|
279
340
|
ns = ns.split("::")
|
@@ -283,7 +344,7 @@ module Rbind
|
|
283
344
|
end
|
284
345
|
end
|
285
346
|
t ||= begin
|
286
|
-
used_namespaces.
|
347
|
+
used_namespaces.each do |ns|
|
287
348
|
t = ns.type(name,false,false)
|
288
349
|
break if t
|
289
350
|
end
|
@@ -292,25 +353,84 @@ module Rbind
|
|
292
353
|
t ||= if search_owner && owner
|
293
354
|
owner.type(name,false)
|
294
355
|
end
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
356
|
+
# check if type is a pointer and pointee is registered
|
357
|
+
t ||= begin
|
358
|
+
ptr_level = $1.to_s.size if name =~ /(\**)$/
|
359
|
+
name2 = name.gsub("*","")
|
360
|
+
ref_level = $1.to_s.size if name2 =~ /(&*)$/
|
361
|
+
name2 = name2.gsub("&","")
|
362
|
+
if ptr_level > 0 || ref_level > 0
|
363
|
+
t = type(name2,raise_,search_owner)
|
364
|
+
if t
|
365
|
+
1.upto(ptr_level) do
|
366
|
+
t = t.to_ptr
|
367
|
+
end
|
368
|
+
1.upto(ref_level) do
|
369
|
+
t = t.to_ref
|
370
|
+
end
|
371
|
+
# t.owner.add_type(t,false)
|
372
|
+
t
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# check if type is a template and a template is registered
|
378
|
+
# under the given name
|
379
|
+
t ||= if search_owner && name =~ /([:\w]*)<(.*)>$/
|
380
|
+
t = type($1,false) if $1 && !$1.empty?
|
381
|
+
t2 = type($2,false) if $2 && !$2.empty?
|
382
|
+
if t && t2
|
383
|
+
name = "#{t.name}<#{t2.full_name}>"
|
384
|
+
t3 ||= t.owner.type(name,false,false)
|
385
|
+
t3 ||= begin
|
386
|
+
if !t.template?
|
387
|
+
::Rbind.log.error "try to spezialize a class #{t.full_name} --> #{name}"
|
388
|
+
nil
|
389
|
+
else
|
390
|
+
t3 = t.do_specialize(name,t2)
|
391
|
+
if !t3
|
392
|
+
::Rbind.log.error "Failed to specialize template #{t.full_name} --> #{name}"
|
393
|
+
nil
|
394
|
+
else
|
395
|
+
t.owner.add_type(t3,false)
|
396
|
+
::Rbind.log.info "spezialize template #{t.full_name} --> #{t3.full_name}"
|
397
|
+
t3
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
if !t && raise_
|
405
|
+
if self.class.callbacks_for_hook(:on_type_not_found)
|
406
|
+
results = self.run_hook(:on_type_not_found,self,name)
|
407
|
+
t = results.find do |t|
|
408
|
+
t.respond_to?(:type)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
raise RuntimeError,"#{full_name} has no type called #{name}" if !t
|
412
|
+
end
|
413
|
+
if constant
|
414
|
+
t.to_const
|
415
|
+
else
|
416
|
+
t
|
300
417
|
end
|
301
|
-
t
|
302
418
|
end
|
303
419
|
|
304
420
|
def pretty_print_name
|
305
|
-
"namespace #{full_name}
|
421
|
+
"namespace #{full_name}"
|
306
422
|
end
|
307
423
|
|
308
424
|
def root?
|
309
425
|
!!root
|
310
426
|
end
|
311
427
|
|
428
|
+
def empty?
|
429
|
+
consts.empty? && types.empty? && operations.empty?
|
430
|
+
end
|
431
|
+
|
312
432
|
def pretty_print(pp)
|
313
|
-
pp.text pretty_print_name
|
433
|
+
pp.text pretty_print_name unless root?
|
314
434
|
|
315
435
|
unless consts.empty?
|
316
436
|
pp.nest(2) do
|
@@ -329,7 +449,20 @@ module Rbind
|
|
329
449
|
pp.breakable
|
330
450
|
pp.text "Types:"
|
331
451
|
pp.nest(2) do
|
452
|
+
simple = []
|
453
|
+
other = []
|
332
454
|
types.each do |t|
|
455
|
+
if t.basic_type? && !t.container?
|
456
|
+
simple << t.name
|
457
|
+
else
|
458
|
+
other << t
|
459
|
+
end
|
460
|
+
end
|
461
|
+
if !simple.empty?
|
462
|
+
pp.breakable
|
463
|
+
pp.text(simple.join(", "))
|
464
|
+
end
|
465
|
+
other.each do |t|
|
333
466
|
pp.breakable
|
334
467
|
pp.pp(t)
|
335
468
|
end
|
@@ -354,12 +487,16 @@ module Rbind
|
|
354
487
|
end
|
355
488
|
|
356
489
|
def method_missing(m,*args)
|
357
|
-
|
358
|
-
|
490
|
+
if m != :to_ary && args.empty?
|
491
|
+
t = type(m.to_s,false,false)
|
492
|
+
return t if t
|
359
493
|
|
360
|
-
|
361
|
-
|
494
|
+
op = operation(m.to_s,false)
|
495
|
+
return op if op
|
362
496
|
|
497
|
+
c = const(m.to_s,false)
|
498
|
+
return c if c
|
499
|
+
end
|
363
500
|
super
|
364
501
|
end
|
365
502
|
end
|