superchris-rubyjs 0.8.2
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.
- data/README +131 -0
- data/Rakefile +65 -0
- data/bin/rubyjs +144 -0
- data/rubyjs.gemspec +112 -0
- data/src/rubyjs.rb +3 -0
- data/src/rubyjs/code_generator.rb +474 -0
- data/src/rubyjs/compiler.rb +2061 -0
- data/src/rubyjs/debug_name_generator.rb +95 -0
- data/src/rubyjs/encoder.rb +171 -0
- data/src/rubyjs/eval_into.rb +59 -0
- data/src/rubyjs/lib/core.rb +1016 -0
- data/src/rubyjs/lib/dom_element.rb +66 -0
- data/src/rubyjs/lib/json.rb +101 -0
- data/src/rubyjs/lib/microunit.rb +188 -0
- data/src/rubyjs/model.rb +293 -0
- data/src/rubyjs/name_generator.rb +71 -0
- data/src/rwt/AbsolutePanel.rb +161 -0
- data/src/rwt/DOM.Konqueror.rb +89 -0
- data/src/rwt/DOM.Opera.rb +65 -0
- data/src/rwt/DOM.rb +1044 -0
- data/src/rwt/Event.Opera.rb +35 -0
- data/src/rwt/Event.rb +429 -0
- data/src/rwt/HTTPRequest.IE6.rb +5 -0
- data/src/rwt/HTTPRequest.rb +74 -0
- data/src/rwt/Label.rb +164 -0
- data/src/rwt/Panel.rb +90 -0
- data/src/rwt/RootPanel.rb +16 -0
- data/src/rwt/UIObject.rb +495 -0
- data/src/rwt/Widget.rb +193 -0
- data/src/rwt/ported-from/AbsolutePanel.java +158 -0
- data/src/rwt/ported-from/DOM.java +571 -0
- data/src/rwt/ported-from/DOMImpl.java +426 -0
- data/src/rwt/ported-from/DOMImplOpera.java +82 -0
- data/src/rwt/ported-from/DOMImplStandard.java +234 -0
- data/src/rwt/ported-from/HTTPRequest.java +81 -0
- data/src/rwt/ported-from/HTTPRequestImpl.java +103 -0
- data/src/rwt/ported-from/Label.java +163 -0
- data/src/rwt/ported-from/Panel.java +99 -0
- data/src/rwt/ported-from/UIObject.java +614 -0
- data/src/rwt/ported-from/Widget.java +221 -0
- data/test/benchmark/bm_vm1_block.rb +15 -0
- data/test/benchmark/bm_vm1_const.rb +13 -0
- data/test/benchmark/bm_vm1_ensure.rb +15 -0
- data/test/benchmark/common.rb +5 -0
- data/test/benchmark/params.yaml +7 -0
- data/test/common.Browser.rb +13 -0
- data/test/common.rb +8 -0
- data/test/gen_browser_test_suite.rb +129 -0
- data/test/gen_test_suite.rb +41 -0
- data/test/run_benchs.rb +58 -0
- data/test/run_tests.rb +22 -0
- data/test/test_args.rb +24 -0
- data/test/test_array.rb +22 -0
- data/test/test_case.rb +35 -0
- data/test/test_class.rb +55 -0
- data/test/test_eql.rb +9 -0
- data/test/test_exception.rb +61 -0
- data/test/test_expr.rb +12 -0
- data/test/test_hash.rb +29 -0
- data/test/test_hot_ruby.rb +146 -0
- data/test/test_if.rb +28 -0
- data/test/test_insertion_sort.rb +25 -0
- data/test/test_inspect.rb +10 -0
- data/test/test_lebewesen.rb +39 -0
- data/test/test_massign.rb +66 -0
- data/test/test_new.rb +12 -0
- data/test/test_range.rb +70 -0
- data/test/test_regexp.rb +22 -0
- data/test/test_send.rb +65 -0
- data/test/test_simple_output.rb +5 -0
- data/test/test_splat.rb +21 -0
- data/test/test_string.rb +51 -0
- data/test/test_test.rb +17 -0
- data/test/test_yield.rb +154 -0
- data/utils/js/Makefile +9 -0
- data/utils/js/RunScript.class +0 -0
- data/utils/js/RunScript.java +73 -0
- data/utils/js/js.jar +0 -0
- data/utils/js/run.sh +3 -0
- data/utils/jsc/Makefile +7 -0
- data/utils/jsc/README +3 -0
- data/utils/jsc/RunScript.c +93 -0
- data/utils/jsc/run.sh +15 -0
- data/utils/yuicompressor/README +1 -0
- data/utils/yuicompressor/yuicompressor-2.2.5.jar +0 -0
- metadata +157 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
class DOMElement
|
2
|
+
def initialize(element)
|
3
|
+
@dom_element = element
|
4
|
+
end
|
5
|
+
|
6
|
+
def observe(event, &block)
|
7
|
+
element = @dom_element
|
8
|
+
`
|
9
|
+
if (#<element>.addEventListener) {
|
10
|
+
#<element>.addEventListener(#<event>, #<block>, false);
|
11
|
+
} else {
|
12
|
+
#<element>.attachEvent("on" + #<event>, #<block>);
|
13
|
+
}
|
14
|
+
`
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](attribute)
|
19
|
+
element = @dom_element
|
20
|
+
`return #<element>[#<attribute>]`
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(attr, value)
|
24
|
+
attr_name = attr.to_s
|
25
|
+
element = @dom_element
|
26
|
+
`#<element>[#<attr_name>] = #<value>;`
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.find_js_element(element)
|
31
|
+
`return document.getElementById(#<element>);`
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def self.find(element)
|
36
|
+
dom_element = self.find_js_element(element)
|
37
|
+
DOMElement.new(dom_element)
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Gets an HTML representation (as String) of an element's children.
|
42
|
+
#
|
43
|
+
# elem:: the element whose HTML is to be retrieved
|
44
|
+
# return:: the HTML representation of the element's children
|
45
|
+
#
|
46
|
+
def inner_html
|
47
|
+
elem = @dom_element
|
48
|
+
`
|
49
|
+
var ret = #<elem>.innerHTML;
|
50
|
+
return (ret == null) ? #<nil> : ret;`
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Sets the HTML contained within an element.
|
55
|
+
#
|
56
|
+
# elem:: the element whose inner HTML is to be set
|
57
|
+
# html:: the new html
|
58
|
+
#
|
59
|
+
def inner_html=(html)
|
60
|
+
elem = @dom_element
|
61
|
+
`
|
62
|
+
#<elem>.innerHTML = #<html>;
|
63
|
+
return #<nil>;`
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
#
|
2
|
+
# JSON loading/dumping
|
3
|
+
#
|
4
|
+
# Parser code taken from http://www.json.org/json.js
|
5
|
+
#
|
6
|
+
|
7
|
+
class JSON
|
8
|
+
class SyntaxError < RuntimeError; end
|
9
|
+
|
10
|
+
#
|
11
|
+
# Parsing happens in three stages. In the first stage, we run the text against
|
12
|
+
# a regular expression which looks for non-JSON characters. We are especially
|
13
|
+
# concerned with '()' and 'new' because they can cause invocation, and '='
|
14
|
+
# because it can cause mutation. But just to be safe, we will reject all
|
15
|
+
# unexpected characters.
|
16
|
+
#
|
17
|
+
# We split the first stage into 4 regexp operations in order to work around
|
18
|
+
# crippling deficiencies in IE's and Safari's regexp engines. First we replace
|
19
|
+
# all backslash pairs with '@' (a non-JSON character). Second, we replace all
|
20
|
+
# simple value tokens with ']' characters. Third, we delete all open brackets
|
21
|
+
# that follow a colon or comma or that begin the text. Finally, we look to see
|
22
|
+
# that the remaining characters are only whitespace or ']' or ',' or ':' or '{'
|
23
|
+
# or '}'. If that is so, then the text is safe for eval.
|
24
|
+
#
|
25
|
+
# In the second stage we use the eval function to compile the text into a
|
26
|
+
# JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
27
|
+
# in JavaScript: it can begin a block or an object literal. We wrap the text
|
28
|
+
# in parens to eliminate the ambiguity.
|
29
|
+
#
|
30
|
+
def self._parse(str)
|
31
|
+
RubyJS::inline <<-'endjs'
|
32
|
+
if (/^[\],:{}\s]*$/.test(#<str>.replace(/\\./g, '@').
|
33
|
+
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(:?[eE][+\-]?\d+)?/g, ']').
|
34
|
+
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
35
|
+
return eval('(' + #<str> + ')');
|
36
|
+
}
|
37
|
+
endjs
|
38
|
+
|
39
|
+
raise SyntaxError, str
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.load(str)
|
43
|
+
obj = _parse(str)
|
44
|
+
`
|
45
|
+
var conv = function(obj) {
|
46
|
+
if (obj==null) return #<nil>;
|
47
|
+
else if (obj instanceof Array) {
|
48
|
+
for (var i=0; i<obj.length; i++) obj[i] = conv(obj[i]);
|
49
|
+
}
|
50
|
+
else if (typeof(obj) == 'object') {
|
51
|
+
var nobj = #<Hash>.#<m:new>();
|
52
|
+
for (var i in obj) {
|
53
|
+
nobj.#<m:[]=>(#<nil>, conv(i), conv(obj[i]));
|
54
|
+
}
|
55
|
+
return nobj;
|
56
|
+
}
|
57
|
+
return obj;
|
58
|
+
};
|
59
|
+
return conv(#<obj>);
|
60
|
+
`
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.dump(obj)
|
64
|
+
obj.to_json
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Object
|
69
|
+
def to_json; raise end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Boolean
|
73
|
+
alias to_json to_s
|
74
|
+
end
|
75
|
+
|
76
|
+
class NilClass
|
77
|
+
def to_json; "null" end
|
78
|
+
end
|
79
|
+
|
80
|
+
class String
|
81
|
+
alias to_json inspect # FIXME?
|
82
|
+
end
|
83
|
+
|
84
|
+
class Number
|
85
|
+
alias to_json to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
class Array
|
89
|
+
def to_json
|
90
|
+
map {|a| a.to_json}.join(",")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Hash
|
95
|
+
def to_json
|
96
|
+
str = "{"
|
97
|
+
str += map {|k, v| (k.to_json + ":" + v.to_json) }.join(",")
|
98
|
+
str += "}"
|
99
|
+
str
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
module MicroUnit
|
2
|
+
class TestCase
|
3
|
+
# def self.reset
|
4
|
+
# @@test_suites = {}
|
5
|
+
# end
|
6
|
+
#
|
7
|
+
# reset
|
8
|
+
|
9
|
+
# def self.inherited klass
|
10
|
+
# @test_suites ||= {}
|
11
|
+
# @test_suites[klass] = true
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def self.test_suites
|
15
|
+
# @test_suites.keys.sort_by { |ts| ts.name }
|
16
|
+
# end
|
17
|
+
|
18
|
+
attr_accessor :_assertions
|
19
|
+
|
20
|
+
def setup
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def teardown
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def _increment_assertions
|
29
|
+
@_assertions ||= 0
|
30
|
+
@_assertions += 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def assert test, msg = "failed assertion (no message given)"
|
34
|
+
_increment_assertions
|
35
|
+
raise StandardError, msg unless test
|
36
|
+
end
|
37
|
+
|
38
|
+
def assert_block msg = "assert_block failed."
|
39
|
+
assert yield, msg
|
40
|
+
end
|
41
|
+
|
42
|
+
def assert_equal exp, act, msg = ""
|
43
|
+
msg += '.' unless msg.empty?
|
44
|
+
assert exp == act, "#{msg}\n<#{exp.inspect}> expected but was\n<#{act.inspect}>.".strip
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.main
|
48
|
+
TestRunner.run(self)
|
49
|
+
rescue StandardError => error
|
50
|
+
puts error
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# def assert_in_delta exp, act, delta, msg = "Expected #{exp} to be within #{delta} of #{act}"
|
55
|
+
# assert delta.to_f > (exp.to_f - act.to_f).abs, msg
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# def assert_instance_of cls, obj, msg = "Expected #{obj.inspect} to be an instance of #{cls}"
|
59
|
+
# assert cls === obj, msg
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# def assert_kind_of cls, obj, msg = "Expected #{obj.inspect} to be a kind of #{cls}"
|
63
|
+
# assert obj.kind_of?(cls), msg
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# def assert_match exp, act, msg = "Expected #{act.inspect} to match #{exp.inspect}"
|
67
|
+
# assert act =~ exp, msg
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# def assert_nil obj, msg = "Expected #{obj.inspect} to be nil"
|
71
|
+
# assert obj.nil?, msg
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# def assert_no_match exp, act, msg = "Expected #{act.inspect} to not match #{exp.inspect}"
|
75
|
+
# assert act !~ exp, msg
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# def assert_not_equal exp, act, msg = "Expected #{act.inspect} to not be equal to #{exp.inspect}"
|
79
|
+
# assert exp != act, msg
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# def assert_not_nil obj, msg = "Expected #{obj.inspect} to not be nil"
|
83
|
+
# assert ! obj.nil?, msg
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# def assert_not_same exp, act, msg = "Expected #{act.inspect} to not be the same as #{exp.inspect}"
|
87
|
+
# assert ! exp.equal?(act), msg
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# def assert_nothing_raised
|
91
|
+
# _increment_assertions
|
92
|
+
# yield
|
93
|
+
# rescue => e
|
94
|
+
# raise StandardError, exception_details(e, "Exception raised:")
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# alias :assert_nothing_thrown :assert_nothing_raised
|
98
|
+
#
|
99
|
+
# def assert_operator o1, op, o2, msg = "<#{o1.inspect}> expected to be\n#{op.inspect}\n<#{o2.inspect}>."
|
100
|
+
# assert o1.__send__(op, o2), msg
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# def exception_details e, msg
|
104
|
+
# "#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{filter_backtrace(e.backtrace).join("\n")}\n---------------"
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# def assert_raises *exp
|
108
|
+
# msg = "" #exp.last.kind_of(String) ? exp.pop : nil
|
109
|
+
# exp = exp.first if exp.size == 1
|
110
|
+
# begin
|
111
|
+
# yield
|
112
|
+
# raise StandardError, "<#{exp.inspect}> exception expected but none was thrown."
|
113
|
+
# rescue Exception => e
|
114
|
+
# assert((Array === exp ? exp.include?(e) : exp === e),
|
115
|
+
# exception_details(e,
|
116
|
+
# "<#{exp.inspect}> exception expected but was"))
|
117
|
+
#
|
118
|
+
# return e
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
# alias :assert_raise :assert_raises
|
122
|
+
#
|
123
|
+
# def assert_respond_to obj, meth, msg = "Expected #{obj.inspect} of type #{obj.class} to respond_to? #{meth.inspect}"
|
124
|
+
# assert obj.respond_to?(meth), msg
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# def assert_same exp, act, msg = "Expected #{act.inspect} to be the same as #{exp.inspect}."
|
128
|
+
# assert exp.equal?(act), msg
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# def assert_send send, msg = nil
|
132
|
+
# recv, meth, *args = send
|
133
|
+
# assert(recv.__send__(meth, *args),
|
134
|
+
# msg || "<#{recv.inspect}> expected to respond to\n<#{meth.inspect}> with a true value.")
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# def assert_throws sym, msg = "<#{sym.inspect}> should have been thrown."
|
138
|
+
# caught = true
|
139
|
+
# catch(sym) do
|
140
|
+
# yield rescue nil
|
141
|
+
# caught = false
|
142
|
+
# end
|
143
|
+
# assert caught, msg
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# def flunk msg = "Flunked"
|
147
|
+
# assert false, msg
|
148
|
+
# end
|
149
|
+
end # class TestCase
|
150
|
+
|
151
|
+
class TestRunner
|
152
|
+
|
153
|
+
def self.puts(m)
|
154
|
+
message = m.to_s
|
155
|
+
`document.write(#<message>);`
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.run(klass)
|
159
|
+
@failures, @errors, @assertions = 0,0,0
|
160
|
+
klass.instance_methods.each do |meth|
|
161
|
+
if (meth =~ /^test/)
|
162
|
+
inst = klass.new
|
163
|
+
begin
|
164
|
+
inst.setup
|
165
|
+
inst.send meth
|
166
|
+
puts "."
|
167
|
+
rescue Exception => e
|
168
|
+
puke(klass, meth, e)
|
169
|
+
ensure
|
170
|
+
begin
|
171
|
+
inst.teardown
|
172
|
+
rescue Exception => e
|
173
|
+
puke(klass, meth, e)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
@assertions += inst._assertions
|
177
|
+
end
|
178
|
+
end
|
179
|
+
puts ("<br/>")
|
180
|
+
puts ("Assertions: #{@assertions} Failures: #{@failures}")
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.puke(klass, meth, e)
|
184
|
+
puts e
|
185
|
+
@failures += 1
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
data/src/rubyjs/model.rb
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
#
|
2
|
+
# Extract the class/module hierarchy and the methods.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'parse_tree'
|
9
|
+
require 'sexp_processor'
|
10
|
+
require 'enumerator'
|
11
|
+
require 'rubyjs/encoder'
|
12
|
+
require 'set'
|
13
|
+
|
14
|
+
class MethodExtractor < SexpProcessor
|
15
|
+
attr_accessor :instance_methods, :methods
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
super()
|
19
|
+
|
20
|
+
self.strict = false
|
21
|
+
self.auto_shift_type = false
|
22
|
+
self.require_empty = false
|
23
|
+
|
24
|
+
@instance_methods = {}
|
25
|
+
@methods = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def process_defs(exp)
|
29
|
+
defs, _self, name, code, *r = *exp
|
30
|
+
raise unless r.empty?
|
31
|
+
raise unless _self == s(:self)
|
32
|
+
|
33
|
+
@methods[name.to_s] = s(:defn, name, code)
|
34
|
+
return s()
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_defn(exp)
|
38
|
+
defn, name, code, *r = *exp
|
39
|
+
raise unless r.empty?
|
40
|
+
|
41
|
+
@instance_methods[name.to_s] = exp
|
42
|
+
return s()
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Model < Encoder
|
47
|
+
SCOPE_R = /^RubyJS::Environment::(.*)$/
|
48
|
+
|
49
|
+
attr_accessor :models
|
50
|
+
attr_accessor :current_model
|
51
|
+
|
52
|
+
attr_reader :method_calls
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
super()
|
56
|
+
|
57
|
+
#
|
58
|
+
# record all (potential) names of all method calls
|
59
|
+
#
|
60
|
+
@method_calls = Set.new
|
61
|
+
|
62
|
+
|
63
|
+
@models = {}
|
64
|
+
|
65
|
+
# all modules and classes (a Class is_a Module)
|
66
|
+
ObjectSpace.each_object {|o|
|
67
|
+
@models[o] = model_for(o) if o.is_a?(::Module) && o.name =~ SCOPE_R
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_method_call(name)
|
72
|
+
@method_calls.add(name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def iterate_all(seen, &block)
|
76
|
+
@models.each_value do |v|
|
77
|
+
iterate_rec(v, seen, &block)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def iterate_rec(model, seen, &block)
|
82
|
+
return if seen.include?(model[:for])
|
83
|
+
iterate_rec(@models[model[:superclass]], seen, &block) if model[:superclass]
|
84
|
+
|
85
|
+
model[:modules].each do |m|
|
86
|
+
iterate_rec(@models[m], seen, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
with_current_model(model) do
|
90
|
+
block.call(model)
|
91
|
+
end
|
92
|
+
seen.add(model[:for])
|
93
|
+
end
|
94
|
+
|
95
|
+
alias old_encode_constant encode_constant
|
96
|
+
|
97
|
+
def encode_constant(name)
|
98
|
+
if @current_model
|
99
|
+
lookup_constant(name)
|
100
|
+
else
|
101
|
+
old_encode_constant(name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Compile time constant lookup.
|
107
|
+
#
|
108
|
+
# Lookup rules (like Ruby 1.9+):
|
109
|
+
#
|
110
|
+
# 1. Current class
|
111
|
+
# 2. Super classes except object
|
112
|
+
# 3. lexically enclosing modules/classes
|
113
|
+
# 4. Object
|
114
|
+
#
|
115
|
+
def lookup_constant(name)
|
116
|
+
model = @current_model
|
117
|
+
prefix, *path = name.split("::")
|
118
|
+
|
119
|
+
start_lookup_at = nil
|
120
|
+
done = false
|
121
|
+
|
122
|
+
if prefix.empty?
|
123
|
+
# e.g. "::A"
|
124
|
+
start_lookup_at = RubyJS::Environment
|
125
|
+
done = true
|
126
|
+
else
|
127
|
+
|
128
|
+
# 1. Current class
|
129
|
+
if model[:for].constants.include?(prefix)
|
130
|
+
start_lookup_at = model[:for].const_get(prefix)
|
131
|
+
done = true
|
132
|
+
end
|
133
|
+
|
134
|
+
# 2. Super classes except object
|
135
|
+
unless done
|
136
|
+
m = model
|
137
|
+
loop do
|
138
|
+
if m[:superclass] and m[:superclass] != RubyJS::Environment::Object
|
139
|
+
if m[:superclass].constants.include?(prefix)
|
140
|
+
start_lookup_at = m[:superclass].const_get(prefix)
|
141
|
+
done = true
|
142
|
+
break
|
143
|
+
else
|
144
|
+
m = @models[m[:superclass]]
|
145
|
+
end
|
146
|
+
else
|
147
|
+
break
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# 3. lexically enclosing modules/classes
|
153
|
+
# FIXME
|
154
|
+
unless done
|
155
|
+
arr = model[:name].split("::")
|
156
|
+
loop do
|
157
|
+
arr.pop
|
158
|
+
|
159
|
+
begin
|
160
|
+
start_lookup_at = eval((["RubyJS", "Environment"] + arr + [prefix]).join("::"))
|
161
|
+
done = true
|
162
|
+
break
|
163
|
+
rescue NameError
|
164
|
+
end
|
165
|
+
|
166
|
+
break if arr.empty?
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# 4. Object
|
171
|
+
unless done
|
172
|
+
begin
|
173
|
+
start_lookup_at = RubyJS::Environment::Object.const_get(prefix)
|
174
|
+
done = true
|
175
|
+
rescue NameError
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
unless done
|
182
|
+
raise "failed to lookup constant prefix #{prefix}"
|
183
|
+
end
|
184
|
+
|
185
|
+
#
|
186
|
+
# follow the whole path, e.g. A::B::C
|
187
|
+
#
|
188
|
+
value = start_lookup_at
|
189
|
+
path.each do |piece|
|
190
|
+
value = value.const_get(piece)
|
191
|
+
end
|
192
|
+
|
193
|
+
if value.is_a?(::Class) or value.is_a?(::Module)
|
194
|
+
# A class or module
|
195
|
+
|
196
|
+
if model = @models[value]
|
197
|
+
return old_encode_constant(model[:name])
|
198
|
+
else
|
199
|
+
raise("unrecognized class/module referenced by constant")
|
200
|
+
end
|
201
|
+
else
|
202
|
+
# A value
|
203
|
+
if value.is_a?(Fixnum)
|
204
|
+
# If it is the receiver of a method call, we have to surround it
|
205
|
+
# with parens, e.g. (1).
|
206
|
+
# As we can't easily decide whether it's a receiver of a method
|
207
|
+
# call, we simply surround every constant Fixnum with parens.
|
208
|
+
return "(" + value.inspect + ")"
|
209
|
+
elsif value.is_a?(String)
|
210
|
+
# FIXME: Generate a reference instead?
|
211
|
+
return value.inspect
|
212
|
+
else
|
213
|
+
raise
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def namify(klass)
|
219
|
+
name = klass.name
|
220
|
+
if name =~ SCOPE_R
|
221
|
+
name = $1
|
222
|
+
else
|
223
|
+
raise "must be scoped inside RubyJS module"
|
224
|
+
end
|
225
|
+
return name
|
226
|
+
end
|
227
|
+
|
228
|
+
def with_current_model(model)
|
229
|
+
old_current_model = @current_model
|
230
|
+
@current_model = model
|
231
|
+
begin
|
232
|
+
yield
|
233
|
+
ensure
|
234
|
+
@current_model = old_current_model
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def model_for(klass)
|
239
|
+
name = namify(klass)
|
240
|
+
|
241
|
+
me = MethodExtractor.new
|
242
|
+
me.process(*ParseTree.new.parse_tree(klass))
|
243
|
+
|
244
|
+
if klass.is_a?(::Class)
|
245
|
+
a = klass.ancestors
|
246
|
+
a = a[0...(a.index(::Object))]
|
247
|
+
|
248
|
+
s = klass.superclass
|
249
|
+
s = nil if s == ::Object
|
250
|
+
|
251
|
+
# remove klass from the ancestor chain
|
252
|
+
a = a[1..-1] if a[0] == klass
|
253
|
+
|
254
|
+
# a now contains the included modules
|
255
|
+
a = a[0...(a.index(s))] if s
|
256
|
+
|
257
|
+
if klass == RubyJS::Environment::Object
|
258
|
+
raise unless s.nil?
|
259
|
+
s = nil
|
260
|
+
else
|
261
|
+
if s.nil?
|
262
|
+
s = RubyJS::Environment::Object
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
return {
|
267
|
+
:for => klass,
|
268
|
+
:modules => a,
|
269
|
+
:superclass => s,
|
270
|
+
:is_a => :class,
|
271
|
+
:name => name,
|
272
|
+
:instance_methods => me.instance_methods,
|
273
|
+
:methods => me.methods
|
274
|
+
}
|
275
|
+
elsif klass.is_a?(::Module)
|
276
|
+
a = klass.ancestors
|
277
|
+
|
278
|
+
# remove klass from the ancestor chain
|
279
|
+
a = a[1..-1] if a[0] == klass
|
280
|
+
|
281
|
+
return {
|
282
|
+
:for => klass,
|
283
|
+
:modules => a,
|
284
|
+
:is_a => :module,
|
285
|
+
:name => name,
|
286
|
+
:instance_methods => me.instance_methods,
|
287
|
+
:methods => me.methods
|
288
|
+
}
|
289
|
+
else
|
290
|
+
raise
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|