ruby2js 1.3.0 → 1.4.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 +8 -8
- data/README.md +13 -1
- data/lib/ruby2js/converter.rb +10 -0
- data/lib/ruby2js/converter/class.rb +88 -11
- data/lib/ruby2js/converter/defined.rb +1 -1
- data/lib/ruby2js/converter/hash.rb +18 -3
- data/lib/ruby2js/converter/if.rb +3 -17
- data/lib/ruby2js/converter/logical.rb +31 -15
- data/lib/ruby2js/converter/return.rb +21 -0
- data/lib/ruby2js/converter/send.rb +2 -7
- data/lib/ruby2js/filter/angularrb.rb +171 -6
- data/lib/ruby2js/filter/functions.rb +29 -4
- data/lib/ruby2js/filter/return.rb +7 -34
- data/lib/ruby2js/version.rb +1 -1
- data/ruby2js.gemspec +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YTU0NmY4ZDc4NDJiMGVjZGNiMmJjOWJhZmZkYzk3ODUwNjQ4YjVjMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzRlMTE2ZWY5NTRjYjQ1ODBhMDUzMzZjMzFkNjY3M2IxNDVjY2VkNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZDk5MGVjOTdmNWRiNWY1ODhmMTMxMjdhOWMwNWEzNTUxYThiMGVlYWRjOTY4
|
10
|
+
YjU4MDM2OWI1ZmFhMjZhOTM3NzIwYjgyZWI4ZjA5ODE1MmFhMWU5YmZlYmYw
|
11
|
+
OTcyMmNhYzE0NDMyZDNlMTAxODdjYzEyNjBjOTY0ZmI0OGNmMzA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NDhmNTY1OGNhNWVmYmRmMGVkZTMwMTg4ZTMzMGY0YjE0YjFiY2UwNmYzYjNi
|
14
|
+
YTc4ZmViYWFjZWFjOGIyY2FhOThjNWM1M2E1M2MzZDZmYjI3NDQ5YjE5MjU5
|
15
|
+
MjA0ZTk3NzkzYjA2ZTIzNGY2MWU4NzNmZjE3NjFmM2FmYzM3N2U=
|
data/README.md
CHANGED
@@ -13,6 +13,14 @@ calls IF there are either one or more arguments passed OR parenthesis are
|
|
13
13
|
used, otherwise Ruby method calls become JavaScript property accesses.
|
14
14
|
By default, methods, lambdas, and procs return `undefined`.
|
15
15
|
|
16
|
+
Ruby attribute accessors, as well as getter and setter method definitions, are
|
17
|
+
mapped to
|
18
|
+
[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),
|
19
|
+
so avoid these if you wish to target users running IE8 or lower. Instance
|
20
|
+
methods defined with no arguments are presumed to be defining a property
|
21
|
+
accessor; if you want a method with no arguments append a `!` to the method
|
22
|
+
name.
|
23
|
+
|
16
24
|
Filters may be provided to add Ruby-specific or framework specific
|
17
25
|
behavior. Filters are essentially macro facilities that operate on
|
18
26
|
an AST representation of the code.
|
@@ -127,10 +135,11 @@ the script.
|
|
127
135
|
* `.to_a` becomes `to_Array`
|
128
136
|
* `.to_i` becomes `parseInt`
|
129
137
|
* `.to_f` becomes `parseFloat`
|
130
|
-
* `.sub` becomes `replace`
|
131
138
|
* `.ord` becomes `charCodeAt(0)`
|
132
139
|
* `.chr` becomes `fromCharCode`
|
140
|
+
* `.sub` becomes `replace`
|
133
141
|
* `.gsub` becomes `replace //g`
|
142
|
+
* `x.sub!` and `x.gsub!` become equivalent `x = x.replace` statements
|
134
143
|
* `.first` becomes `[0]`
|
135
144
|
* `.last` becomes `[*.length-1]`
|
136
145
|
* `[-n]` becomes `[*.length-n]` for literal values of `n`
|
@@ -148,6 +157,9 @@ the script.
|
|
148
157
|
* `.each_with_index` becomes `forEach`
|
149
158
|
* `setInterval` and `setTimeout` allow block to be treated as the
|
150
159
|
first parameter on the call
|
160
|
+
* for the following methods, if the block consists entirely of a simple
|
161
|
+
expression (or ends with one), a `return` is added prior to the
|
162
|
+
expression: `sub`, `gsub`, `any?`, `all?`, `map`.
|
151
163
|
|
152
164
|
* [jquery](https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/jquery.rb)
|
153
165
|
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -6,6 +6,16 @@ module Ruby2JS
|
|
6
6
|
OPERATORS = [:[], :[]=], [:not, :!], [:*, :/, :%], [:+, :-], [:>>, :<<],
|
7
7
|
[:<=, :<, :>, :>=], [:==, :!=, :===, :"!=="], [:and, :or]
|
8
8
|
|
9
|
+
INVERT_OP = {
|
10
|
+
:< => :>=,
|
11
|
+
:<= => :>,
|
12
|
+
:== => :!=,
|
13
|
+
:!= => :==,
|
14
|
+
:> => :<=,
|
15
|
+
:>= => :<,
|
16
|
+
:=== => :'!=='
|
17
|
+
}
|
18
|
+
|
9
19
|
attr_accessor :binding, :ivars
|
10
20
|
|
11
21
|
def initialize( ast, vars = {} )
|
@@ -6,6 +6,8 @@ module Ruby2JS
|
|
6
6
|
# (const nil :B)
|
7
7
|
# (...)
|
8
8
|
|
9
|
+
# NOTE: macro :prop is defined at the bottom of this file
|
10
|
+
|
9
11
|
handle :class do |name, inheritance, *body|
|
10
12
|
init = s(:def, :initialize, s(:args))
|
11
13
|
body.compact!
|
@@ -20,9 +22,22 @@ module Ruby2JS
|
|
20
22
|
# constructor: remove from body and overwrite init function
|
21
23
|
init = m
|
22
24
|
nil
|
25
|
+
elsif m.children.first =~ /=/
|
26
|
+
# property setter
|
27
|
+
sym = :"#{m.children.first.to_s[0..-2]}"
|
28
|
+
s(:prop, s(:attr, name, :prototype), sym,
|
29
|
+
enumerable: s(:true), configurable: s(:true),
|
30
|
+
set: s(:block, s(:send, nil, :proc), *m.children[1..-1]))
|
31
|
+
elsif m.children[1].children.length == 0 and m.children.first !~ /!/
|
32
|
+
# property getter
|
33
|
+
s(:prop, s(:attr, name, :prototype), m.children.first,
|
34
|
+
enumerable: s(:true), configurable: s(:true),
|
35
|
+
get: s(:block, s(:send, nil, :proc), m.children[1],
|
36
|
+
s(:autoreturn, *m.children[2..-1])))
|
23
37
|
else
|
24
38
|
# method: add to prototype
|
25
|
-
s(:send, s(:attr, name, :prototype),
|
39
|
+
s(:send, s(:attr, name, :prototype),
|
40
|
+
:"#{m.children[0].to_s.chomp('!')}=",
|
26
41
|
s(:block, s(:send, nil, :proc), *m.children[1..-1]))
|
27
42
|
end
|
28
43
|
elsif m.type == :defs and m.children.first == s(:self)
|
@@ -30,8 +45,38 @@ module Ruby2JS
|
|
30
45
|
s(:prototype, s(:send, name, "#{m.children[1]}=",
|
31
46
|
s(:block, s(:send, nil, :proc), *m.children[2..-1])))
|
32
47
|
elsif m.type == :send and m.children.first == nil
|
33
|
-
|
34
|
-
|
48
|
+
if m.children[1] == :attr_accessor
|
49
|
+
m.children[2..-1].map do |sym|
|
50
|
+
var = sym.children.first
|
51
|
+
s(:prop, s(:attr, name, :prototype), var,
|
52
|
+
enumerable: s(:true), configurable: s(:true),
|
53
|
+
get: s(:block, s(:send, nil, :proc), s(:args),
|
54
|
+
s(:return, s(:ivar, :"@#{var}"))),
|
55
|
+
set: s(:block, s(:send, nil, :proc), s(:args, s(:arg, var)),
|
56
|
+
s(:ivasgn, :"@#{var}", s(:lvar, var))))
|
57
|
+
end
|
58
|
+
elsif m.children[1] == :attr_reader
|
59
|
+
m.children[2..-1].map do |sym|
|
60
|
+
var = sym.children.first
|
61
|
+
s(:prop, s(:attr, name, :prototype), var,
|
62
|
+
get: s(:block, s(:send, nil, :proc), s(:args),
|
63
|
+
s(:return, s(:ivar, :"@#{var}"))),
|
64
|
+
enumerable: s(:true),
|
65
|
+
configurable: s(:true))
|
66
|
+
end
|
67
|
+
elsif m.children[1] == :attr_writer
|
68
|
+
m.children[2..-1].map do |sym|
|
69
|
+
var = sym.children.first
|
70
|
+
s(:prop, s(:attr, name, :prototype), var,
|
71
|
+
set: s(:block, s(:send, nil, :proc), s(:args, s(:arg, var)),
|
72
|
+
s(:ivasgn, :"@#{var}", s(:lvar, var))),
|
73
|
+
enumerable: s(:true),
|
74
|
+
configurable: s(:true))
|
75
|
+
end
|
76
|
+
else
|
77
|
+
# class method call
|
78
|
+
s(:send, name, *m.children[1..-1])
|
79
|
+
end
|
35
80
|
elsif m.type == :lvasgn
|
36
81
|
# class variable
|
37
82
|
s(:send, name, "#{m.children[0]}=", *m.children[1..-1])
|
@@ -49,24 +94,49 @@ module Ruby2JS
|
|
49
94
|
end
|
50
95
|
end
|
51
96
|
|
97
|
+
body.flatten!
|
98
|
+
|
99
|
+
# merge nearby property definitions
|
100
|
+
for i in 0...body.length-1
|
101
|
+
next unless body[i] and body[i].type == :prop
|
102
|
+
for j in i+1...body.length
|
103
|
+
break unless body[j] and body[j].type == :prop
|
104
|
+
if body[i].children[0..1] == body[j].children[0..1]
|
105
|
+
merge = body[i].children[2].merge(body[j].children[2])
|
106
|
+
body[j] = s(:prop, *body[j].children[0..1], merge)
|
107
|
+
body[i] = nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
52
112
|
if inheritance
|
53
113
|
body.unshift s(:send, name, :prototype=, s(:send, inheritance, :new))
|
54
114
|
else
|
115
|
+
body.compact!
|
116
|
+
|
55
117
|
# look for a sequence of methods
|
56
118
|
methods = 0
|
57
|
-
body.
|
58
|
-
break unless node
|
59
|
-
|
60
|
-
|
61
|
-
|
119
|
+
body.each do |node|
|
120
|
+
break unless node
|
121
|
+
if node.type == :send
|
122
|
+
break unless node.children[0] and node.children[0].type == :attr
|
123
|
+
break unless node.children[0].children[0..1] == [name, :prototype]
|
124
|
+
break unless node.children[1] =~ /=$/
|
125
|
+
elsif node.type != :prop
|
126
|
+
break
|
127
|
+
end
|
62
128
|
methods += 1
|
63
129
|
end
|
64
130
|
|
65
131
|
# collapse sequence of methods to a single assignment
|
66
|
-
if methods > 1
|
67
|
-
body.compact!
|
132
|
+
if methods > 1 or (methods == 1 and body[0].type == :prop)
|
68
133
|
pairs = body[0...methods].map do |node|
|
69
|
-
|
134
|
+
if node.type == :send
|
135
|
+
s(:pair, s(:str, node.children[1].to_s.chomp('=')),
|
136
|
+
node.children[2])
|
137
|
+
else
|
138
|
+
s(:pair, s(:prop, node.children[1]), node.children[2])
|
139
|
+
end
|
70
140
|
end
|
71
141
|
body.shift(methods)
|
72
142
|
body.unshift s(:send, name, :prototype=, s(:hash, *pairs))
|
@@ -87,5 +157,12 @@ module Ruby2JS
|
|
87
157
|
@class_name = class_name
|
88
158
|
end
|
89
159
|
end
|
160
|
+
|
161
|
+
# macro that expands into Object.defineProperty(obj, prop, descriptor)
|
162
|
+
handle :prop do |obj, prop, descriptor|
|
163
|
+
parse s(:send, s(:const, nil, :Object), :defineProperty,
|
164
|
+
obj, s(:sym, prop), s(:hash,
|
165
|
+
*descriptor.map { |key, value| s(:pair, s(:sym, key), value) }))
|
166
|
+
end
|
90
167
|
end
|
91
168
|
end
|
@@ -8,7 +8,7 @@ module Ruby2JS
|
|
8
8
|
# NOTE: undefined is not produced directly by Parser
|
9
9
|
|
10
10
|
handle :defined?, :undefined? do |var|
|
11
|
-
op = (@ast.type == :defined? ? "!==" :
|
11
|
+
op = (@ast.type == :defined? ? :"!==" : :===)
|
12
12
|
"typeof #{ parse var } #{ op } 'undefined'"
|
13
13
|
end
|
14
14
|
end
|
@@ -9,11 +9,26 @@ module Ruby2JS
|
|
9
9
|
handle :hash do |*pairs|
|
10
10
|
pairs.map! do |node|
|
11
11
|
left, right = node.children
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
if left.type == :prop
|
13
|
+
result = []
|
14
|
+
if right[:get]
|
15
|
+
result << "get #{left.children[0]}#{
|
16
|
+
parse(right[:get]).sub(/^function/,'')}"
|
17
|
+
end
|
18
|
+
if right[:set]
|
19
|
+
result << "set #{left.children[0]}#{
|
20
|
+
parse(right[:set]).sub(/^function/,'')}"
|
21
|
+
end
|
22
|
+
result
|
23
|
+
else
|
24
|
+
key = parse left
|
25
|
+
key = $1 if key =~ /\A"([a-zA-Z_$][a-zA-Z_$0-9]*)"\Z/
|
26
|
+
"#{key}: #{parse right}"
|
27
|
+
end
|
15
28
|
end
|
16
29
|
|
30
|
+
pairs.flatten!
|
31
|
+
|
17
32
|
if pairs.map {|item| item.length+2}.reduce(&:+).to_i < @width-10
|
18
33
|
"{#{ pairs.join(', ') }}"
|
19
34
|
else
|
data/lib/ruby2js/converter/if.rb
CHANGED
@@ -6,25 +6,10 @@ module Ruby2JS
|
|
6
6
|
# (...)
|
7
7
|
# (...))
|
8
8
|
|
9
|
-
INVERT_OP = {
|
10
|
-
:< => :>=,
|
11
|
-
:<= => :>,
|
12
|
-
:== => :!=,
|
13
|
-
:!= => :==,
|
14
|
-
:> => :<=,
|
15
|
-
:>= => :<
|
16
|
-
}
|
17
|
-
|
18
9
|
handle :if do |condition, then_block, else_block|
|
19
|
-
# return parse condition if
|
10
|
+
# return parse not condition if else_block and no then_block
|
20
11
|
if else_block and not then_block
|
21
|
-
if condition
|
22
|
-
return parse(s(:if, s(:send, condition.children[0],
|
23
|
-
INVERT_OP[condition.children[1]], condition.children[2]),
|
24
|
-
else_block,nil), @state)
|
25
|
-
else
|
26
|
-
return parse(s(:if, s(:send, condition, :!), else_block, nil), @state)
|
27
|
-
end
|
12
|
+
return parse(s(:if, s(:not, condition), else_block, nil), @state)
|
28
13
|
end
|
29
14
|
|
30
15
|
then_block ||= s(:nil)
|
@@ -45,6 +30,7 @@ module Ruby2JS
|
|
45
30
|
|
46
31
|
output
|
47
32
|
else
|
33
|
+
else_block ||= s(:nil)
|
48
34
|
"(#{ parse condition } ? #{ parse then_block } : #{ parse else_block })"
|
49
35
|
end
|
50
36
|
end
|
@@ -9,10 +9,10 @@ module Ruby2JS
|
|
9
9
|
# (...)
|
10
10
|
# (...))
|
11
11
|
|
12
|
-
#
|
12
|
+
# Note: not handled below
|
13
13
|
# (...))
|
14
14
|
|
15
|
-
handle :and, :or
|
15
|
+
handle :and, :or do |left, right|
|
16
16
|
type = @ast.type
|
17
17
|
op_index = operator_index type
|
18
18
|
|
@@ -22,21 +22,37 @@ module Ruby2JS
|
|
22
22
|
left = parse left
|
23
23
|
left = "(#{ left })" if lgroup
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
right = "(#{ right })" if rgroup
|
31
|
-
end
|
25
|
+
rgroup = LOGICAL.include?( right.type ) &&
|
26
|
+
op_index < operator_index( right.type )
|
27
|
+
rgroup = true if right.type == :begin
|
28
|
+
right = parse right
|
29
|
+
right = "(#{ right })" if rgroup
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
"#{ left } #{ type==:and ? '&&' : '||' } #{ right }"
|
32
|
+
end
|
33
|
+
|
34
|
+
# (not
|
35
|
+
# (...))
|
36
|
+
|
37
|
+
handle :not do |expr|
|
38
|
+
|
39
|
+
if expr.type == :send and INVERT_OP.include? expr.children[1]
|
40
|
+
parse(s(:send, expr.children[0], INVERT_OP[expr.children[1]],
|
41
|
+
expr.children[2]))
|
42
|
+
elsif expr.type == :defined?
|
43
|
+
parse s(:undefined?, *expr.children)
|
44
|
+
elsif expr.type == :or
|
45
|
+
parse s(:and, s(:not, expr.children[0]), s(:not, expr.children[1]))
|
46
|
+
elsif expr.type == :and
|
47
|
+
parse s(:or, s(:not, expr.children[0]), s(:not, expr.children[1]))
|
38
48
|
else
|
39
|
-
|
49
|
+
group = LOGICAL.include?( expr.type ) &&
|
50
|
+
operator_index( :not ) < operator_index( expr.type )
|
51
|
+
group = true if expr and expr.type == :begin
|
52
|
+
expr = parse expr
|
53
|
+
expr = "(#{ expr })" if group
|
54
|
+
|
55
|
+
"!#{ expr }"
|
40
56
|
end
|
41
57
|
end
|
42
58
|
end
|
@@ -11,5 +11,26 @@ module Ruby2JS
|
|
11
11
|
"return"
|
12
12
|
end
|
13
13
|
end
|
14
|
+
|
15
|
+
EXPRESSIONS = [ :array, :float, :hash, :int, :lvar, :nil, :send,
|
16
|
+
:str, :sym, :dstr, :dsym ]
|
17
|
+
|
18
|
+
handle :autoreturn do |*statements|
|
19
|
+
return if statements == [nil]
|
20
|
+
block = statements.dup
|
21
|
+
while block.length == 1 and block.first.type == :begin
|
22
|
+
block = block.first.children.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
if EXPRESSIONS.include? block.last.type
|
26
|
+
block.push s(:return, block.pop)
|
27
|
+
end
|
28
|
+
|
29
|
+
if block.length == 1
|
30
|
+
parse block.first, @state
|
31
|
+
else
|
32
|
+
parse s(:begin, *block), @state
|
33
|
+
end
|
34
|
+
end
|
14
35
|
end
|
15
36
|
end
|
@@ -56,12 +56,7 @@ module Ruby2JS
|
|
56
56
|
end
|
57
57
|
|
58
58
|
if method == :!
|
59
|
-
|
60
|
-
parse s(:undefined?, *receiver.children)
|
61
|
-
else
|
62
|
-
group_receiver ||= (receiver.type != :send && receiver.children.length > 1)
|
63
|
-
"!#{ group_receiver ? group(receiver) : parse(receiver) }"
|
64
|
-
end
|
59
|
+
parse s(:not, receiver)
|
65
60
|
|
66
61
|
elsif method == :[]
|
67
62
|
"#{ parse receiver }[#{ args.map {|arg| parse arg}.join(', ') }]"
|
@@ -140,7 +135,7 @@ module Ruby2JS
|
|
140
135
|
s(:send, s(:array, *args[0..-2]), :concat,
|
141
136
|
args[-1].children.first))
|
142
137
|
else
|
143
|
-
call = "#{ parse receiver }#{ '.' if receiver }#{ method }"
|
138
|
+
call = "#{ parse receiver }#{ '.' if receiver && method}#{ method }"
|
144
139
|
args = args.map {|a| parse a}
|
145
140
|
if args.any? {|arg| arg.to_s.include? "\n"}
|
146
141
|
"#{ call }(#{ args.join(', ') })"
|
@@ -53,6 +53,11 @@ module Ruby2JS
|
|
53
53
|
# ...
|
54
54
|
|
55
55
|
def on_module(node)
|
56
|
+
ngContext, @ngContext = @ngContext, :module
|
57
|
+
@ngModule = node.children
|
58
|
+
if @ngModule.last and @ngModule.last.type == :begin
|
59
|
+
@ngModule = @ngModule.last.children
|
60
|
+
end
|
56
61
|
module_name = node.children[0]
|
57
62
|
parent_name = module_name.children[0]
|
58
63
|
|
@@ -97,6 +102,8 @@ module Ruby2JS
|
|
97
102
|
# contents all wrapped in an anonymous function
|
98
103
|
s(:send, s(:block, s(:send, nil, :lambda), s(:args),
|
99
104
|
s(:begin, s(:casgn, nil, name, app), *block)), :[])
|
105
|
+
ensure
|
106
|
+
@ngContext = ngContext
|
100
107
|
end
|
101
108
|
|
102
109
|
# input:
|
@@ -107,7 +114,9 @@ module Ruby2JS
|
|
107
114
|
# ...
|
108
115
|
# end
|
109
116
|
def on_class(node)
|
117
|
+
ngContext, @ngContext = @ngContext, :class
|
110
118
|
return super unless @ngApp and @ngChildren.include? node
|
119
|
+
|
111
120
|
name = node.children.first
|
112
121
|
if name.children.first == nil
|
113
122
|
@ngClassUses, @ngClassOmit = [], []
|
@@ -128,6 +137,9 @@ module Ruby2JS
|
|
128
137
|
else
|
129
138
|
super
|
130
139
|
end
|
140
|
+
ensure
|
141
|
+
@ngClassUses, @ngClassOmit = [], []
|
142
|
+
@ngContext = ngContext
|
131
143
|
end
|
132
144
|
|
133
145
|
# input:
|
@@ -156,6 +168,8 @@ module Ruby2JS
|
|
156
168
|
ng_factory(node)
|
157
169
|
when :filter
|
158
170
|
ng_filter(node)
|
171
|
+
when :config
|
172
|
+
ng_config(node)
|
159
173
|
when :directive
|
160
174
|
hash = AngularRB.hash(node.children[2..-1])
|
161
175
|
if hash
|
@@ -163,7 +177,11 @@ module Ruby2JS
|
|
163
177
|
end
|
164
178
|
ng_controller(node, :directive)
|
165
179
|
when :watch
|
166
|
-
ng_watch(node)
|
180
|
+
ng_watch(node, :$watch)
|
181
|
+
when :on
|
182
|
+
ng_watch(node, :$on)
|
183
|
+
when :observe
|
184
|
+
ng_observe(node)
|
167
185
|
else
|
168
186
|
super
|
169
187
|
end
|
@@ -172,13 +190,44 @@ module Ruby2JS
|
|
172
190
|
end
|
173
191
|
end
|
174
192
|
|
193
|
+
# input:
|
194
|
+
# config :service do
|
195
|
+
# name = value
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# output:
|
199
|
+
# AppName.config("service") do |service|
|
200
|
+
# service.name = value
|
201
|
+
# end
|
202
|
+
def ng_config(node)
|
203
|
+
call = node.children.first
|
204
|
+
services = call.children[2..-1].map {|sym| sym.children[0]}
|
205
|
+
list = node.children[2..-1]
|
206
|
+
|
207
|
+
if services.length == 1
|
208
|
+
hash = AngularRB.hash(node.children[2..-1])
|
209
|
+
if hash
|
210
|
+
service = call.children[2].children[0]
|
211
|
+
list = hash.children.map do |pair|
|
212
|
+
s(:send, s(:gvar, service), "#{pair.children[0].children[0]}=",
|
213
|
+
pair.children[1])
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
s(:send, @ngApp, :config,
|
219
|
+
s(:array, *services.map {|sym| s(:str, sym.to_s)},
|
220
|
+
s(:block, s(:send, nil, :proc),
|
221
|
+
s(:args, *services.map {|sym| s(:arg, sym)}), s(:begin, *list))))
|
222
|
+
end
|
223
|
+
|
175
224
|
# input:
|
176
225
|
# controller :name do
|
177
226
|
# ...
|
178
227
|
# end
|
179
228
|
#
|
180
229
|
# output:
|
181
|
-
# AppName.controller("name"
|
230
|
+
# AppName.controller("name") do |uses|
|
182
231
|
# ...
|
183
232
|
# end
|
184
233
|
def ng_controller(node, scope)
|
@@ -216,6 +265,7 @@ module Ruby2JS
|
|
216
265
|
:or, :regexp, :self, :send, :str, :sym, :true, :undefined?, :xstr ]
|
217
266
|
|
218
267
|
def ng_filter(node)
|
268
|
+
ngContext, @ngContext = @ngContext, :filter
|
219
269
|
@ngClassUses, @ngClassOmit = [], []
|
220
270
|
call = node.children.first
|
221
271
|
|
@@ -235,6 +285,9 @@ module Ruby2JS
|
|
235
285
|
outer = s(:send, @ngApp, :filter, *call.children[2..-1])
|
236
286
|
|
237
287
|
node.updated nil, [outer, s(:args, *uses), s(:return, inner)]
|
288
|
+
ensure
|
289
|
+
@ngClassUses, @ngClassOmit = [], []
|
290
|
+
@ngContext = ngContext
|
238
291
|
end
|
239
292
|
|
240
293
|
# input:
|
@@ -245,6 +298,7 @@ module Ruby2JS
|
|
245
298
|
# output:
|
246
299
|
# AppName.factory :name, [uses, lambda {|uses| ...}]
|
247
300
|
def ng_factory(node)
|
301
|
+
ngContext, @ngContext = @ngContext, :factory
|
248
302
|
call = node.children.first
|
249
303
|
call = call.updated(nil, [@ngApp, *call.children[1..-1]])
|
250
304
|
|
@@ -269,6 +323,9 @@ module Ruby2JS
|
|
269
323
|
array = args.map {|arg| s(:str, arg.children.first.to_s)}
|
270
324
|
|
271
325
|
s(:send, *call.children, s(:array, *array, function))
|
326
|
+
ensure
|
327
|
+
@ngClassUses, @ngClassOmit = [], []
|
328
|
+
@ngContext = ngContext
|
272
329
|
end
|
273
330
|
|
274
331
|
# input:
|
@@ -302,13 +359,47 @@ module Ruby2JS
|
|
302
359
|
# $scope.$watch 'expression' do |oldvalue, newvalue|
|
303
360
|
# ...
|
304
361
|
# end
|
305
|
-
|
362
|
+
#
|
363
|
+
# also handles 'on'
|
364
|
+
#
|
365
|
+
def ng_watch(node, method)
|
306
366
|
call = node.children.first
|
307
367
|
if @ngContext == :controller and call.children.first == nil
|
308
|
-
|
309
|
-
|
368
|
+
target = s(:gvar, :$scope)
|
369
|
+
expression = call.children[2]
|
370
|
+
if not [:str, :dstr, :sym, :dsym].include? expression.type
|
371
|
+
expression = s(:block, s(:send, nil, :proc), s(:args),
|
372
|
+
s(:return, expression))
|
373
|
+
end
|
374
|
+
else
|
375
|
+
target = nil
|
376
|
+
method = call.children[1]
|
377
|
+
expression = call.children[2]
|
378
|
+
end
|
379
|
+
call = s(:send, target, method, process(expression),
|
380
|
+
*process_all(call.children[3..-1]))
|
381
|
+
node = node.updated nil, [call, *process_all(node.children[1..-1])]
|
382
|
+
end
|
383
|
+
|
384
|
+
# input:
|
385
|
+
# observe attr.name do |value|
|
386
|
+
# ...
|
387
|
+
# end
|
388
|
+
#
|
389
|
+
# output:
|
390
|
+
# attr.$observe('name') do |value|
|
391
|
+
# ...
|
392
|
+
# end
|
393
|
+
def ng_observe(node)
|
394
|
+
if @ngContext == :directive
|
395
|
+
call = node.children[0]
|
396
|
+
expression = call.children[2]
|
397
|
+
call = s(:send, expression.children[0], :$observe,
|
398
|
+
s(:sym, expression.children[1]))
|
399
|
+
process node.updated nil, [call, *node.children[1..-1]]
|
400
|
+
else
|
401
|
+
node.updated nil, process_all(node.children)
|
310
402
|
end
|
311
|
-
return process node
|
312
403
|
end
|
313
404
|
|
314
405
|
# convert ivar assignments in controllers to $scope
|
@@ -326,6 +417,80 @@ module Ruby2JS
|
|
326
417
|
end
|
327
418
|
end
|
328
419
|
|
420
|
+
NG_METHOD_MAP = {
|
421
|
+
:apply! => [:$rootScope, :$apply],
|
422
|
+
:apply => [:$scope, :$apply],
|
423
|
+
:broadcast! => [:$rootScope, :$broadcast],
|
424
|
+
:broadcast => [:$scope, :$broadcast],
|
425
|
+
:digest! => [:$rootScope, :$digest],
|
426
|
+
:digest => [:$scope, :$digest],
|
427
|
+
:emit => [:$scope, :$emit],
|
428
|
+
:evalAsync! => [:$rootScope, :$evalAsync],
|
429
|
+
:evalAsync => [:$scope, :$evalAsync],
|
430
|
+
:eval! => [:$rootScope, :$eval],
|
431
|
+
:eval => [:$scope, :$eval],
|
432
|
+
:filter => [nil, :$filter],
|
433
|
+
:parent => [:$scope, :$parent],
|
434
|
+
}
|
435
|
+
|
436
|
+
def on_send(node)
|
437
|
+
if @ngContext == :controller
|
438
|
+
# map well known method names to the appropriate service
|
439
|
+
scope, method = NG_METHOD_MAP[node.children[1]]
|
440
|
+
|
441
|
+
return super unless node.children.first == nil and method
|
442
|
+
|
443
|
+
scope = s(:gvar, scope) if scope
|
444
|
+
process s(:gvar, method) unless scope
|
445
|
+
|
446
|
+
process node.updated nil, [scope, method, *node.children[2..-1]]
|
447
|
+
|
448
|
+
elsif @ngContext == :module and node.children[0]
|
449
|
+
return super unless @ngModule.include? node
|
450
|
+
child = node
|
451
|
+
while child and child.type == :send
|
452
|
+
child = child.children[0]
|
453
|
+
end
|
454
|
+
|
455
|
+
# singleton configuration syntax
|
456
|
+
return super unless child and (child.type == :gvar or
|
457
|
+
(child.type == :const and child.children[0] == nil))
|
458
|
+
|
459
|
+
service = child.children.last
|
460
|
+
s(:send, @ngApp, :config, s(:array, s(:str, service.to_s), s(:block,
|
461
|
+
s(:send, nil, :proc), s(:args, s(:arg, service)), node)))
|
462
|
+
|
463
|
+
elsif @ngContext == :directive
|
464
|
+
if node.children[0..1] == [nil, :interpolate]
|
465
|
+
|
466
|
+
@ngClassUses << :$interpolate
|
467
|
+
if node.children.length == 3
|
468
|
+
process node.updated nil, [nil, :$interpolate, node.children[2]]
|
469
|
+
else
|
470
|
+
process s(:send, s(:send, nil, :$interpolate, node.children[2]),
|
471
|
+
nil, node.children[3])
|
472
|
+
end
|
473
|
+
|
474
|
+
elsif node.children[0..1] == [nil, :compile]
|
475
|
+
|
476
|
+
@ngClassUses << :$compile
|
477
|
+
if node.children.length == 3
|
478
|
+
process node.updated nil, [nil, :$compile, node.children[2]]
|
479
|
+
else
|
480
|
+
process s(:send, s(:send, nil, :$compile, node.children[2]),
|
481
|
+
nil, node.children[3])
|
482
|
+
end
|
483
|
+
|
484
|
+
|
485
|
+
else
|
486
|
+
super
|
487
|
+
end
|
488
|
+
|
489
|
+
else
|
490
|
+
super
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
329
494
|
# convert instance method definitions in controllers to $scope
|
330
495
|
def on_def(node)
|
331
496
|
if @ngContext == :controller
|
@@ -25,6 +25,24 @@ module Ruby2JS
|
|
25
25
|
source, method, before, after = node.children
|
26
26
|
process node.updated nil, [source, :replace, before, after]
|
27
27
|
|
28
|
+
elsif [:sub!, :gsub!].include? node.children[1]
|
29
|
+
method = :"#{node.children[1].to_s[0..-2]}"
|
30
|
+
target = node.children[0]
|
31
|
+
if target.type == :lvar
|
32
|
+
process s(:lvasgn, target.children[0], s(:send,
|
33
|
+
s(:lvar, target.children[0]), method, *node.children[2..-1]))
|
34
|
+
elsif target.type == :send
|
35
|
+
if target.children[0] == nil
|
36
|
+
process s(:lvasgn, target.children[1], s(:send,
|
37
|
+
s(:lvar, target.children[1]), method, *node.children[2..-1]))
|
38
|
+
else
|
39
|
+
process s(:send, target.children[0], :"#{target.children[1]}=",
|
40
|
+
s(:send, target, method, *node.children[2..-1]))
|
41
|
+
end
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
28
46
|
elsif node.children[1] == :gsub and node.children.length == 4
|
29
47
|
source, method, before, after = node.children
|
30
48
|
if before.type == :regexp
|
@@ -139,18 +157,25 @@ module Ruby2JS
|
|
139
157
|
block = process s(:block, s(:send, nil, :proc), *node.children[1..-1])
|
140
158
|
call.updated nil, [*call.children[0..1], block, *call.children[2..-1]]
|
141
159
|
|
142
|
-
elsif [:sub, :gsub].include? call.children[1]
|
160
|
+
elsif [:sub, :gsub, :sub!, :gsub!].include? call.children[1]
|
143
161
|
return super if call.children.first == nil
|
144
|
-
block = s(:block, s(:send, nil, :proc),
|
162
|
+
block = s(:block, s(:send, nil, :proc), node.children[1],
|
163
|
+
s(:autoreturn, *node.children[2..-1]))
|
145
164
|
process call.updated(nil, [*call.children, block])
|
146
165
|
|
147
166
|
elsif call.children[1] == :any? and call.children.length == 2
|
148
167
|
call = call.updated nil, [call.children.first, :some]
|
149
|
-
node.updated nil, [call,
|
168
|
+
process node.updated nil, [call, node.children[1],
|
169
|
+
s(:autoreturn, *node.children[2..-1])]
|
150
170
|
|
151
171
|
elsif call.children[1] == :all? and call.children.length == 2
|
152
172
|
call = call.updated nil, [call.children.first, :every]
|
153
|
-
node.updated nil, [call,
|
173
|
+
process node.updated nil, [call, node.children[1],
|
174
|
+
s(:autoreturn, *node.children[2..-1])]
|
175
|
+
|
176
|
+
elsif call.children[1] == :map and call.children.length == 2
|
177
|
+
node.updated nil, [process(call), process(node.children[1]),
|
178
|
+
s(:autoreturn, *process_all(node.children[2..-1]))]
|
154
179
|
|
155
180
|
else
|
156
181
|
super
|
@@ -10,46 +10,19 @@ module Ruby2JS
|
|
10
10
|
def on_block(node)
|
11
11
|
children = process_all(node.children)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
if EXPRESSIONS.include? block.last.type
|
20
|
-
block.push s(:return, block.pop)
|
21
|
-
end
|
22
|
-
|
23
|
-
if block.length == 1
|
24
|
-
children.push block.first
|
25
|
-
else
|
26
|
-
children.push s(:begin, *block)
|
27
|
-
end
|
28
|
-
|
29
|
-
node.updated nil, children
|
13
|
+
children[-1] = s(:nil) if children.last == nil
|
14
|
+
|
15
|
+
node.updated nil, [*node.children[0..1],
|
16
|
+
s(:autoreturn, *children[2..-1])]
|
30
17
|
end
|
31
18
|
|
32
19
|
def on_def(node)
|
33
20
|
children = process_all(node.children[1..-1])
|
34
|
-
children.unshift node.children.first
|
35
|
-
|
36
|
-
# find the block
|
37
|
-
block = [children.pop || s(:nil)]
|
38
|
-
while block.length == 1 and block.first.type == :begin
|
39
|
-
block = block.first.children.dup
|
40
|
-
end
|
41
|
-
|
42
|
-
if EXPRESSIONS.include? block.last.type
|
43
|
-
block.push s(:return, block.pop)
|
44
|
-
end
|
45
21
|
|
46
|
-
if
|
47
|
-
children.push block.first
|
48
|
-
else
|
49
|
-
children.push s(:begin, *block)
|
50
|
-
end
|
22
|
+
children[-1] = s(:nil) if children.last == nil
|
51
23
|
|
52
|
-
node.updated nil, children
|
24
|
+
node.updated nil, [node.children[0], children.first,
|
25
|
+
s(:autoreturn, *children[1..-1])]
|
53
26
|
end
|
54
27
|
end
|
55
28
|
|
data/lib/ruby2js/version.rb
CHANGED
data/ruby2js.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "ruby2js"
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.4.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Sam Ruby"]
|
9
|
-
s.date = "2014-01-
|
9
|
+
s.date = "2014-01-18"
|
10
10
|
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"
|
11
11
|
s.email = "rubys@intertwingly.net"
|
12
12
|
s.files = ["ruby2js.gemspec", "README.md", "lib/ruby2js", "lib/ruby2js/rails.rb", "lib/ruby2js/version.rb", "lib/ruby2js/converter", "lib/ruby2js/converter/kwbegin.rb", "lib/ruby2js/converter/const.rb", "lib/ruby2js/converter/return.rb", "lib/ruby2js/converter/prototype.rb", "lib/ruby2js/converter/opasgn.rb", "lib/ruby2js/converter/xstr.rb", "lib/ruby2js/converter/args.rb", "lib/ruby2js/converter/defs.rb", "lib/ruby2js/converter/literal.rb", "lib/ruby2js/converter/array.rb", "lib/ruby2js/converter/if.rb", "lib/ruby2js/converter/nil.rb", "lib/ruby2js/converter/logical.rb", "lib/ruby2js/converter/next.rb", "lib/ruby2js/converter/while.rb", "lib/ruby2js/converter/whilepost.rb", "lib/ruby2js/converter/arg.rb", "lib/ruby2js/converter/case.rb", "lib/ruby2js/converter/break.rb", "lib/ruby2js/converter/hash.rb", "lib/ruby2js/converter/for.rb", "lib/ruby2js/converter/boolean.rb", "lib/ruby2js/converter/module.rb", "lib/ruby2js/converter/var.rb", "lib/ruby2js/converter/undef.rb", "lib/ruby2js/converter/blockpass.rb", "lib/ruby2js/converter/until.rb", "lib/ruby2js/converter/regexp.rb", "lib/ruby2js/converter/untilpost.rb", "lib/ruby2js/converter/masgn.rb", "lib/ruby2js/converter/cvasgn.rb", "lib/ruby2js/converter/block.rb", "lib/ruby2js/converter/ivar.rb", "lib/ruby2js/converter/send.rb", "lib/ruby2js/converter/vasgn.rb", "lib/ruby2js/converter/defined.rb", "lib/ruby2js/converter/def.rb", "lib/ruby2js/converter/sym.rb", "lib/ruby2js/converter/cvar.rb", "lib/ruby2js/converter/ivasgn.rb", "lib/ruby2js/converter/casgn.rb", "lib/ruby2js/converter/self.rb", "lib/ruby2js/converter/begin.rb", "lib/ruby2js/converter/dstr.rb", "lib/ruby2js/converter/class.rb", "lib/ruby2js/cgi.rb", "lib/ruby2js/converter.rb", "lib/ruby2js/filter", "lib/ruby2js/filter/return.rb", "lib/ruby2js/filter/strict.rb", "lib/ruby2js/filter/angularrb.rb", "lib/ruby2js/filter/angular-resource.rb", "lib/ruby2js/filter/functions.rb", "lib/ruby2js/filter/jquery.rb", "lib/ruby2js/filter/angular-route.rb", "lib/ruby2js/sinatra.rb", "lib/ruby2js.rb"]
|
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: 1.
|
4
|
+
version: 1.4.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: 2014-01-
|
11
|
+
date: 2014-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|