ruby2js 3.5.2 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -665
  3. data/lib/ruby2js.rb +47 -13
  4. data/lib/ruby2js/converter.rb +9 -3
  5. data/lib/ruby2js/converter/args.rb +6 -1
  6. data/lib/ruby2js/converter/assign.rb +159 -0
  7. data/lib/ruby2js/converter/begin.rb +7 -2
  8. data/lib/ruby2js/converter/case.rb +7 -2
  9. data/lib/ruby2js/converter/class.rb +80 -21
  10. data/lib/ruby2js/converter/class2.rb +107 -33
  11. data/lib/ruby2js/converter/def.rb +7 -3
  12. data/lib/ruby2js/converter/dstr.rb +8 -3
  13. data/lib/ruby2js/converter/hash.rb +28 -6
  14. data/lib/ruby2js/converter/hide.rb +13 -0
  15. data/lib/ruby2js/converter/if.rb +10 -2
  16. data/lib/ruby2js/converter/import.rb +19 -4
  17. data/lib/ruby2js/converter/kwbegin.rb +9 -2
  18. data/lib/ruby2js/converter/literal.rb +14 -2
  19. data/lib/ruby2js/converter/logical.rb +1 -1
  20. data/lib/ruby2js/converter/module.rb +41 -4
  21. data/lib/ruby2js/converter/opasgn.rb +8 -0
  22. data/lib/ruby2js/converter/return.rb +2 -1
  23. data/lib/ruby2js/converter/send.rb +73 -8
  24. data/lib/ruby2js/converter/vasgn.rb +5 -0
  25. data/lib/ruby2js/converter/xstr.rb +2 -3
  26. data/lib/ruby2js/demo.rb +53 -0
  27. data/lib/ruby2js/es2022.rb +5 -0
  28. data/lib/ruby2js/es2022/strict.rb +3 -0
  29. data/lib/ruby2js/filter.rb +9 -1
  30. data/lib/ruby2js/filter/active_functions.rb +44 -0
  31. data/lib/ruby2js/filter/camelCase.rb +6 -3
  32. data/lib/ruby2js/filter/cjs.rb +2 -0
  33. data/lib/ruby2js/filter/esm.rb +118 -26
  34. data/lib/ruby2js/filter/functions.rb +104 -106
  35. data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
  36. data/lib/ruby2js/filter/node.rb +58 -14
  37. data/lib/ruby2js/filter/nokogiri.rb +12 -12
  38. data/lib/ruby2js/filter/react.rb +192 -57
  39. data/lib/ruby2js/filter/require.rb +102 -11
  40. data/lib/ruby2js/filter/return.rb +13 -1
  41. data/lib/ruby2js/filter/stimulus.rb +185 -0
  42. data/lib/ruby2js/jsx.rb +309 -0
  43. data/lib/ruby2js/namespace.rb +75 -0
  44. data/lib/ruby2js/rails.rb +15 -9
  45. data/lib/ruby2js/serializer.rb +3 -1
  46. data/lib/ruby2js/version.rb +3 -3
  47. data/ruby2js.gemspec +2 -2
  48. metadata +17 -9
  49. data/lib/ruby2js/filter/esm_migration.rb +0 -72
  50. data/lib/ruby2js/filter/fast-deep-equal.rb +0 -23
@@ -11,13 +11,27 @@ module Ruby2JS
11
11
  # NOTE: class_extend is not generated by the parser, but instead produced
12
12
  # when ++class is encountered; it signals that this construct is
13
13
  # meant to extend an already existing JavaScrpt class.
14
+ #
15
+ # class_hash is an anonymous class as a value in a hash; the
16
+ # name has already been output so should be ignored other than
17
+ # in determining the namespace.
18
+ #
19
+ # class_module is a module that to be re-processed by this handler
20
+ # given the similarity between the two structures.
14
21
 
15
- handle :class, :class_extend, :class_module do |name, inheritance, *body|
16
- if @ast.type != :class
22
+ handle :class, :class_hash, :class_extend, :class_module do |name, inheritance, *body|
23
+ extend = @namespace.enter(name) unless @ast.type == :class_module
24
+
25
+ if !%i(class class_hash).include?(@ast.type) or extend
17
26
  init = nil
18
27
  else
