ruby2js 2.0.18 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6a8536e0ac6c8225fa67af8d2b8d7e61dea03e0
4
- data.tar.gz: 613628648eba36cd5da7cf87c4abf7fd26ca232a
3
+ metadata.gz: af96d4a5579bf41a109fbf248e6639302113cd01
4
+ data.tar.gz: 90062d392b1cb821f403b3e40f751fd4bcc3cb85
5
5
  SHA512:
6
- metadata.gz: c4aaf90a8cfff4aad198efbe8247930c67fc2da306b45f7d11017cad59560de42fd01d93b62284025b37c63e4861096b677eab94de423b890a353e919ef5e9bc
7
- data.tar.gz: 0f3f72481dfa37aa1fc1c3a17231206b0755dfcd13c35e893459a4cf92e6b07bee435cf67a608e788efd8a60598f151010c987cc6496fb8aafac67152e447e30
6
+ metadata.gz: e03b33dc464a0852d874a4c0c8815d9252c7df7c81d08a6ae4dc178b68db16130c9782512fedeb895937f2b2ade2d6f76a75206324d3680b4ec9cbf05233de3a
7
+ data.tar.gz: 5ba34dc016fd19d17c0b39541c7127b7a117e2aea6ad9bca920e8d2eeb500bab7fd573d74ca1dd797a3382c70dac519fe8ee0dbe299f10f47407efa7d4ee9cf8
@@ -161,7 +161,7 @@ module Parser
161
161
  selector = loc.name
162
162
  end
163
163
 
164
- return true unless selector.source_buffer
164
+ return true unless selector and selector.source_buffer
165
165
  selector.source_buffer.source[selector.end_pos] == '('
166
166
  end
167
167
  end
@@ -771,8 +771,7 @@ module Ruby2JS
771
771
  # convert global variables to refs
772
772
  def on_gvar(node)
773
773
  return super unless @reactClass
774
- ref = s(:attr, s(:attr, s(:self), :refs),
775
- node.children.first.to_s[1..-1])
774
+ s(:attr, s(:attr, s(:self), :refs), node.children.first.to_s[1..-1])
776
775
  end
777
776
 
778
777
  # convert instance variables to state
