ruby2js 2.0.18 → 2.1.0

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.
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