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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: '009edffb834a3c8c298d4ad601160d30c4781891a4fe7b229e6dbc6f4284569e'
4
- data.tar.gz: 186d6e6ec33a0fee107623c3ed7994e9dea0741cf454bb79005acbb6be7f6429
2
+ SHA1:
3
+ metadata.gz: a00761caa853bb0ecbd0d4531a47373e5bfde02c
4
+ data.tar.gz: 96f676c25a71ea845b8f914303bd5a550e3a564d
5
5
  SHA512:
6
- metadata.gz: de2efb3d8d13a282af0401ce3a6216423564933483d3be4ed160eb1ef2bbf3092fdae6c9325d09298d6c86012de936c764178a0767a08b66b49b6d6d53bd9daa
7
- data.tar.gz: 3558c528e771c98fd50ece66410dd12d3a33c57af85e89e47a1c04f743f4a531cb971dbdf197291f8e6b1530d1895ea9c40aaf8814d64d094eb2f397092504a2
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
@@ -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
- put 'switch ('; parse expr; puts ') {'
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
- values.each {|value| put 'case '; parse value; put ":#@ws"}
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 es2015
12
- put "const "
13
- else
14
- put "var "
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
- handle :class do |name, inheritance, *body|
12
- if es2015
13
- parse @ast.updated(:class2)
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
- if inheritance
18
- init = s(:def, :initialize, s(:args), s(:super))
15
+ handle :class, :class_extend do |name, inheritance, *body|
16
+ if @ast.type == :class_extend
17
+ init = nil
19
18
  else
20
- init = s(:def, :initialize, s(:args), nil)
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(:def, nil, *m.children[1..-1]))
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 methods > 1 or (methods == 1 and body[start].type == :prop)
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
- constructor = init.updated(:constructor, [name, *init.children[1..-1]])
213
- @comments[constructor] = @comments[init] unless @comments[init].empty?
214
- body.unshift constructor
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
- parse receiver; put '.' if receiver; put name
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
- put method.to_s[0]; parse receiver
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
- raise NotImplementedError, "use of <=>"
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
- parse receiver
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, nil, args.first.children[1]), :new,
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 args.first.type == :str
116
- length = S(:int, args.first.children.first.length)
117
- else
118
- length = S(:attr, *args, :length)
119
- end
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
- process S(:send, S(:send, target, :slice,
126
- S(:send, length, :-@)), :==, *args)
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?
@@ -2,7 +2,7 @@ module Ruby2JS
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 0
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
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.2
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-01-24 00:00:00.000000000 Z
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.7.4
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.