@@ -0,0 +1,733 @@
1
+ require 'ruby2js'
2
+
3
+ module Ruby2JS
4
+ module Filter
5
+ module Vue
6
+ include SEXP
7
+
8
+ VUE_METHODS = [
9
+ :delete, :destroy, :emit, :forceUpdate, :mount, :nextTick, :off, :on,
10
+ :once, :set, :watch
11
+ ]
12
+
13
+ def initialize(*args)
14
+ @vue_h = nil
15
+ @vue_self = nil
16
+ @vue_apply = nil
17
+ @vue_inventory = Hash.new {|h, k| h[k] = []}
18
+ super
19
+ end
20
+
21
+ def options=(options)
22
+ super
23
+ @vue_h ||= options[:vue_h]
24
+ end
25
+
26
+ # Example conversion
27
+ # before:
28
+ # (class (const nil :Foo) (const nil :Vue) nil)
29
+ # after:
30
+ # (casgn nil :Foo, (send nil, :Vue, :component, (:str, "foo"),
31
+ # s(:hash)))
32
+ def on_class(node)
33
+ cname, inheritance, *body = node.children
34
+ return super unless cname.children.first == nil
35
+ return super unless inheritance == s(:const, nil, :Vue)
36
+
37
+ # traverse down to actual list of class statements
38
+ if body.length == 1
39
+ if not body.first
40
+ body = []
41
+ elsif body.first.type == :begin
42
+ body = body.first.children
43
+ end
44
+ end
45
+
46
+ hash = []
47
+ methods = []
48
+
49
+ # insert constructor if none present
50
+ unless body.any? {|statement|
51
+ statement.type == :def and statement.children.first ==:initialize}
52
+ then
53
+ body = body.dup
54
+ body.unshift s(:def, :initialize, s(:args), nil)
55
+ end
56
+
57
+ @vue_inventory = vue_walk(node)
58
+
59
+ # convert body into hash
60
+ body.each do |statement|
61
+
62
+ # named values
63
+ if statement.type == :send and statement.children.first == nil
64
+ if [:template, :props].include? statement.children[1]
65
+ hash << s(:pair, s(:sym, statement.children[1]),
66
+ statement.children[2])
67
+ end
68
+
69
+ # methods
70
+ elsif statement.type == :def
71
+ begin
72
+ @vue_self = s(:attr, s(:self), :$data)
73
+ method, args, block = statement.children
74
+ if method == :render
75
+ args = s(:args, s(:arg, :$h)) if args.children.empty?
76
+
77
+ block = s(:begin, block) unless block and block.type == :begin
78
+
79
+ if
80
+ block.children.length != 1 or not block.children.last or
81
+ not [:send, :block].include? block.children.first.type
82
+ then
83
+ # wrap multi-line blocks with a 'span' element
84
+ block = s(:return,
85
+ s(:block, s(:send, nil, :_span), s(:args), *block))
86
+ end
87
+
88
+ @vue_h = args.children.first.children.last
89
+ elsif method == :initialize
90
+ method = :data
91
+
92
+ # find block
93
+ if block == nil
94
+ block = s(:begin)
95
+ elsif block.type != :begin
96
+ block = s(:begin, block)
97
+ end
98
+
99
+ simple = block.children.all? {|child| child.type == :ivasgn}
100
+
101
+ # not so simple if ivars are being read as well as written
102
+ if simple
103
+ block_inventory = vue_walk(block)
104
+ simple = block_inventory[:ivar].empty?
105
+ end
106
+
107
+ uninitialized = @vue_inventory[:ivar].dup
108
+
109
+ block.children.each do |child|
110
+ if child.type == :ivasgn
111
+ uninitialized.delete child.children.first
112
+ end
113
+ end
114
+
115
+ # convert to a hash
116
+ if simple
117
+ # simple case: all statements are ivar assignments
118
+ pairs = block.children.map do |child|
119
+ s(:pair, s(:sym, child.children[0].to_s[1..-1]),
120
+ process(child.children[1]))
121
+ end
122
+
123
+ pairs += uninitialized.map do |symbol|
124
+ s(:pair, s(:sym, symbol.to_s[1..-1]),
125
+ s(:attr, nil, :undefined))
126
+ end
127
+
128
+ block = s(:return, s(:hash, *pairs))
129
+ else
130
+ # general case: build up a hash incrementally
131
+ block = s(:begin, s(:gvasgn, :$_,
132
+ s(:hash, *uninitialized.map {|sym|
133
+ s(:pair, s(:sym, sym.to_s[1..-1]),
134
+ s(:attr, nil, :undefined))})),
135
+ block, s(:return, s(:gvar, :$_)))
136
+ @vue_self = s(:gvar, :$_)
137
+ end
138
+ end
139
+
140
+ # add to hash in the appropriate location
141
+ pair = s(:pair, s(:sym, method),
142
+ s(:block, s(:send, nil, :lambda), args, process(block)))
143
+ if %w(data render beforeCreate created beforeMount mounted
144
+ beforeUpdate updated beforeDestroy destroyed
145
+ ).include? method.to_s
146
+ then
147
+ hash << pair
148
+ else
149
+ methods << pair
150
+ end
151
+ ensure
152
+ @vue_h = nil
153
+ @vue_self = nil
154
+ end
155
+ end
156
+ end
157
+
158
+ unless hash.any? {|pair| pair.children[0].children[0] == :props}
159
+ unless @vue_inventory[:cvar].empty?
160
+ hash.unshift s(:pair, s(:sym, :props), s(:array,
161
+ *@vue_inventory[:cvar].map {|sym| s(:str, sym.to_s[2..-1])}))
162
+ end
163
+ end
164
+
165
+ # add methods to hash
166
+ unless methods.empty?
167
+ hash << s(:pair, s(:sym, :methods), s(:hash, *methods))
168
+ end
169
+
170
+ # convert class name to camel case
171
+ camel = cname.children.last.to_s.gsub(/[^\w]/, '-').
172
+ sub(/^[A-Z]/) {|c| c.downcase}.
173
+ gsub(/[A-Z]/) {|c| "-#{c.downcase}"}
174
+
175
+ # build component
176
+ s(:casgn, nil, cname.children.last,
177
+ s(:send, s(:const, nil, :Vue), :component,
178
+ s(:str, camel), s(:hash, *hash)))
179
+ end
180
+
181
+ # expand 'wunderbar' like method calls
182
+ def on_send(node)
183
+ if not @vue_h
184
+ # enable React filtering within React class method calls or
185
+ # React component calls
186
+ if
187
+ node.children.first == s(:const, nil, :Vue)
188
+ then
189
+ begin
190
+ vue_h, @vue_h = @vue_h, :$h
191
+ return on_send(node)
192
+ ensure
193
+ @vue_h = vue_h
194
+ end
195
+ end
196
+ end
197
+
198
+ # map method calls involving i/g/c vars to straight calls
199
+ #
200
+ # input:
201
+ # @x.(a,b,c)
202
+ # output:
203
+ # @x(a,b,c)
204
+ if @vue_self and node.children[1] == :call
205
+ if [:ivar, :gvar, :cvar].include? node.children.first.type
206
+ return process(s(:send, node.children.first, nil,
207
+ *node.children[2..-1]))
208
+ else
209
+ return super
210
+ end
211
+ end
212
+
213
+ return super unless @vue_h
214
+
215
+ if node.children[0] == nil and node.children[1] =~ /^_\w/
216
+ tag = node.children[1].to_s[1..-1]
217
+ hash = Hash.new {|h, k| h[k] = {}}
218
+ args = []
219
+ complex_block = []
220
+ component = (tag =~ /^[A-Z]/)
221
+
222
+ node.children[2..-1].each do |attr|
223
+ if attr.type == :hash
224
+ # attributes
225
+ # https://github.com/vuejs/babel-plugin-transform-vue-jsx#difference-from-react-jsx
226
+ pairs = attr.children.dup
227
+
228
+ # extract all class names
229
+ classes = pairs.find_all do |pair|
230
+ key = pair.children.first.children.first
231
+ [:class, 'class', :className, 'className'].include? key
232
+ end
233
+
234
+ # combine all classes into a single value (or expression)
235
+ if classes.length > 0
236
+ expr = nil
237
+ values = classes.map do |pair|
238
+ if [:sym, :str].include? pair.children.last.type
239
+ pair.children.last.children.first.to_s
240
+ else
241
+ expr = pair.children.last
242
+ ''
243
+ end
244
+ end
245
+ pairs -= classes
246
+ if expr
247
+ if values.length > 1
248
+ while expr.type == :begin and expr.children.length == 1
249
+ expr = expr.children.first
250
+ end
251
+
252
+ if expr.type == :array
253
+ hash[:class] = s(:array, *expr.children,
254
+ *values.join(' ').split(' ').map {|str| s(:str, str)})
255
+ elsif expr.type == :hash
256
+ hash[:class] = s(:hash, *expr.children,
257
+ *values.join(' ').split(' ').
258
+ map {|str| s(:pair, s(:str, str), s(:true))})
259
+ else
260
+ if
261
+ expr.type == :if and expr.children[1] and
262
+ expr.children[1].type == :str
263
+ then
264
+ left = expr.children[1]
265
+ right = expr.children[2] || s(:str, '')
266
+
267
+ unless right.type == :str
268
+ right = s(:or, right, s(:str, ''))
269
+ end
270
+
271
+ expr = expr.updated(nil,
272
+ [expr.children[0], left, right])
273
+ elsif expr.type != :str
274
+ expr = s(:or, expr, s(:str, ''))
275
+ end
276
+
277
+ value = s(:send, s(:str, values.join(' ')), :+, expr)
278
+ pairs.unshift s(:pair, s(:sym, :class), value)
279
+ end
280
+ elsif [:hash, :array].include? expr.type
281
+ hash[:class] = expr
282
+ else
283
+ pairs.unshift s(:pair, s(:sym, :class), expr)
284
+ end
285
+ else
286
+ hash[:class] = s(:array,
287
+ *values.join(' ').split(' ').map {|str| s(:str, str)})
288
+ end
289
+ end
290
+
291
+ # search for the presence of a 'style' attribute
292
+ style = pairs.find_index do |pair|
293
+ ['style', :style].include? pair.children.first.children.first
294
+ end
295
+
296
+ # converts style strings into style hashes
297
+ if style and pairs[style].children[1].type == :str
298
+ rules = []
299
+ value = pairs[style].children[1].children[0]
300
+ value.split(/;\s+/).each do |prop|
301
+ prop.strip!
302
+ next unless prop =~ /^([-a-z]+):\s*(.*)$/
303
+ name, value = $1, $2
304
+ name.gsub!(/-[a-z]/) {|str| str[1].upcase}
305
+ if value =~ /^-?\d+$/
306
+ rules << s(:pair, s(:str, name), s(:int, value.to_i))
307
+ elsif value =~ /^-?\d+$\.\d*/
308
+ rules << s(:pair, s(:str, name), s(:float, value.to_f))
309
+ else
310
+ rules << s(:pair, s(:str, name), s(:str, value))
311
+ end
312
+ end
313
+ pairs.delete_at(style)
314
+ hash[:style] = s(:hash, *rules)
315
+ end
316
+
317
+ # process remaining attributes
318
+ pairs.each do |pair|
319
+ name = pair.children[0].children[0].to_s
320
+ if name =~ /^(nativeOn|on)([A-Z])(.*)/
321
+ hash[$1]["#{$2.downcase}#$3"] = pair.children[1]
322
+ elsif component
323
+ hash[:props][name] = pair.children[1]
324
+ elsif name =~ /^domProps([A-Z])(.*)/
325
+ hash[:domProps]["#{$1.downcase}#$2"] = pair.children[1]
326
+ elsif name == 'style' and pair.children[1].type == :hash
327
+ hash[:style] = pair.children[1]
328
+ elsif %w(key ref refInFor slot).include? name
329
+ hash[name] = pair.children[1]
330
+ else
331
+ hash[:attrs][name.to_s.gsub('_', '-')] = pair.children[1]
332
+ end
333
+ end
334
+
335
+ elsif attr.type == :block
336
+ # traverse down to actual list of nested statements
337
+ statements = attr.children[2..-1]
338
+ if statements.length == 1
339
+ if not statements.first
340
+ statements = []
341
+ elsif statements.first.type == :begin
342
+ statements = statements.first.children
343
+ end
344
+ end
345
+
346
+ # check for normal case: only elements and text
347
+ simple = statements.all? do |arg|
348
+ # explicit call to Vue.createElement
349
+ next true if arg.children[1] == :createElement and
350
+ arg.children[0] == s(:const, nil, :Vue)
351
+
352
+ # wunderbar style call
353
+ arg = arg.children.first if arg.type == :block
354
+ while arg.type == :send and arg.children.first != nil
355
+ arg = arg.children.first
356
+ end
357
+ arg.type == :send and arg.children[1] =~ /^_/
358
+ end
359
+
360
+ if simple
361
+ args << s(:array, *statements)
362
+ else
363
+ complex_block += statements
364
+ end
365
+
366
+ else
367
+ # text or child elements
368
+ args << node.children[2]
369
+ end
370
+ end
371
+
372
+ # support controlled form components
373
+ if %w(input select textarea).include? tag
374
+ # search for the presence of a 'value' attribute
375
+ value = hash[:attrs]['value']
376
+
377
+ # search for the presence of a 'onChange' attribute
378
+ onChange = hash['on']['input'] ||
379
+ hash['on']['change'] ||
380
+ hash['nativeOn']['input'] ||
381
+ hash['nativeOn']['change']
382
+
383
+ if value and value.type == :ivar and !onChange
384
+ hash['domProps']['value'] ||= value
385
+ hash['on']['input'] ||=
386
+ s(:block, s(:send, nil, :proc), s(:args, s(:arg, :event)),
387
+ s(:ivasgn, value.children.first,
388
+ s(:attr, s(:attr, s(:lvar, :event), :target), :value)))
389
+ hash[:attrs].delete('value')
390
+ end
391
+
392
+ if not value and not onChange and tag == 'input'
393
+ # search for the presence of a 'checked' attribute
394
+ checked = hash[:attrs]['checked']
395
+
396
+ if checked and checked.type == :ivar
397
+ hash['domProps']['checked'] ||= checked
398
+ hash['on']['click'] ||=
399
+ s(:block, s(:send, nil, :proc), s(:args),
400
+ s(:ivasgn,checked.children.first,
401
+ s(:send, checked, :!)))
402
+ end
403
+ end
404
+ end
405
+
406
+ # put attributes up front
407
+ unless hash.empty?
408
+ pairs = hash.to_a.map do |k1, v1|
409
+ next if Hash === v1 and v1.empty?
410
+ s(:pair, s(:str, k1.to_s),
411
+ if Parser::AST::Node === v1
412
+ v1
413
+ else
414
+ s(:hash, *v1.map {|k2, v2| s(:pair, s(:str, k2.to_s), v2)})
415
+ end
416
+ )
417
+ end
418
+ args.unshift s(:hash, *pairs.compact)
419
+ end
420
+
421
+ # prepend element name
422
+ if component
423
+ args.unshift s(:const, nil, tag)
424
+ else
425
+ args.unshift s(:str, tag)
426
+ end
427
+
428
+ begin
429
+ vue_apply = @vue_apply
430
+
431
+ if complex_block.empty?
432
+ @vue_apply = false
433
+
434
+ # emit $h (createElement) call
435
+ element = node.updated :send, [nil, @vue_h, *process_all(args)]
436
+ else
437
+ # calls to $h (createElement) which contain a block
438
+ #
439
+ # collect array of child elements in a proc, and call that proc
440
+ #
441
+ # $h('tag', hash, proc {
442
+ # var $_ = []
443
+ # $_.push($h(...))
444
+ # return $_
445
+ # }())
446
+ #
447
+ @vue_apply = true
448
+
449
+ element = node.updated :send, [nil, @vue_h,
450
+ *process_all(args),
451
+ s(:send, s(:block, s(:send, nil, :proc),
452
+ s(:args, s(:shadowarg, :$_)), s(:begin,
453
+ s(:lvasgn, :$_, s(:array)),
454
+ *process_all(complex_block),
455
+ s(:return, s(:lvar, :$_)))), :[])]
456
+ end
457
+ ensure
458
+ @vue_apply = vue_apply
459
+ end
460
+
461
+ if @vue_apply
462
+ # if apply is set, emit code that pushes result
463
+ s(:send, s(:gvar, :$_), :push, element)
464
+ else
465
+ element
466
+ end
467
+
468
+ elsif node.children[0] == nil and node.children[1] == :_
469
+ # text nodes
470
+ # https://stackoverflow.com/questions/42414627/create-text-node-with-custom-render-function-in-vue-js
471
+ text = s(:send, s(:self), :_v, process(node.children[2]))
472
+ if @vue_apply
473
+ # if apply is set, emit code that pushes text
474
+ s(:send, s(:gvar, :$_), :push, text)
475
+ else
476
+ # simple/normal case: simply return the text
477
+ text
478
+ end
479
+
480
+ elsif node.children[0]==s(:send, nil, :_) and node.children[1]==:[]
481
+ if @vue_apply
482
+ # if apply is set, emit code that pushes results
483
+ s(:send, s(:gvar, :$_), :push, *process_all(node.children[2..-1]))
484
+ elsif node.children.length == 3
485
+ process(node.children[2])
486
+ else
487
+ # simple/normal case: simply return the element
488
+ s(:splat, s(:array, *process_all(node.children[2..-1])))
489
+ end
490
+
491
+ elsif
492
+ node.children[1] == :createElement and
493
+ node.children[0] == s(:const, nil, :Vue)
494
+ then
495
+ # explicit calls to Vue.createElement
496
+ element = node.updated nil, [nil, :$h,
497
+ *process_all(node.children[2..-1])]
498
+
499
+ if @vue_apply
500
+ # if apply is set, emit code that pushes result
501
+ s(:send, s(:gvar, :$_), :push, element)
502
+ else
503
+ element
504
+ end
505
+
506
+ elsif
507
+ VUE_METHODS.include? node.children[1] and
508
+ node.children[0] == s(:const, nil, :Vue)
509
+ then
510
+ # vm methods
511
+ node.updated nil, [s(:self), "$#{node.children[1]}",
512
+ *process_all(node.children[2..-1])]
513
+
514
+ elsif node.children[0] and node.children[0].type == :send
515
+ # determine if markaby style class and id names are being used
516
+ child = node
517
+ test = child.children.first
518
+ while test and test.type == :send and not test.is_method?
519
+ child, test = test, test.children.first
520
+ end
521
+
522
+ if child.children[0] == nil and child.children[1] =~ /^_\w/
523
+ # capture the arguments provided on the current node
524
+ children = node.children[2..-1]
525
+
526
+ # convert method calls to id and class values
527
+ while node != child
528
+ if node.children[1] !~ /!$/
529
+ # convert method name to hash {class: name} pair
530
+ pair = s(:pair, s(:sym, :class),
531
+ s(:str, node.children[1].to_s.gsub('_','-')))
532
+ else
533
+ # convert method name to hash {id: name} pair
534
+ pair = s(:pair, s(:sym, :id),
535
+ s(:str, node.children[1].to_s[0..-2].gsub('_','-')))
536
+ end
537
+
538
+ # if a hash argument is already passed, merge in id value
539
+ hash = children.find_index {|cnode| cnode.type == :hash}
540
+ if hash
541
+ children[hash] = s(:hash, pair, *children[hash].children)
542
+ else
543
+ children << s(:hash, pair)
544
+ end
545
+
546
+ # advance to next node
547
+ node = node.children.first
548
+ end
549
+
550
+ # collapse series of method calls into a single call
551
+ return process(node.updated(nil, [*node.children[0..1], *children]))
552
+
553
+ else
554
+ super
555
+ end
556
+
557
+ else
558
+ super
559
+ end
560
+ end
561
+
562
+ # convert blocks to proc arguments
563
+ def on_block(node)
564
+ child = node.children.first
565
+
566
+ # map Vue.render(el, &block) to Vue.new(el: el, render: block)
567
+ if
568
+ child.children[1] == :render and
569
+ child.children[0] == s(:const, nil, :Vue)
570
+ then
571
+ begin
572
+ arg = node.children[1].children[0] || s(:arg, :$h)
573
+ vue_h, @vue_h = @vue_h, arg.children.first
574
+
575
+ block = node.children[2]
576
+ block = s(:begin, block) unless block and block.type == :begin
577
+
578
+ if
579
+ block.children.length != 1 or not block.children.last or
580
+ not [:send, :block].include? block.children.first.type
581
+ then
582
+ # wrap multi-line blocks with a 'span' element
583
+ block = s(:return,
584
+ s(:block, s(:send, nil, :_span), s(:args), *block))
585
+ end
586
+
587
+ return node.updated :send, [child.children[0], :new,
588
+ s(:hash, s(:pair, s(:sym, :el), process(child.children[2])),
589
+ s(:pair, s(:sym, :render), s(:block, s(:send, nil, :lambda),
590
+ s(:args, s(:arg, @vue_h)), process(block))))]
591
+ ensure
592
+ @vue_h = vue_h
593
+ end
594
+ end
595
+
596
+ return super unless @vue_h
597
+
598
+ if
599
+ child.children[1] == :createElement and
600
+ child.children[0] == s(:const, nil, :Vue)
601
+ then
602
+ # block calls to Vue.createElement
603
+ #
604
+ # collect array of child elements in a proc, and call that proc
605
+ #
606
+ # $h('tag', hash, proc {
607
+ # var $_ = []
608
+ # $_.push($h(...))
609
+ # return $_
610
+ # }())
611
+ #
612
+ begin
613
+ vue_apply, @vue_apply = @vue_apply, true
614
+
615
+ element = node.updated :send, [nil, @vue_h,
616
+ *child.children[2..-1],
617
+ s(:send, s(:block, s(:send, nil, :proc),
618
+ s(:args, s(:shadowarg, :$_)), s(:begin,
619
+ s(:lvasgn, :$_, s(:array)),
620
+ process(node.children[2]),
621
+ s(:return, s(:lvar, :$_)))), :[])]
622
+ ensure
623
+ @vue_apply = vue_apply
624
+ end
625
+
626
+ if @vue_apply
627
+ # if apply is set, emit code that pushes result
628
+ return s(:send, s(:gvar, :$_), :push, element)
629
+ else
630
+ return element
631
+ end
632
+ end
633
+
634
+ # traverse through potential "css proxy" style method calls
635
+ child = node.children.first
636
+ test = child.children.first
637
+ while test and test.type == :send and not test.is_method?
638
+ child, test = test, test.children.first
639
+ end
640
+
641
+ # wunderbar style calls
642
+ if child.children[0] == nil and child.children[1] =~ /^_\w/
643
+ if node.children[1].children.empty?
644
+ # append block as a standalone proc
645
+ block = s(:block, s(:send, nil, :proc), s(:args),
646
+ *node.children[2..-1])
647
+ return on_send node.children.first.updated(:send,
648
+ [*node.children.first.children, block])
649
+ else
650
+ # iterate over Enumerable arguments if there are args present
651
+ send = node.children.first.children
652
+ return super if send.length < 3
653
+ return process s(:block, s(:send, *send[0..1], *send[3..-1]),
654
+ s(:args), s(:block, s(:send, send[2], :forEach),
655
+ *node.children[1..-1]))
656
+ end
657
+ else
658
+ super
659
+ end
660
+ end
661
+
662
+ # expand @@ to self
663
+ def on_cvar(node)
664
+ return super unless @vue_self
665
+ s(:attr, s(:attr, s(:self), :$props), node.children[0].to_s[2..-1])
666
+ end
667
+
668
+ # prevent attempts to assign to Vue properties
669
+ def on_cvasgn(node)
670
+ return super unless @vue_self
671
+ raise NotImplementedError, "setting a Vue property"
672
+ end
673
+
674
+ # expand @ to @vue_self
675
+ def on_ivar(node)
676
+ return super unless @vue_self
677
+ s(:attr, @vue_self, node.children[0].to_s[1..-1])
678
+ end
679
+
680
+ # expand @= to @vue_self.=
681
+ def on_ivasgn(node)
682
+ return super unless @vue_self
683
+ if node.children.length == 1
684
+ s(:attr, @vue_self, "#{node.children[0].to_s[1..-1]}")
685
+ else
686
+ s(:send, @vue_self, "#{node.children[0].to_s[1..-1]}=",
687
+ process(node.children[1]))
688
+ end
689
+ end
690
+
691
+ def on_op_asgn(node)
692
+ return super unless @vue_self
693
+ return super unless node.children.first.type == :ivasgn
694
+ node.updated nil, [s(:attr, @vue_self,
695
+ node.children[0].children[0].to_s[1..-1]),
696
+ node.children[1], process(node.children[2])]
697
+ end
698
+
699
+ # gather ivar and cvar usage
700
+ def vue_walk(node, inventory = Hash.new {|h, k| h[k] = []})
701
+ # extract ivars and cvars
702
+ if [:ivar, :cvar].include? node.type
703
+ symbol = node.children.first
704
+ unless inventory[node.type].include? symbol
705
+ inventory[node.type] << symbol
706
+ end
707
+ elsif node.type == :ivasgn
708
+ symbol = nil
709
+ symbol = node.children.first if node.children.length == 1
710
+ if node.children.length == 2
711
+ value = node.children[-1]
712
+ symbol = value.children.first if value.type == :ivasgn
713
+ end
714
+
715
+ if symbol
716
+ unless inventory[:ivar].include? symbol
717
+ inventory[:ivar] << symbol
718
+ end
719
+ end
720
+ end
721
+
722
+ # recurse
723
+ node.children.each do |child|
724
+ vue_walk(child, inventory) if Parser::AST::Node === child
725
+ end
726
+
727
+ return inventory
728
+ end
729
+ end
730
+
731
+ DEFAULTS.push Vue
732
+ end
733
+ end
@@ -1,8 +1,8 @@
1
1
  module Ruby2JS
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
- MINOR = 0
5
- TINY = 18
4
+ MINOR = 1
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/ruby2js.gemspec CHANGED
@@ -1,17 +1,17 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ruby2js 2.0.18 ruby lib
2
+ # stub: ruby2js 2.1.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ruby2js".freeze
6
- s.version = "2.0.18"
6
+ s.version = "2.1.0"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sam Ruby".freeze]
11
- s.date = "2017-07-29"
11
+ s.date = "2017-09-03"
12
12
  s.description = " The base package maps Ruby syntax to JavaScript semantics.\n Filters may be provided to add Ruby-specific or framework specific\n behavior.\n".freeze