19
- if es2015
20
- parse @ast.updated(:class2)
28
+ if es2015 and not extend
29
+ if @ast.type == :class_hash
30
+ parse @ast.updated(:class2, [nil, *@ast.children[1..-1]])
31
+ else
32
+ parse @ast.updated(:class2)
33
+ end
34
+ @namespace.leave unless @ast.type == :class_module
21
35
  return
22
36
  end
23
37
 
@@ -35,7 +49,7 @@ module Ruby2JS
35
49
  end
36
50
 
37
51
  body.compact!
38
- visible = {}
52
+ visible = @namespace.getOwnProps
39
53
  body.map! do |m|
40
54
  if \
41
55
  @ast.type == :class_module and m.type == :defs and
@@ -45,7 +59,7 @@ module Ruby2JS
45
59
  end
46
60
 
47
61
  node = if m.type == :def
48
- if m.children.first == :initialize
62
+ if m.children.first == :initialize and !visible[:initialize]
49
63
  # constructor: remove from body and overwrite init function
50
64
  init = m
51
65
  nil
@@ -54,17 +68,20 @@ module Ruby2JS
54
68
  sym = :"#{m.children.first.to_s[0..-2]}"
55
69
  s(:prop, s(:attr, name, :prototype), sym =>
56
70
  {enumerable: s(:true), configurable: s(:true),
57
- set: s(:block, s(:send, nil, :proc), *m.children[1..-1])})
71
+ set: s(:defm, nil, *m.children[1..-1])})
58
72
  else
59
- visible[m.children[0]] = s(:self)
60
73
 
61
74
  if not m.is_method?
75
+ visible[m.children[0]] = s(:self)
76
+
62
77
  # property getter
63
78
  s(:prop, s(:attr, name, :prototype), m.children.first =>
64
79
  {enumerable: s(:true), configurable: s(:true),
65
- get: s(:block, s(:send, nil, :proc), m.children[1],
80
+ get: s(:defm, nil, m.children[1],
66
81
  m.updated(:autoreturn, m.children[2..-1]))})
67
82
  else
83
+ visible[m.children[0]] = s(:autobind, s(:self))
84
+
68
85
  # method: add to prototype
69
86
  s(:method, s(:attr, name, :prototype),
70
87
  :"#{m.children[0].to_s.chomp('!')}=",
@@ -90,13 +107,14 @@ module Ruby2JS
90
107
  else
91
108
  # class method definition: add to prototype
92
109
  s(:prototype, s(:send, name, "#{m.children[1]}=",
93
- s(:block, s(:send, nil, :proc), *m.children[2..-1])))
110
+ s(:defm, nil, *m.children[2..-1])))
94
111
  end
95
112
 
96
113
  elsif m.type == :send and m.children.first == nil
97
114
  if m.children[1] == :attr_accessor
98
115
  m.children[2..-1].map do |child_sym|
99
116
  var = child_sym.children.first
