ruby2js 3.0.2 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +6 -0
- data/lib/ruby2js.rb +3 -1
- data/lib/ruby2js/converter.rb +2 -2
- data/lib/ruby2js/converter/case.rb +28 -2
- data/lib/ruby2js/converter/casgn.rb +6 -4
- data/lib/ruby2js/converter/class.rb +41 -13
- data/lib/ruby2js/converter/const.rb +11 -1
- data/lib/ruby2js/converter/def.rb +2 -2
- data/lib/ruby2js/converter/send.rb +14 -4
- data/lib/ruby2js/filter/functions.rb +19 -11
- data/lib/ruby2js/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a00761caa853bb0ecbd0d4531a47373e5bfde02c
|
4
|
+
data.tar.gz: 96f676c25a71ea845b8f914303bd5a550e3a564d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b41112e1bce8ff9a65c3dd2fa12f25e7b7fdd460c80f022e24486ede24848cca05895c30b602189c001472dc3e7be00c032e8ab6b2324dccb27d71089beafdb6
|
7
|
+
data.tar.gz: 8656d7be7bc9a581216096b122fd8b887943bb02b9302706bfa0d047e12f0fadc20e07adbf3e17ce837492fae120bd0f9ca274bfad7dce9392e3627f687f102b
|
data/README.md
CHANGED
@@ -45,6 +45,12 @@ mapped to
|
|
45
45
|
[Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2FdefineProperty),
|
46
46
|
so avoid these if you wish to target users running IE8 or lower.
|
47
47
|
|
48
|
+
While both Ruby and JavaScript have open classes, Ruby unifies the syntax for
|
49
|
+
defining and extending an existing class, whereas JavaScript does not. This
|
50
|
+
means that Ruby2JS needs to be told when a class is being extended, which is
|
51
|
+
done by prepending the `class` keyword with two plus signs, thus:
|
52
|
+
`++class C; ...; end`.
|
53
|
+
|
48
54
|
Filters may be provided to add Ruby-specific or framework specific
|
49
55
|
behavior. Filters are essentially macro facilities that operate on
|
50
56
|
an AST representation of the code.
|
data/lib/ruby2js.rb
CHANGED
@@ -84,14 +84,16 @@ module Ruby2JS
|
|
84
84
|
@ast = ast
|
85
85
|
end
|
86
86
|
|
87
|
-
# handle all of the 'invented' ast types
|
87
|
+
# handle all of the 'invented/synthetic' ast types
|
88
88
|
def on_async(node); on_def(node); end
|
89
89
|
def on_asyncs(node); on_defs(node); end
|
90
90
|
def on_attr(node); on_send(node); end
|
91
91
|
def on_autoreturn(node); on_return(node); end
|
92
92
|
def on_await(node); on_send(node); end
|
93
93
|
def on_call(node); on_send(node); end
|
94
|
+
def on_class_extend(node); on_send(node); end
|
94
95
|
def on_constructor(node); on_def(node); end
|
96
|
+
def on_defm(node); on_defs(node); end
|
95
97
|
def on_defp(node); on_defs(node); end
|
96
98
|
def on_for_of(node); on_for(node); end
|
97
99
|
def on_in?(node); on_send(node); end
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -19,7 +19,7 @@ module Ruby2JS
|
|
19
19
|
:=== => :'!=='
|
20
20
|
}
|
21
21
|
|
22
|
-
GROUP_OPERATORS = [:begin, :dstr, :dsym, :and, :or]
|
22
|
+
GROUP_OPERATORS = [:begin, :dstr, :dsym, :and, :or, :casgn]
|
23
23
|
|
24
24
|
VASGN = [:cvasgn, :ivasgn, :gvasgn, :lvasgn]
|
25
25
|
|
@@ -182,7 +182,7 @@ module Ruby2JS
|
|
182
182
|
walk = proc do |ast|
|
183
183
|
if ast.loc and ast.loc.expression
|
184
184
|
filename = ast.loc.expression.source_buffer.name
|
185
|
-
if filename
|
185
|
+
if filename and not filename.empty?
|
186
186
|
filename = filename.dup.untaint
|
187
187
|
@timestamps[filename] ||= File.mtime(filename)
|
188
188
|
end
|
@@ -13,13 +13,39 @@ module Ruby2JS
|
|
13
13
|
scope, @scope = @scope, false
|
14
14
|
mark = output_location
|
15
15
|
|
16
|
-
|
16
|
+
has_range = whens.any? do |node|
|
17
|
+
node.children.any? {|child| [:irange, :erange].include? child.type}
|
18
|
+
end
|
19
|
+
|
20
|
+
if has_range
|
21
|
+
# https://stackoverflow.com/questions/5619832/switch-on-ranges-of-integers-in-javascript
|
22
|
+
puts 'switch (true) {'
|
23
|
+
else
|
24
|
+
put 'switch ('; parse expr; puts ') {'
|
25
|
+
end
|
17
26
|
|
18
27
|
whens.each_with_index do |node, index|
|
19
28
|
puts '' unless index == 0
|
20
29
|
|
21
30
|
*values, code = node.children
|
22
|
-
|
31
|
+
|
32
|
+
values.each do |value|
|
33
|
+
put 'case ';
|
34
|
+
if has_range
|
35
|
+
if value.type == :irange
|
36
|
+
parse expr; put ' >= '; parse value.children.first; put " && "
|
37
|
+
parse expr; put ' <= '; parse value.children.last; put ":#@ws"
|
38
|
+
elsif value.type == :erange
|
39
|
+
parse expr; put ' >= '; parse value.children.first; put " && "
|
40
|
+
parse expr; put ' < '; parse value.children.last; put ":#@ws"
|
41
|
+
else
|
42
|
+
parse expr; put ' == '; parse value; put ":#@ws"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
parse value; put ":#@ws"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
23
49
|
parse code, :statement
|
24
50
|
put "#{@sep}break#@sep" if other or index < whens.length-1
|
25
51
|
end
|
@@ -8,10 +8,12 @@ module Ruby2JS
|
|
8
8
|
multi_assign_declarations if @state == :statement
|
9
9
|
|
10
10
|
begin
|
11
|
-
if
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
if @state == :statement
|
12
|
+
if es2015
|
13
|
+
put "const "
|
14
|
+
else
|
15
|
+
put "var "
|
16
|
+
end
|
15
17
|
end
|
16
18
|
|
17
19
|
cbase ||= @rbstack.map {|rb| rb[var]}.compact.last
|
@@ -8,16 +8,24 @@ module Ruby2JS
|
|
8
8
|
|
9
9
|
# NOTE: :prop and :method macros are defined at the bottom of this file
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
return
|
15
|
-
end
|
11
|
+
# NOTE: class_extend is not generated by the parser, but instead produced
|
12
|
+
# when ++class is encountered; it signals that this construct is
|
13
|
+
# meant to extend an already existing JavaScrpt class.
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
handle :class, :class_extend do |name, inheritance, *body|
|
16
|
+
if @ast.type == :class_extend
|
17
|
+
init = nil
|
19
18
|
else
|
20
|
-
|
19
|
+
if es2015 and @ast.type != :class_extend
|
20
|
+
parse @ast.updated(:class2)
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
if inheritance
|
25
|
+
init = s(:def, :initialize, s(:args), s(:super))
|
26
|
+
else
|
27
|
+
init = s(:def, :initialize, s(:args), nil)
|
28
|
+
end
|
21
29
|
end
|
22
30
|
|
23
31
|
body.compact!
|
@@ -53,7 +61,7 @@ module Ruby2JS
|
|
53
61
|
# method: add to prototype
|
54
62
|
s(:method, s(:attr, name, :prototype),
|
55
63
|
:"#{m.children[0].to_s.chomp('!')}=",
|
56
|
-
s(:
|
64
|
+
s(:defm, nil, *m.children[1..-1]))
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
@@ -182,7 +190,10 @@ module Ruby2JS
|
|
182
190
|
end
|
183
191
|
|
184
192
|
# collapse sequence to a single assignment
|
185
|
-
if
|
193
|
+
if
|
194
|
+
@ast.type == :class and
|
195
|
+
(methods > 1 or (methods == 1 and body[start].type == :prop))
|
196
|
+
then
|
186
197
|
pairs = body[start...start+methods].map do |node|
|
187
198
|
if node.type == :method
|
188
199
|
replacement = node.updated(:pair, [
|
@@ -209,9 +220,26 @@ module Ruby2JS
|
|
209
220
|
end
|
210
221
|
|
211
222
|
# prepend constructor
|
212
|
-
|
213
|
-
|
214
|
-
|
223
|
+
if init
|
224
|
+
constructor = init.updated(:constructor, [name, *init.children[1..-1]])
|
225
|
+
@comments[constructor] = @comments[init] unless @comments[init].empty?
|
226
|
+
|
227
|
+
if @ast.type == :class_extend
|
228
|
+
if es2015
|
229
|
+
constructor = s(:masgn, s(:mlhs,
|
230
|
+
s(:attr, s(:casgn, *name.children, constructor), :prototype)),
|
231
|
+
s(:array, s(:attr, name, :prototype)))
|
232
|
+
else
|
233
|
+
constructor = s(:send, s(:block, s(:send, nil, :proc),
|
234
|
+
s(:args, s(:shadowarg, :$_)), s(:begin,
|
235
|
+
s(:gvasgn, :$_, s(:attr, name, :prototype)),
|
236
|
+
s(:send, s(:casgn, *name.children, constructor),
|
237
|
+
:prototype=, s(:gvar, :$_)))), :[])
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
body.unshift constructor
|
242
|
+
end
|
215
243
|
|
216
244
|
begin
|
217
245
|
# save class name
|
@@ -7,7 +7,17 @@ module Ruby2JS
|
|
7
7
|
# resolve anonymous receivers against rbstack
|
8
8
|
receiver ||= @rbstack.map {|rb| rb[name]}.compact.last
|
9
9
|
|
10
|
-
|
10
|
+
if receiver
|
11
|
+
if Parser::AST::Node === receiver and receiver.type == :cbase
|
12
|
+
put 'Function("return this")().'
|
13
|
+
else
|
14
|
+
parse receiver
|
15
|
+
put '.'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
put name
|
11
21
|
end
|
12
22
|
end
|
13
23
|
end
|
@@ -6,7 +6,7 @@ module Ruby2JS
|
|
6
6
|
# (arg :x)
|
7
7
|
# (...)
|
8
8
|
|
9
|
-
handle :def, :async do |name, args, body=nil|
|
9
|
+
handle :def, :defm, :async do |name, args, body=nil|
|
10
10
|
body ||= s(:begin)
|
11
11
|
if name =~ /[!?]$/
|
12
12
|
raise NotImplementedError, "invalid method name #{ name }"
|
@@ -91,7 +91,7 @@ module Ruby2JS
|
|
91
91
|
put 'async ' if @ast.type == :async
|
92
92
|
|
93
93
|
# es2015 fat arrow support
|
94
|
-
if not name and es2015 and @state != :method
|
94
|
+
if not name and es2015 and @state != :method and @ast.type != :defm
|
95
95
|
put '('; parse args; put ') => '
|
96
96
|
|
97
97
|
expr = body
|
@@ -131,7 +131,16 @@ module Ruby2JS
|
|
131
131
|
put ')'
|
132
132
|
|
133
133
|
elsif [:-@, :+@, :~, '~'].include? method
|
134
|
-
|
134
|
+
if
|
135
|
+
receiver.type == :send and
|
136
|
+
receiver.children[1] == :+@ and
|
137
|
+
Parser::AST::Node === receiver.children[0] and
|
138
|
+
receiver.children[0].type == :class
|
139
|
+
then
|
140
|
+
parse receiver.children[0].updated(:class_extend)
|
141
|
+
else
|
142
|
+
put method.to_s[0]; parse receiver
|
143
|
+
end
|
135
144
|
|
136
145
|
elsif method == :=~
|
137
146
|
parse args.first; put '.test('; parse receiver; put ')'
|
@@ -143,7 +152,8 @@ module Ruby2JS
|
|
143
152
|
parse receiver; put '.push('; parse args.first; put ')'
|
144
153
|
|
145
154
|
elsif method == :<=>
|
146
|
-
|
155
|
+
parse receiver; put ' < '; parse args.first; put ' ? -1 : '
|
156
|
+
parse receiver; put ' > '; parse args.first; put ' ? 1 : 0'
|
147
157
|
|
148
158
|
elsif OPERATORS.flatten.include?(method) and not LOGICAL.include?(method)
|
149
159
|
(group_receiver ? group(receiver) : parse(receiver))
|
@@ -153,7 +163,7 @@ module Ruby2JS
|
|
153
163
|
elsif method =~ /=$/
|
154
164
|
multi_assign_declarations if @state == :statement
|
155
165
|
|
156
|
-
|
166
|
+
(group_receiver ? group(receiver) : parse(receiver))
|
157
167
|
put "#{ '.' if receiver }#{ method.to_s.sub(/=$/, ' =') } "
|
158
168
|
parse args.first, (@state == :method ? :method : :expression)
|
159
169
|
|
@@ -195,7 +205,7 @@ module Ruby2JS
|
|
195
205
|
end
|
196
206
|
elsif args.length == 1 and args.first.type == :send
|
197
207
|
# accommodation for JavaScript like new syntax w/argument list
|
198
|
-
parse s(:send, s(:const,
|
208
|
+
parse s(:send, s(:const, *args.first.children[0..1]), :new,
|
199
209
|
*args.first.children[2..-1]), @state
|
200
210
|
elsif args.length == 1 and args.first.type == :const
|
201
211
|
# accommodation for JavaScript like new syntax w/o argument list
|
@@ -112,18 +112,26 @@ module Ruby2JS
|
|
112
112
|
process S(:send, target, :==, s(:nil))
|
113
113
|
|
114
114
|
elsif [:start_with?, :end_with?].include? method and args.length == 1
|
115
|
-
if
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
if method == :start_with?
|
122
|
-
process S(:send, S(:send, target, :substring, s(:int, 0),
|
123
|
-
length), :==, *args)
|
115
|
+
if es2015
|
116
|
+
if method == :start_with?
|
117
|
+
process S(:send, target, :startsWith, *args)
|
118
|
+
else
|
119
|
+
process S(:send, target, :endsWith, *args)
|
120
|
+
end
|
124
121
|
else
|
125
|
-
|
126
|
-
|
122
|
+
if args.first.type == :str
|
123
|
+
length = S(:int, args.first.children.first.length)
|
124
|
+
else
|
125
|
+
length = S(:attr, *args, :length)
|
126
|
+
end
|
127
|
+
|
128
|
+
if method == :start_with?
|
129
|
+
process S(:send, S(:send, target, :substring, s(:int, 0),
|
130
|
+
length), :==, *args)
|
131
|
+
else
|
132
|
+
process S(:send, S(:send, target, :slice,
|
133
|
+
S(:send, length, :-@)), :==, *args)
|
134
|
+
end
|
127
135
|
end
|
128
136
|
|
129
137
|
elsif method == :clear and args.length == 0 and node.is_method?
|
data/lib/ruby2js/version.rb
CHANGED
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: 3.0.
|
4
|
+
version: 3.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Ruby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -130,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
130
|
version: '0'
|
131
131
|
requirements: []
|
132
132
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.
|
133
|
+
rubygems_version: 2.6.11
|
134
134
|
signing_key:
|
135
135
|
specification_version: 4
|
136
136
|
summary: Minimal yet extensible Ruby to JavaScript conversion.
|