13
13
  s.email = "rubys@intertwingly.net".freeze
14
- s.files = ["README.md".freeze, "lib/ruby2js".freeze, "lib/ruby2js.rb".freeze, "lib/ruby2js/cgi.rb".freeze, "lib/ruby2js/converter".freeze, "lib/ruby2js/converter.rb".freeze, "lib/ruby2js/converter/arg.rb".freeze, "lib/ruby2js/converter/args.rb".freeze, "lib/ruby2js/converter/array.rb".freeze, "lib/ruby2js/converter/begin.rb".freeze, "lib/ruby2js/converter/block.rb".freeze, "lib/ruby2js/converter/blockpass.rb".freeze, "lib/ruby2js/converter/boolean.rb".freeze, "lib/ruby2js/converter/break.rb".freeze, "lib/ruby2js/converter/case.rb".freeze, "lib/ruby2js/converter/casgn.rb".freeze, "lib/ruby2js/converter/class.rb".freeze, "lib/ruby2js/converter/const.rb".freeze, "lib/ruby2js/converter/cvar.rb".freeze, "lib/ruby2js/converter/cvasgn.rb".freeze, "lib/ruby2js/converter/def.rb".freeze, "lib/ruby2js/converter/defined.rb".freeze, "lib/ruby2js/converter/defs.rb".freeze, "lib/ruby2js/converter/dstr.rb".freeze, "lib/ruby2js/converter/for.rb".freeze, "lib/ruby2js/converter/hash.rb".freeze, "lib/ruby2js/converter/if.rb".freeze, "lib/ruby2js/converter/in.rb".freeze, "lib/ruby2js/converter/ivar.rb".freeze, "lib/ruby2js/converter/ivasgn.rb".freeze, "lib/ruby2js/converter/kwbegin.rb".freeze, "lib/ruby2js/converter/literal.rb".freeze, "lib/ruby2js/converter/logical.rb".freeze, "lib/ruby2js/converter/masgn.rb".freeze, "lib/ruby2js/converter/module.rb".freeze, "lib/ruby2js/converter/next.rb".freeze, "lib/ruby2js/converter/nil.rb".freeze, "lib/ruby2js/converter/nthref.rb".freeze, "lib/ruby2js/converter/opasgn.rb".freeze, "lib/ruby2js/converter/prototype.rb".freeze, "lib/ruby2js/converter/regexp.rb".freeze, "lib/ruby2js/converter/return.rb".freeze, "lib/ruby2js/converter/self.rb".freeze, "lib/ruby2js/converter/send.rb".freeze, "lib/ruby2js/converter/super.rb".freeze, "lib/ruby2js/converter/sym.rb".freeze, "lib/ruby2js/converter/undef.rb".freeze, "lib/ruby2js/converter/until.rb".freeze, "lib/ruby2js/converter/untilpost.rb".freeze, "lib/ruby2js/converter/var.rb".freeze, "lib/ruby2js/converter/vasgn.rb".freeze, "lib/ruby2js/converter/while.rb".freeze, "lib/ruby2js/converter/whilepost.rb".freeze, "lib/ruby2js/converter/xstr.rb".freeze, "lib/ruby2js/execjs.rb".freeze, "lib/ruby2js/filter".freeze, "lib/ruby2js/filter/angular-resource.rb".freeze, "lib/ruby2js/filter/angular-route.rb".freeze, "lib/ruby2js/filter/angularrb.rb".freeze, "lib/ruby2js/filter/camelCase.rb".freeze, "lib/ruby2js/filter/functions.rb".freeze, "lib/ruby2js/filter/jquery.rb".freeze, "lib/ruby2js/filter/minitest-jasmine.rb".freeze, "lib/ruby2js/filter/react.rb".freeze, "lib/ruby2js/filter/require.rb".freeze, "lib/ruby2js/filter/return.rb".freeze, "lib/ruby2js/filter/rubyjs.rb".freeze, "lib/ruby2js/filter/strict.rb".freeze, "lib/ruby2js/filter/underscore.rb".freeze, "lib/ruby2js/rails.rb".freeze, "lib/ruby2js/serializer.rb".freeze, "lib/ruby2js/sinatra.rb".freeze, "lib/ruby2js/version.rb".freeze, "ruby2js.gemspec".freeze]
14
+ s.files = ["README.md".freeze, "lib/ruby2js".freeze, "lib/ruby2js.rb".freeze, "lib/ruby2js/cgi.rb".freeze, "lib/ruby2js/converter".freeze, "lib/ruby2js/converter.rb".freeze, "lib/ruby2js/converter/arg.rb".freeze, "lib/ruby2js/converter/args.rb".freeze, "lib/ruby2js/converter/array.rb".freeze, "lib/ruby2js/converter/begin.rb".freeze, "lib/ruby2js/converter/block.rb".freeze, "lib/ruby2js/converter/blockpass.rb".freeze, "lib/ruby2js/converter/boolean.rb".freeze, "lib/ruby2js/converter/break.rb".freeze, "lib/ruby2js/converter/case.rb".freeze, "lib/ruby2js/converter/casgn.rb".freeze, "lib/ruby2js/converter/class.rb".freeze, "lib/ruby2js/converter/const.rb".freeze, "lib/ruby2js/converter/cvar.rb".freeze, "lib/ruby2js/converter/cvasgn.rb".freeze, "lib/ruby2js/converter/def.rb".freeze, "lib/ruby2js/converter/defined.rb".freeze, "lib/ruby2js/converter/defs.rb".freeze, "lib/ruby2js/converter/dstr.rb".freeze, "lib/ruby2js/converter/for.rb".freeze, "lib/ruby2js/converter/hash.rb".freeze, "lib/ruby2js/converter/if.rb".freeze, "lib/ruby2js/converter/in.rb".freeze, "lib/ruby2js/converter/ivar.rb".freeze, "lib/ruby2js/converter/ivasgn.rb".freeze, "lib/ruby2js/converter/kwbegin.rb".freeze, "lib/ruby2js/converter/literal.rb".freeze, "lib/ruby2js/converter/logical.rb".freeze, "lib/ruby2js/converter/masgn.rb".freeze, "lib/ruby2js/converter/module.rb".freeze, "lib/ruby2js/converter/next.rb".freeze, "lib/ruby2js/converter/nil.rb".freeze, "lib/ruby2js/converter/nthref.rb".freeze, "lib/ruby2js/converter/opasgn.rb".freeze, "lib/ruby2js/converter/prototype.rb".freeze, "lib/ruby2js/converter/regexp.rb".freeze, "lib/ruby2js/converter/return.rb".freeze, "lib/ruby2js/converter/self.rb".freeze, "lib/ruby2js/converter/send.rb".freeze, "lib/ruby2js/converter/super.rb".freeze, "lib/ruby2js/converter/sym.rb".freeze, "lib/ruby2js/converter/undef.rb".freeze, "lib/ruby2js/converter/until.rb".freeze, "lib/ruby2js/converter/untilpost.rb".freeze, "lib/ruby2js/converter/var.rb".freeze, "lib/ruby2js/converter/vasgn.rb".freeze, "lib/ruby2js/converter/while.rb".freeze, "lib/ruby2js/converter/whilepost.rb".freeze, "lib/ruby2js/converter/xstr.rb".freeze, "lib/ruby2js/execjs.rb".freeze, "lib/ruby2js/filter".freeze, "lib/ruby2js/filter/angular-resource.rb".freeze, "lib/ruby2js/filter/angular-route.rb".freeze, "lib/ruby2js/filter/angularrb.rb".freeze, "lib/ruby2js/filter/camelCase.rb".freeze, "lib/ruby2js/filter/functions.rb".freeze, "lib/ruby2js/filter/jquery.rb".freeze, "lib/ruby2js/filter/minitest-jasmine.rb".freeze, "lib/ruby2js/filter/react.rb".freeze, "lib/ruby2js/filter/require.rb".freeze, "lib/ruby2js/filter/return.rb".freeze, "lib/ruby2js/filter/rubyjs.rb".freeze, "lib/ruby2js/filter/strict.rb".freeze, "lib/ruby2js/filter/underscore.rb".freeze, "lib/ruby2js/filter/vue.rb".freeze, "lib/ruby2js/rails.rb".freeze, "lib/ruby2js/serializer.rb".freeze, "lib/ruby2js/sinatra.rb".freeze, "lib/ruby2js/version.rb".freeze, "ruby2js.gemspec".freeze]
15
15
  s.homepage = "http://github.com/rubys/ruby2js".freeze
16
16
  s.licenses = ["MIT".freeze]
17
17
  s.required_ruby_version = Gem::Requirement.new(">= 1.9.3".freeze)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby2js
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.18
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Ruby
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-29 00:00:00.000000000 Z
11
+ date: 2017-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -99,6 +99,7 @@ files:
99
99
  - lib/ruby2js/filter/rubyjs.rb
100
100
  - lib/ruby2js/filter/strict.rb
101
101
  - lib/ruby2js/filter/underscore.rb
102
+ - lib/ruby2js/filter/vue.rb
102
103
  - lib/ruby2js/rails.rb
103
104
  - lib/ruby2js/serializer.rb
104
105
  - lib/ruby2js/sinatra.rb