117
+ visible[var] = s(:self)
100
118
  s(:prop, s(:attr, name, :prototype), var =>
101
119
  {enumerable: s(:true), configurable: s(:true),
102
120
  get: s(:block, s(:send, nil, :proc), s(:args),
@@ -107,6 +125,7 @@ module Ruby2JS
107
125
  elsif m.children[1] == :attr_reader
108
126
  m.children[2..-1].map do |child_sym|
109
127
  var = child_sym.children.first
128
+ visible[var] = s(:self)
110
129
  s(:prop, s(:attr, name, :prototype), var =>
111
130
  {get: s(:block, s(:send, nil, :proc), s(:args),
112
131
  s(:return, s(:ivar, :"@#{var}"))),
@@ -116,6 +135,7 @@ module Ruby2JS
116
135
  elsif m.children[1] == :attr_writer
117
136
  m.children[2..-1].map do |child_sym|
118
137
  var = child_sym.children.first
138
+ visible[var] = s(:self)
119
139
  s(:prop, s(:attr, name, :prototype), var =>
120
140
  {set: s(:block, s(:send, nil, :proc), s(:args, s(:arg, var)),
121
141
  s(:ivasgn, :"@#{var}", s(:lvar, var))),
@@ -125,9 +145,10 @@ module Ruby2JS
125
145
  elsif m.children[1] == :include
126
146
  s(:send, s(:block, s(:send, nil, :lambda), s(:args),
127
147
  s(:begin, *m.children[2..-1].map {|modname|
128
- s(:for, s(:lvasgn, :$_), modname,
129
- s(:send, s(:attr, name, :prototype), :[]=,
130
- s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
148
+ @namespace.defineProps @namespace.find(modname)
149
+ s(:for, s(:lvasgn, :$_), modname,
150
+ s(:send, s(:attr, name, :prototype), :[]=,
151
+ s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
131
152
  })), :[])
132
153
  elsif [:private, :protected, :public].include? m.children[1]
133
154
  raise Error.new("class #{m.children[1]} is not supported", @ast)
@@ -160,17 +181,23 @@ module Ruby2JS
160
181
  s(:send, s(:attr, name, :prototype),
161
182
  "#{m.children[0].children.first}=",
162
183
  s(:attr, s(:attr, name, :prototype), m.children[1].children.first))
163
- elsif m.type == :class
184
+ elsif m.type == :class or m.type == :module
164
185
  innerclass_name = m.children.first
165
186
  if innerclass_name.children.first
166
187
  innerclass_name = innerclass_name.updated(nil,
167
- [s(:attr, innerclass_name.children[0], name),
188
+ [s(:attr, name, innerclass_name.children[0].children.last),
168
189
  innerclass_name.children[1]])
169
190
  else
170
191
  innerclass_name = innerclass_name.updated(nil,
171
192
  [name, innerclass_name.children[1]])
172
193
  end
173
194
  m.updated(nil, [innerclass_name, *m.children[1..-1]])
195
+ elsif @ast.type == :class_module
196
+ m
197
+ elsif m.type == :defineProps
198
+ @namespace.defineProps m.children.first
199
+ visible.merge! m.children.first
200
+ nil
174
201
  else
175
202
  raise Error.new("class #{ m.type } not supported", @ast)
176
203
  end
@@ -194,7 +221,7 @@ module Ruby2JS
194
221
  # merge property definitions
195
222
  combine_properties(body)
196
223
 
197
- if inheritance
224
+ if inheritance and (@ast.type != :class_extend and !extend)
198
225
  body.unshift s(:send, name, :prototype=,
199
226
  s(:send, s(:const, nil, :Object), :create,
200
227
  s(:attr, inheritance, :prototype))),
@@ -206,10 +233,14 @@ module Ruby2JS
206
233
  methods = 0
207
234
  start = 0
208
235
  body.each do |node|
209
- if [:method, :prop].include? node.type and
236
+ if (node.type == :method or (node.type == :prop and es2015)) and
210
237
  node.children[0].type == :attr and
211
238
  node.children[0].children[1] == :prototype
212
239
  methods += 1
240
+ elsif node.type == :class and @ast.type == :class_module and es2015
241
+ methods += 1 if node.children.first.children.first == name
242
+ elsif node.type == :module and @ast.type == :class_module
243
+ methods += 1 if node.children.first.children.first == name
213
244
  elsif methods == 0
214
245
  start += 1
215
246
  else
@@ -219,14 +250,22 @@ module Ruby2JS
219
250
 
220
251
  # collapse sequence to a single assignment
221
252
  if \
222
- @ast.type != :class_extend and
223
- (methods > 1 or (methods == 1 and body[start].type == :prop))
253
+ @ast.type == :class_module or methods > 1 or
254
+ body[start]&.type == :prop
224
255
  then
225
256
  pairs = body[start...start+methods].map do |node|
226
257
  if node.type == :method
227
258
  replacement = node.updated(:pair, [
228
259
  s(:str, node.children[1].to_s.chomp('=')),
229
260
  node.children[2]])
261
+ elsif node.type == :class and node.children.first.children.first == name
262
+ sym = node.children.first.children.last
263
+ replacement = s(:pair, s(:sym, sym),
264
+ s(:class_hash, s(:const, nil, sym), nil, node.children.last))
265
+ elsif node.type == :module and node.children.first.children.first == name
266
+ sym = node.children.first.children.last
267
+ replacement = s(:pair, s(:sym, sym),
268
+ s(:module_hash, s(:const, nil, sym), node.children.last))
230
269
  else
231
270
  replacement = node.children[1].map do |prop, descriptor|
232
271
  node.updated(:pair, [s(:prop, prop), descriptor])
@@ -244,12 +283,30 @@ module Ruby2JS
244
283
  end
245
284
 
246
285
  if @ast.type == :class_module
286
+ start = 0 if methods == 0
287
+ if name
288
+ body[start...start+methods] =
289
+ s(:casgn, *name.children, s(:hash, *pairs.flatten))
290
+ else
291
+ body[start...start+methods] = s(:hash, *pairs.flatten)
292
+ end
293
+ elsif @ast.type == :class_extend or extend
247
294
  body[start...start+methods] =
248
- s(:casgn, *name.children, s(:hash, *pairs.flatten))
295
+ s(:assign, body[start].children.first, s(:hash, *pairs.flatten))
249
296
  else
250
297
  body[start...start+methods] =
251
298
  s(:send, name, :prototype=, s(:hash, *pairs.flatten))
252
299
  end
300
+
301
+ elsif (@ast.type == :class_extend or extend) and methods > 1
302
+
303
+ pairs = body[start...start+methods].map do |node|
304
+ node.updated(:pair, [
305
+ s(:sym, node.children[1].to_s[0..-2]), node.children[2]])
306
+ end
307
+
308
+ body[start...start+methods] =
309
+ s(:assign, body[start].children.first, s(:hash, *pairs))
253
310
  end
254
311
  end
255
312
 
@@ -258,7 +315,7 @@ module Ruby2JS
258
315
  constructor = init.updated(:constructor, [name, *init.children[1..-1]])
259
316
  @comments[constructor] = @comments[init] unless @comments[init].empty?
260
317
 
261
- if @ast.type == :class_extend
318
+ if @ast.type == :class_extend or extend
262
319
  if es2015
263
320
  constructor = s(:masgn, s(:mlhs,
264
321
  s(:attr, s(:casgn, *name.children, constructor), :prototype)),
@@ -285,6 +342,7 @@ module Ruby2JS
285
342
 
286
343
  # add locally visible interfaces to rbstack. See send.rb, const.rb
287
344
  @rbstack.push visible
345
+ @rbstack.last.merge!(@namespace.find(inheritance)) if inheritance
288
346
 
289
347
  parse s(:begin, *body.compact), :statement
290
348
  ensure
@@ -292,6 +350,7 @@ module Ruby2JS
292
350
  @class_name = class_name
293
351
  @class_parent = class_parent
294
352
  @rbstack.pop
353
+ @namespace.leave unless @ast.type == :class_module
295
354
  end
296
355
  end
297
356
 
@@ -9,11 +9,24 @@ module Ruby2JS
9
9
  # NOTE: this is the es2015 version of class
10
10
 
11
11
  handle :class2 do |name, inheritance, *body|
12
- if name.type == :const and name.children.first == nil
12
+ body.compact!
13
+ while body.length == 1 and body.first.type == :begin
14
+ body = body.first.children
15
+ end
16
+
17
+ proxied = body.find do |node|
18
+ node.type == :def and node.children.first == :method_missing
19
+ end
20
+
21
+ if not name
22
+ put 'class'
23
+ elsif name.type == :const and name.children.first == nil
13
24
  put 'class '
14
25
  parse name
26
+ put '$' if proxied
15
27
  else
16
28
  parse name
29
+ put '$' if proxied
17
30
  put ' = class'
18
31
  end
19
32
 
@@ -24,15 +37,11 @@ module Ruby2JS
24
37
 
25
38
  put " {"
26
39
 
27
- body.compact!
28
- while body.length == 1 and body.first.type == :begin
29
- body = body.first.children
30
- end
31
-
32
40
  begin
33
41
  class_name, @class_name = @class_name, name
34
42
  class_parent, @class_parent = @class_parent, inheritance
35
- @rbstack.push({})
43
+ @rbstack.push(@namespace.getOwnProps)
44
+ @rbstack.last.merge!(@namespace.find(inheritance)) if inheritance
36
45
  constructor = []
37
46
  index = 0
38
47
 
@@ -40,10 +49,17 @@ module Ruby2JS
40
49
  body.each do |m|
41
50
  if m.type == :def
42
51
  prop = m.children.first
43
- if prop == :initialize
52
+ if prop == :initialize and !@rbstack.last[:initialize]
44
53
  constructor = m.children[2..-1]
45
- elsif not prop.to_s.end_with? '='
46
- @rbstack.last[prop] = s(:self)
54
+ elsif prop.to_s.end_with? '='
55
+ @rbstack.last[prop.to_s[0..-2].to_sym] = s(:autobind, s(:self))
56
+ else
57
+ @rbstack.last[prop] = m.is_method? ? s(:autobind, s(:self)) : s(:self)
58
+ end
59
+ elsif m.type == :send and m.children[0..1] == [nil, :async]
60
+ if m.children[2].type == :def
61
+ prop = m.children[2].children.first
62
+ @rbstack.last[prop] = s(:autobind, s(:self))
47
63
  end
48
64
  end
49
65
  end
@@ -64,21 +80,21 @@ module Ruby2JS
64
80
  walk[child] if child.is_a? Parser::AST::Node
65
81
  end
66
82
 
67
- if ast.type == :send and ast.children.first == nil
68
- if ast.children[1] == :attr_accessor
69
- ast.children[2..-1].each_with_index do |child_sym, index2|
70
- ivars << :"@#{child_sym.children.first}"
71
- end
72
- elsif ast.children[1] == :attr_reader
73
- ast.children[2..-1].each_with_index do |child_sym, index2|
74
- ivars << :"@#{child_sym.children.first}"
75
- end
76
- elsif ast.children[1] == :attr_writer
77
- ast.children[2..-1].each_with_index do |child_sym, index2|
78
- ivars << :"@#{child_sym.children.first}"
79
- end
80
- end
81
- end
83
+ if ast.type == :send and ast.children.first == nil
84
+ if ast.children[1] == :attr_accessor
85
+ ast.children[2..-1].each_with_index do |child_sym, index2|
86
+ ivars << :"@#{child_sym.children.first}"
87
+ end
88
+ elsif ast.children[1] == :attr_reader
89
+ ast.children[2..-1].each_with_index do |child_sym, index2|
90
+ ivars << :"@#{child_sym.children.first}"
91
+ end
92
+ elsif ast.children[1] == :attr_writer
93
+ ast.children[2..-1].each_with_index do |child_sym, index2|
94
+ ivars << :"@#{child_sym.children.first}"
95
+ end
96
+ end
97
+ end
82
98
 
83
99
  end
84
100
  walk[@ast]
@@ -140,10 +156,10 @@ module Ruby2JS
140
156
  end
141
157
  end
142
158
 
143
- if m.type == :def || m.type == :async
159
+ if m.type == :def || m.type == :defm || m.type == :async
144
160
  @prop = m.children.first
145
161
 
146
- if @prop == :initialize
162
+ if @prop == :initialize and !@rbstack.last[:initialize]
147
163
  @prop = :constructor
148
164
 
149
165
  if constructor == [] or constructor == [(:super)]
@@ -190,7 +206,7 @@ module Ruby2JS
190
206
  @prop = "static #{m.children[1]}"
191
207
  end
192
208
 
193
- @prop.sub! 'static', 'static async' if m.type == :asyncs
209
+ @prop = @prop.sub('static', 'static async') if m.type == :asyncs
194
210
 
195
211
  m = m.updated(:def, m.children[1..3])
196
212
  begin
@@ -208,6 +224,7 @@ module Ruby2JS
208
224
  m.children[2..-1].each_with_index do |child_sym, index2|
209
225
  put @sep unless index2 == 0
210
226
  var = child_sym.children.first
227
+ @rbstack.last[var] = s(:self)
211
228
  put "get #{var}() {#{@nl}return this.#{p}#{var}#@nl}#@sep"
212
229
  put "set #{var}(#{var}) {#{@nl}this.#{p}#{var} = #{var}#@nl}"
213
230
  end
@@ -215,12 +232,14 @@ module Ruby2JS
215
232
  m.children[2..-1].each_with_index do |child_sym, index2|
216
233
  put @sep unless index2 == 0
217
234
  var = child_sym.children.first
235
+ @rbstack.last[var] = s(:self)
218
236
  put "get #{var}() {#{@nl}return this.#{p}#{var}#@nl}"
219
237
  end
220
238
  elsif m.children[1] == :attr_writer
221
239
  m.children[2..-1].each_with_index do |child_sym, index2|
222
240
  put @sep unless index2 == 0
223
241
  var = child_sym.children.first
242
+ @rbstack.last[var] = s(:self)
224
243
  put "set #{var}(#{var}) {#{@nl}this.#{p}#{var} = #{var}#@nl}"
225
244
  end
226
245
  elsif [:private, :protected, :public].include? m.children[1]
@@ -228,13 +247,27 @@ module Ruby2JS
228
247
  else
229
248
  if m.children[1] == :include
230
249
  m = m.updated(:begin, m.children[2..-1].map {|mname|
231
- s(:send, s(:const, nil, :Object), :assign,
232
- s(:attr, name, :prototype), mname)})
250
+ @namespace.defineProps @namespace.find(mname)
251
+ s(:assign, s(:attr, name, :prototype), mname)
252
+ })
233
253
  end
234
254
 
235
255
  skipped = true
236
256
  end
237
257
 
258
+ elsif es2022 and \
259
+ m.type == :send and m.children.first.type == :self and \
260
+ m.children[1].to_s.end_with? '='
261
+
262
+ put 'static '
263
+ parse m.updated(:lvasgn, [m.children[1].to_s.sub('=', ''),
264
+ m.children[2]])
265
+
266
+ elsif m.type == :defineProps
267
+ skipped = true
268
+ @namespace.defineProps m.children.first
269
+ @rbstack.last.merge! m.children.first
270
+
238
271
  else
239
272
  if m.type == :cvasgn and !underscored_private
240
273
  put 'static #$'; put m.children[0].to_s[2..-1]; put ' = '
@@ -246,7 +279,7 @@ module Ruby2JS
246
279
  if m.type == :casgn and m.children[0] == nil
247
280
  @rbstack.last[m.children[1]] = name
248
281
 
249
- if es2020
282
+ if es2022
250
283
  put 'static '; put m.children[1].to_s; put ' = '
251
284
  parse m.children[2]
252
285
  skipped = false
@@ -257,7 +290,7 @@ module Ruby2JS
257
290
  end
258
291
 
259
292
  if skipped
260
- post << [m, comments] if skipped
293
+ post << [m, comments] unless m.type == :defineProps
261
294
  else
262
295
  comments.reverse.each {|comment| insert location, comment}
263
296
  end
@@ -294,15 +327,56 @@ module Ruby2JS
294
327
  else
295
328
  parse m.updated(:send, [@class_name, *m.children[1..-1]])
296
329
  end
330
+ elsif m.type == :block and m.children.first.children.first == nil
331
+ # class method calls passing a block
332
+ parse s(:block, s(:send, name, *m.children.first.children[1..-1]),
333
+ *m.children[1..-1])
297
334
  else
298
335
  parse m, :statement
299
336
  end
300
337
  end
301
338
 
339
+ if proxied
340
+ put @sep
341
+
342
+ rename = name.updated(nil, [name.children.first, name.children.last.to_s + '$'])
343
+
344
+ if proxied.children[1].children.length == 1
345
+ # special case: if method_missing only has on argument, call it
346
+ # directly (i.e., don't pass arguments). This enables
347
+ # method_missing to return instance attributes (getters) as well
348
+ # as bound functions (methods).
349
+ forward = s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop))
350
+ else
351
+ # normal case: return a function which, when called, will call
352
+ # method_missing with method name and arguments.
353
+ forward = s(:block, s(:send, nil, :proc), s(:args, s(:restarg, :args)),
354
+ s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop),
355
+ s(:splat, s(:lvar, :args))))
356
+ end
357
+
358
+ proxy = s(:return, s(:send, s(:const, nil, :Proxy), :new,
359
+ s(:send, rename, :new, s(:splat, s(:lvar, :args))),
360
+ s(:hash, s(:pair, s(:sym, :get), s(:block, s(:send, nil, :proc),
361
+ s(:args, s(:arg, :obj), s(:arg, :prop)),
362
+ s(:if, s(:in?, s(:lvar, :prop), s(:lvar, :obj)),
363
+ s(:return, s(:send, s(:lvar, :obj), :[], s(:lvar, :prop))),
364
+ s(:return, forward))))))
365
+ )
366
+
367
+ if name.children.first == nil
368
+ proxy = s(:def, name.children.last, s(:args, s(:restarg, :args)), proxy)
369
+ else
370
+ proxy = s(:defs, *name.children, s(:args, s(:restarg, :args)), proxy)
371
+ end
372
+
373
+ parse proxy
374
+ end
375
+
302
376
  ensure
303
377
  @class_name = class_name
304
378
  @class_parent = class_parent
305
- @rbstack.pop
379
+ @namespace.defineProps @rbstack.pop
306
380
  end
307
381
  end
308
382
  end