ruby2js 3.0.2 → 3.0.3
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 +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.
|