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.
Files changed (86) hide show
  1. data/README +131 -0
  2. data/Rakefile +65 -0
  3. data/bin/rubyjs +144 -0
  4. data/rubyjs.gemspec +112 -0
  5. data/src/rubyjs.rb +3 -0
  6. data/src/rubyjs/code_generator.rb +474 -0
  7. data/src/rubyjs/compiler.rb +2061 -0
  8. data/src/rubyjs/debug_name_generator.rb +95 -0
  9. data/src/rubyjs/encoder.rb +171 -0
  10. data/src/rubyjs/eval_into.rb +59 -0
  11. data/src/rubyjs/lib/core.rb +1016 -0
  12. data/src/rubyjs/lib/dom_element.rb +66 -0
  13. data/src/rubyjs/lib/json.rb +101 -0
  14. data/src/rubyjs/lib/microunit.rb +188 -0
  15. data/src/rubyjs/model.rb +293 -0
  16. data/src/rubyjs/name_generator.rb +71 -0
  17. data/src/rwt/AbsolutePanel.rb +161 -0
  18. data/src/rwt/DOM.Konqueror.rb +89 -0
  19. data/src/rwt/DOM.Opera.rb +65 -0
  20. data/src/rwt/DOM.rb +1044 -0
  21. data/src/rwt/Event.Opera.rb +35 -0
  22. data/src/rwt/Event.rb +429 -0
  23. data/src/rwt/HTTPRequest.IE6.rb +5 -0
  24. data/src/rwt/HTTPRequest.rb +74 -0
  25. data/src/rwt/Label.rb +164 -0
  26. data/src/rwt/Panel.rb +90 -0
  27. data/src/rwt/RootPanel.rb +16 -0
  28. data/src/rwt/UIObject.rb +495 -0
  29. data/src/rwt/Widget.rb +193 -0
  30. data/src/rwt/ported-from/AbsolutePanel.java +158 -0
  31. data/src/rwt/ported-from/DOM.java +571 -0
  32. data/src/rwt/ported-from/DOMImpl.java +426 -0
  33. data/src/rwt/ported-from/DOMImplOpera.java +82 -0
  34. data/src/rwt/ported-from/DOMImplStandard.java +234 -0
  35. data/src/rwt/ported-from/HTTPRequest.java +81 -0
  36. data/src/rwt/ported-from/HTTPRequestImpl.java +103 -0
  37. data/src/rwt/ported-from/Label.java +163 -0
  38. data/src/rwt/ported-from/Panel.java +99 -0
  39. data/src/rwt/ported-from/UIObject.java +614 -0
  40. data/src/rwt/ported-from/Widget.java +221 -0
  41. data/test/benchmark/bm_vm1_block.rb +15 -0
  42. data/test/benchmark/bm_vm1_const.rb +13 -0
  43. data/test/benchmark/bm_vm1_ensure.rb +15 -0
  44. data/test/benchmark/common.rb +5 -0
  45. data/test/benchmark/params.yaml +7 -0
  46. data/test/common.Browser.rb +13 -0
  47. data/test/common.rb +8 -0
  48. data/test/gen_browser_test_suite.rb +129 -0
  49. data/test/gen_test_suite.rb +41 -0
  50. data/test/run_benchs.rb +58 -0
  51. data/test/run_tests.rb +22 -0
  52. data/test/test_args.rb +24 -0
  53. data/test/test_array.rb +22 -0
  54. data/test/test_case.rb +35 -0
  55. data/test/test_class.rb +55 -0
  56. data/test/test_eql.rb +9 -0
  57. data/test/test_exception.rb +61 -0
  58. data/test/test_expr.rb +12 -0
  59. data/test/test_hash.rb +29 -0
  60. data/test/test_hot_ruby.rb +146 -0
  61. data/test/test_if.rb +28 -0
  62. data/test/test_insertion_sort.rb +25 -0
  63. data/test/test_inspect.rb +10 -0
  64. data/test/test_lebewesen.rb +39 -0
  65. data/test/test_massign.rb +66 -0
  66. data/test/test_new.rb +12 -0
  67. data/test/test_range.rb +70 -0
  68. data/test/test_regexp.rb +22 -0
  69. data/test/test_send.rb +65 -0
  70. data/test/test_simple_output.rb +5 -0
  71. data/test/test_splat.rb +21 -0
  72. data/test/test_string.rb +51 -0
  73. data/test/test_test.rb +17 -0
  74. data/test/test_yield.rb +154 -0
  75. data/utils/js/Makefile +9 -0
  76. data/utils/js/RunScript.class +0 -0
  77. data/utils/js/RunScript.java +73 -0
  78. data/utils/js/js.jar +0 -0
  79. data/utils/js/run.sh +3 -0
  80. data/utils/jsc/Makefile +7 -0
  81. data/utils/jsc/README +3 -0
  82. data/utils/jsc/RunScript.c +93 -0
  83. data/utils/jsc/run.sh +15 -0
  84. data/utils/yuicompressor/README +1 -0
  85. data/utils/yuicompressor/yuicompressor-2.2.5.jar +0 -0
  86. metadata +157 -0
@@ -0,0 +1,95 @@
1
+ #
2
+ # A NameGenerator that outputs readable, non-obfuscated names.
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ class DebugNameGenerator
9
+
10
+ PREFIX = "___"
11
+
12
+ def initialize
13
+ @tmp_counter = 0
14
+ @cache = {}
15
+ end
16
+
17
+ def fresh
18
+ name = "tmp_" + @tmp_counter.to_s
19
+ @tmp_counter += 1
20
+ return name
21
+ end
22
+
23
+ MAP = [
24
+ %w($ dollar),
25
+ %w(? quest),
26
+ %w(+ plus),
27
+ %w(+@ uplus),
28
+ %w(- minus),
29
+ %w(-@ uminus),
30
+ %w(@ ivar),
31
+ %w(/ div),
32
+ %w(% mod),
33
+ %w(* mul),
34
+ %w(~ neg),
35
+ %w(^ xor),
36
+ %w(&& and),
37
+ %w(& band),
38
+ %w(|| or),
39
+ %w(| bor),
40
+ %w(! not),
41
+ %w(=== eqq),
42
+ %w(== eq),
43
+ %w(!== neqq),
44
+ %w(!= neq),
45
+ %w(=~ match),
46
+ %w(!~ nmatch),
47
+ %w(<<< lshift3),
48
+ %w(>>> rshift3),
49
+ %w(<< lshift),
50
+ %w(>> rshift),
51
+ %w(<= le),
52
+ %w(>= ge),
53
+ %w(> gt),
54
+ %w(< lt),
55
+ %w([]= set),
56
+ %w([] at),
57
+ %w(= eq),
58
+ %w(:: doublecolon)
59
+ ]
60
+
61
+ #
62
+ # Generate a name for +name+. Return the same name for the same
63
+ # +name+.
64
+ #
65
+
66
+ def get(name)
67
+ raise unless name.is_a?(String)
68
+
69
+ if @cache[name]
70
+ return @cache[name]
71
+ else
72
+ name2 = name
73
+ MAP.each do |pat, rep|
74
+ name2 = name2.gsub(pat, PREFIX + rep)
75
+ end
76
+
77
+ if name2 !~ /^[A-Za-z_\$0-9]+$/
78
+ STDERR.puts name2
79
+ end
80
+
81
+ @cache[name] = name2
82
+ return name2
83
+ end
84
+ end
85
+
86
+ def cache
87
+ @cache
88
+ end
89
+
90
+ def reverse_lookup(encoded_name)
91
+ @cache.index(encoded_name)
92
+ end
93
+
94
+
95
+ end
@@ -0,0 +1,171 @@
1
+ #
2
+ # Encode all kind of variables or symbols for Javascript generation.
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ if $RUBYJS__DEBUG
9
+ require 'rubyjs/debug_name_generator'
10
+ NameGenerator = DebugNameGenerator
11
+ else
12
+ require 'rubyjs/name_generator'
13
+ end
14
+
15
+ class Encoder
16
+ def initialize
17
+ @method_and_ivar_name_generator = NameGenerator.new
18
+ @attribute_name_generator = NameGenerator.new
19
+ @global_attribute_name_generator = NameGenerator.new
20
+ @global_name_generator = NameGenerator.new
21
+ reset_local_name_generator!
22
+
23
+ @unique_scope_ids = 0
24
+ end
25
+
26
+ def next_unique_scope_id()
27
+ n = @unique_scope_ids
28
+ @unique_scope_ids += 1
29
+ n
30
+ end
31
+
32
+ def reset_local_name_generator!
33
+ @local_name_generator = NameGenerator.new
34
+ end
35
+
36
+ def with_local
37
+ reset_local_name_generator!
38
+ res = yield
39
+ reset_local_name_generator!
40
+ return res
41
+ end
42
+
43
+ def encode_nil
44
+ 'nil'
45
+ end
46
+
47
+ def encode_self
48
+ 'self'
49
+ end
50
+
51
+ #
52
+ # Constants are encoded with a preceding "$". Doesn't conflict with
53
+ # methods or instance variables, as they are always used in dot
54
+ # notation while constants not.
55
+ #
56
+ # Constants use the global_name_generator. They use the same namespace
57
+ # as global variables do. There is no nameclash, as global variables
58
+ # are prefixed in Ruby with a $ character, so the generated name will
59
+ # always differ (e.g. Constant vs. $Constant leads two two different
60
+ # names).
61
+ #
62
+ def encode_constant(name)
63
+ "$" + @global_name_generator.get(name.to_s)
64
+ end
65
+
66
+ #
67
+ # Encode global variable.
68
+ #
69
+ # See encode_constant().
70
+ #
71
+ def encode_global_variable(name)
72
+ raise if name.to_s[0,1] != '$'
73
+ "$" + @global_name_generator.get(name.to_s)
74
+ end
75
+
76
+ #
77
+ # Encodes a Javascript attribute name.
78
+ # This is used in the runtime environment of RubyJS to obfuscate
79
+ # attribute names. They have their own namespace and don't clash
80
+ # with method names or instance variable names!
81
+ #
82
+ # Attributes are encoded with a preceding "a$". This doesn't conflict
83
+ # with methods or instance variables, as they use "$".
84
+ #
85
+ def encode_attr(name)
86
+ "a$" + @attribute_name_generator.get(name.to_s)
87
+ end
88
+
89
+ #
90
+ # A global attribute. Similar to encode_attr(), but for the global
91
+ # scope (used by the def_class() Javascript function).
92
+ #
93
+ # Global attributes are encoded with a "a$" prefix. They don't
94
+ # conflict with attributes, because attributes are always used in dot
95
+ # notation, wheres global attributes not.
96
+ #
97
+ def encode_globalattr(name)
98
+ "a$" + @global_attribute_name_generator.get(name.to_s)
99
+ end
100
+
101
+ #
102
+ # Method names and instance variable names use the same generator.
103
+ # They don't clash, as instance variables are prefixed with '@' (not
104
+ # in the Javascript code, but in the Parse tree from Ruby). That's why
105
+ # a different symbol name is generated.
106
+ #
107
+ def encode_method(name)
108
+ "$" + @method_and_ivar_name_generator.get(name.to_s)
109
+ end
110
+
111
+ def reverse_lookup_method_name(encoded_name)
112
+ raise unless encoded_name[0,1] == "$"
113
+ @method_and_ivar_name_generator.reverse_lookup(encoded_name[1..-1])
114
+ end
115
+
116
+ def all_method_names
117
+ @method_and_ivar_name_generator.cache.each_pair do |k,v|
118
+ yield(k, "$" + v) if k[0,1] != '@'
119
+ end
120
+ end
121
+
122
+ def encode_instance_variable(name)
123
+ raise unless name.to_s[0,1] == '@'
124
+ "$" + @method_and_ivar_name_generator.get(name.to_s)
125
+ end
126
+
127
+ def encode_local_variable(name)
128
+ "_" + @local_name_generator.get(name.to_s)
129
+ end
130
+
131
+ def encode_fresh_local_variable
132
+ "_" + @local_name_generator.fresh()
133
+ end
134
+
135
+ #
136
+ # Interpolate a string that contains #<...> expressions.
137
+ #
138
+ # Supported expressions:
139
+ #
140
+ # #<method()> # => encode_method("method")
141
+ # #<self> # => encode_self()
142
+ # #<nil> # => encode_nil()
143
+ # #<@ivar> # => encode_instance_variable("@ivar")
144
+ # #<Constant> # => encode_constant("Constant")
145
+ # #<attr:name> # => encode_attr("name")
146
+ # #<globalattr:name> # => encode_globalattr("name")
147
+ # #<variable> # => encode_local_variable("variable")
148
+ #
149
+ # FIXME: You can't interpolate methods like ">" yet.
150
+ #
151
+ def interpolate(str)
152
+ str = str.gsub(/#<(.*?)>/) {
153
+ case s = $1.strip
154
+ when /^(\w+)\(\)$/ then encode_method($1)
155
+ when /^m:(.+)$/ then encode_method($1)
156
+ when /^self$/ then encode_self()
157
+ when /^nil$/ then encode_nil()
158
+ when /^(@\w+)$/ then encode_instance_variable($1)
159
+ when /^(\$.+)$/ then encode_global_variable($1)
160
+ when /^([A-Z]\w*)$/ then encode_constant($1)
161
+ when /^attr:(\w+)$/ then encode_attr($1)
162
+ when /^globalattr:(\w+)$/ then encode_globalattr($1)
163
+ when /^([a-z_]\w*)$/ then encode_local_variable($1)
164
+ else
165
+ raise s
166
+ end
167
+ }
168
+ return str
169
+ end
170
+
171
+ end
@@ -0,0 +1,59 @@
1
+ #
2
+ # Evals into the given module_scope.
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ def eval_into(module_scope, &block)
9
+ $RUBYJS__MODULE_SCOPE = module_scope
10
+ $RUBYJS__LOADED ||= [] # avoids recursive loads
11
+
12
+ $RUBYJS__EVAL = proc {|str|
13
+ $RUBYJS__MODULE_SCOPE.module_eval(str)
14
+ }
15
+
16
+ # install "require" handler
17
+ alias old_require require
18
+ def require(file)
19
+ ($RUBYJS__LOAD_PATH||['.']).each do |path|
20
+ name = File.expand_path(File.join(path, file + ".rb"))
21
+ if File.exists?(name)
22
+ if $RUBYJS__LOADED.include?(name)
23
+ return false
24
+ else
25
+ $RUBYJS__LOADED << name
26
+ STDERR.puts "loading file: #{name}" if $DEBUG
27
+ $RUBYJS__EVAL.call(File.read(name))
28
+
29
+ #
30
+ # load also platform specific file
31
+ # load first matching platform
32
+ #
33
+
34
+ ($RUBYJS__PLATFORM||[]).each do |plat|
35
+ plat_name = File.expand_path(File.join(path, file + "." + plat + ".rb"))
36
+ next unless File.exists?(plat_name)
37
+ unless $RUBYJS__LOADED.include?(plat_name)
38
+ $RUBYJS__LOADED << plat_name
39
+ STDERR.puts "loading platform specific file: #{plat_name}" if $DEBUG
40
+ $RUBYJS__EVAL.call(File.read(plat_name))
41
+ break
42
+ end
43
+ end
44
+
45
+ return true
46
+ end
47
+ else
48
+ next
49
+ end
50
+ end
51
+ raise ::RuntimeError, "require: #{file} not found"
52
+ end
53
+
54
+
55
+ block.call($RUBYJS__EVAL)
56
+
57
+ # change "require" handler back to original
58
+ alias require old_require
59
+ end
@@ -0,0 +1,1016 @@
1
+ #
2
+ # Core classes for the Javascript side
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ class Proc
9
+ OBJECT_CONSTRUCTOR__ = "Function"
10
+
11
+ def self.new(&block)
12
+ raise ArgumentError, "tried to create Proc object without a block" unless block
13
+ #
14
+ # wrap block inside another function, that catches iter_break returns.
15
+ #
16
+ `return (function() {
17
+ try {
18
+ return #<block>.#<m:call>.apply(#<block>, arguments);
19
+ } catch(e)
20
+ {
21
+ if (e instanceof #<globalattr:iter_jump>)
22
+ {
23
+ if (e.#<attr:scope> == null)
24
+ {`
25
+ raise LocalJumpError, "break from proc-closure"
26
+ `}
27
+ return e.#<attr:return_value>;
28
+ }
29
+ else throw(e);
30
+ }
31
+ })`
32
+ end
33
+
34
+ def call(*args) `
35
+ // TODO: use switch/case
36
+ if (#<args>.length == 0) return #<self>();
37
+ else if (#<args>.length == 1) return #<self>(#<args>[0]);
38
+ else return #<self>(#<args>);`
39
+ end
40
+ end
41
+
42
+ class Boolean
43
+ OBJECT_CONSTRUCTOR__ = "Boolean"
44
+
45
+ class << self
46
+ undef_method :new
47
+ undef_method :allocate
48
+ end
49
+
50
+ def to_s
51
+ `return (#<self> == true ? 'true' : 'false')`
52
+ end
53
+
54
+ def ==(obj)
55
+ `return (#<self> == #<obj>)`
56
+ end
57
+
58
+ =begin
59
+ def &(other)
60
+ `return (#<self> == true ? (#<other>!==#<nil> ...`
61
+ end
62
+ =end
63
+
64
+ alias inspect to_s
65
+ end
66
+
67
+ class NilClass
68
+ OBJECT_CONSTRUCTOR__ = "NilClass"
69
+
70
+ class << self
71
+ undef_method :new
72
+ undef_method :allocate
73
+ end
74
+
75
+ def nil?
76
+ true
77
+ end
78
+
79
+ def to_s
80
+ ""
81
+ end
82
+
83
+ def to_i
84
+ 0
85
+ end
86
+
87
+ def to_f
88
+ 0.0
89
+ end
90
+
91
+ def to_a
92
+ []
93
+ end
94
+
95
+ def to_splat
96
+ []
97
+ end
98
+
99
+ def inspect
100
+ "nil"
101
+ end
102
+ end
103
+
104
+ class Class
105
+ def allocate
106
+ `return (new #<self>.#<attr:object_constructor>())`
107
+ end
108
+
109
+ def new(*args, &block)
110
+ obj = allocate()
111
+ obj.initialize(*args, &block)
112
+ obj
113
+ end
114
+
115
+ def ===(other)
116
+ eql?(other) or other.kind_of?(self)
117
+ end
118
+
119
+ def name
120
+ `return #<self>.#<attr:classname>`
121
+ end
122
+
123
+ def instance_methods
124
+ allocate.methods
125
+ end
126
+
127
+ alias inspect name
128
+
129
+ def self.new(superclass, classname, object_constructor=nil)
130
+ unless object_constructor
131
+ object_constructor = `(function() {})`
132
+ end
133
+ `return new #<self>.#<attr:object_constructor>(#<Class>, #<superclass>, #<classname>, #<object_constructor>);`
134
+ end
135
+ end
136
+
137
+ module Kernel
138
+ def nil?
139
+ false
140
+ end
141
+
142
+ def loop
143
+ while true
144
+ yield
145
+ end
146
+ end
147
+
148
+ def puts(str)
149
+ str = str.to_s
150
+ `alert(#<str>); return #<nil>`
151
+ end
152
+
153
+ def p(*args)
154
+ args.each do |arg|
155
+ puts arg.inspect
156
+ end
157
+ nil
158
+ end
159
+
160
+ def method_missing(id, *args, &block)
161
+ raise NoMethodError, "undefined method `#{id}' for #{self.inspect}"
162
+ end
163
+
164
+ # id is a Javascript name, e.g. $aaa
165
+ def __invoke(id, args, &block) `
166
+ var m = #<self>[#<id>];
167
+ if (m)
168
+ return m.apply(#<self>, [#<block>].concat(#<args>));
169
+ else
170
+ return #<self>.#<m:method_missing>.apply(#<self>,
171
+ [#<block>].concat([#<globalattr:mm>[#<id>]]).concat(#<args>));`
172
+ end
173
+
174
+ # NOTE: In Ruby __send is __send__
175
+ def __send(id, *args, &block) `
176
+ var m = #<self>[#<globalattr:mm_reverse>[#<id>]];
177
+ if (m)
178
+ return m.apply(#<self>, [#<block>].concat(#<args>));
179
+ else
180
+ return #<self>.#<m:method_missing>.apply(#<self>, [#<block>].concat([#<id>]).concat(#<args>));`
181
+ end
182
+ alias send __send
183
+
184
+ def respond_to?(id) `
185
+ var m = #<globalattr:mm_reverse>[#<id>];
186
+ return (m !== undefined && #<self>[m] !== undefined && !#<self>[m].#<attr:_mm>)`
187
+ end
188
+
189
+ def proc(&block)
190
+ Proc.new(&block)
191
+ end
192
+
193
+ def raise(*args)
194
+ ex =
195
+ if args.empty?
196
+ RuntimeError.new("")
197
+ else
198
+ first = args.shift
199
+ if first.kind_of?(Class) # FIXME: subclass of Exception
200
+ first.new(*args)
201
+ elsif first.instance_of?(Exception)
202
+ if args.empty?
203
+ first
204
+ else
205
+ ArgumentError.new("to many arguments given to raise")
206
+ end
207
+ elsif first.instance_of?(String)
208
+ if args.empty?
209
+ RuntimeError.new(first)
210
+ else
211
+ ArgumentError.new("to many arguments given to raise")
212
+ end
213
+ else
214
+ TypeError.new("exception class/object expected")
215
+ end
216
+ end
217
+
218
+ `throw(#<ex>)`
219
+ end
220
+ end
221
+
222
+ class Object
223
+ include Kernel
224
+
225
+ def eql?(other)
226
+ `return (#<self>.constructor == #<other>.constructor && #<self> == #<other>)`
227
+ end
228
+
229
+ def ===(other)
230
+ eql?(other) or kind_of?(other)
231
+ end
232
+
233
+ def instance_of?(klass)
234
+ `return (#<self>.#<attr:_class> === #<klass>)`
235
+ end
236
+
237
+ def kind_of?(klass)
238
+ `return #<globalattr:kind_of>(#<self>, #<klass>)`
239
+ end
240
+ alias is_a? kind_of?
241
+
242
+ # Ruby 1.9
243
+ def tap
244
+ yield self
245
+ self
246
+ end
247
+
248
+ def initialize
249
+ end
250
+
251
+ def class
252
+ `return #<self>.#<attr:_class>`
253
+ end
254
+
255
+ def to_s
256
+ `return #<self>.toString()`
257
+ end
258
+
259
+ alias inspect to_s
260
+ alias hash to_s
261
+
262
+ def methods
263
+ methods = [];
264
+ `for (meth in #<self>) {
265
+ if (typeof #<self>[meth] == "function") {
266
+ #<methods>.push(#<globalattr:mm>[meth]);
267
+ }
268
+ }`
269
+ methods
270
+ end
271
+
272
+ def method(id)
273
+ Method.new(self, id)
274
+ end
275
+ end
276
+
277
+ class Method
278
+ def initialize(object, method_id)
279
+ @object, @method_id = object, method_id
280
+
281
+ m = nil
282
+ `#<m> = #<object>[#<globalattr:mm_reverse>[#<method_id>]];
283
+ if (#<m>==null) #<m> = #<nil>;`
284
+ if m
285
+ @method = m
286
+ else
287
+ raise NameError, "undefined method `#{method_id}' for class `#{object.class.name}'"
288
+ end
289
+ end
290
+
291
+ def call(*args, &block)
292
+ `return #<self>.#<@method>.apply(#<self>.#<@object>, [#<block>].concat(#<args>))`
293
+ end
294
+
295
+ def inspect
296
+ "#<Method: #{@object.class.name}##{@method_id}>"
297
+ end
298
+ end
299
+
300
+ module Enumerable
301
+ def map(&block)
302
+ result = []
303
+ each {|elem| result << (block ? block.call(elem) : elem) }
304
+ result
305
+ end
306
+ alias collect map
307
+
308
+ def select
309
+ result = []
310
+ each {|elem|
311
+ if yield(elem)
312
+ result << elem
313
+ end
314
+ }
315
+ result
316
+ end
317
+ alias find_all select
318
+
319
+ def reject
320
+ result = []
321
+ each {|elem|
322
+ unless yield(elem)
323
+ result << elem
324
+ end
325
+ }
326
+ result
327
+ end
328
+
329
+ def to_a
330
+ result = []
331
+ each {|elem| result << elem}
332
+ result
333
+ end
334
+ end
335
+
336
+ class Range
337
+ def initialize(first, last, exclude_last=false)
338
+ @first, @last = first, last
339
+ @exclude_last = exclude_last ? true : false
340
+ end
341
+
342
+ def exclude_end?
343
+ @exclude_last
344
+ end
345
+
346
+ def first
347
+ @first
348
+ end
349
+ alias begin first
350
+
351
+ def last
352
+ @last
353
+ end
354
+ alias end last
355
+
356
+ def ==(obj)
357
+ `if (#<self>.constructor != #<obj>.constructor) return false;`
358
+ @first == obj.first and @last == obj.last and @exclude_last == obj.exclude_end?
359
+ end
360
+
361
+ def eql?(obj)
362
+ `if (#<self>.constructor != #<obj>.constructor) return false;`
363
+ @first.eql?(obj.first) and @last.eql?(obj.last) and @exclude_last == obj.exclude_end?
364
+ end
365
+
366
+ def include?(obj)
367
+ return false if obj < @first
368
+ if @exclude_last
369
+ obj < @last
370
+ else
371
+ obj <= @last
372
+ end
373
+ end
374
+
375
+ alias member? include?
376
+ alias === include?
377
+
378
+ def each
379
+ current = @first
380
+ return if @first > @last
381
+ if @exclude_last
382
+ while current < @last
383
+ yield current
384
+ current = current.succ
385
+ end
386
+ else
387
+ while current <= @last
388
+ yield current
389
+ current = current.succ
390
+ end
391
+ end
392
+ end
393
+
394
+ def to_a
395
+ arr = []
396
+ return arr if @first > @last
397
+ current = @first
398
+ if @exclude_last
399
+ while current < @last
400
+ arr << current
401
+ current = current.succ
402
+ end
403
+ else
404
+ while current <= @last
405
+ arr << current
406
+ current = current.succ
407
+ end
408
+ end
409
+ return arr
410
+ end
411
+
412
+ def to_s
413
+ if @exclude_last
414
+ "#{@first}...#{@last}"
415
+ else
416
+ "#{@first}..#{@last}"
417
+ end
418
+ end
419
+
420
+ def inspect
421
+ if @exclude_last
422
+ "#{@first.inspect}...#{@last.inspect}"
423
+ else
424
+ "#{@first.inspect}..#{@last.inspect}"
425
+ end
426
+ end
427
+
428
+ end
429
+
430
+ class Exception
431
+ attr_reader :message
432
+ def initialize(message=nil)
433
+ if message.nil?
434
+ @message = self.class.name
435
+ else
436
+ @message = message
437
+ end
438
+ end
439
+ alias to_s message
440
+
441
+ def inspect
442
+ "#<#{self.class.name}: #{@message}>"
443
+ end
444
+ end
445
+
446
+ class StandardError < Exception; end
447
+ class NameError < StandardError; end
448
+ class NoMethodError < NameError; end
449
+ class RuntimeError < StandardError; end
450
+ class ArgumentError < StandardError; end
451
+ class TypeError < StandardError; end
452
+ class LocalJumpError < StandardError; end
453
+
454
+ #
455
+ # NOTE: Strings in RubyJS are immutable!!!
456
+ #
457
+ class String
458
+ OBJECT_CONSTRUCTOR__ = "String"
459
+
460
+ def +(str)
461
+ `return(#<self> + #<str>)`
462
+ end
463
+
464
+ def empty?
465
+ `return(#<self> === "")`
466
+ end
467
+
468
+ def rjust(len, pad=" ")
469
+ raise ArgumentError, "zero width padding" if pad.empty?
470
+
471
+ n = len - self.length
472
+ return self if n <= 0
473
+
474
+ fillstr = ""
475
+ `while(#<fillstr>.length < #<n>) #<fillstr> += #<pad>;`
476
+
477
+ return fillstr[0,n] + self
478
+ end
479
+
480
+ def ljust(len, pad=" ")
481
+ raise ArgumentError, "zero width padding" if pad.empty?
482
+
483
+ n = len - self.length
484
+ return self if n <= 0
485
+
486
+ fillstr = ""
487
+ `while(#<fillstr>.length < #<n>) #<fillstr> += #<pad>;`
488
+
489
+ return self + fillstr[0,n]
490
+ end
491
+
492
+ def inspect
493
+ # prototype.js
494
+ specialChar = `{
495
+ '\\b': '\\\\b',
496
+ '\\t': '\\\\t',
497
+ '\\n': '\\\\n',
498
+ '\\f': '\\\\f',
499
+ '\\r': '\\\\r',
500
+ '\\\\': '\\\\\\\\'
501
+ };`
502
+
503
+ escapedString = self.gsub(/[\x00-\x1f\\]/) {|match|
504
+ character = `#<specialChar>[#<match>]`
505
+ `return #<character> ? #<character> :
506
+ '\\\\u00' + ("0" + #<match>.charCodeAt().toString(16)).substring(0,2);`
507
+ }
508
+
509
+ `return ('"' + #<escapedString>.replace(/"/g, '\\\\"') + '"');`
510
+ end
511
+
512
+ def to_s
513
+ self
514
+ end
515
+
516
+ def strip
517
+ `return #<self>.replace(/^\\s+/, '').replace(/\\s+$/, '')`
518
+ end
519
+
520
+ def split(str)
521
+ `return #<self>.split(#<str>)`
522
+ end
523
+
524
+ def length
525
+ `return #<self>.length`
526
+ end
527
+ alias size length
528
+
529
+ def index(substring, offset=0) `
530
+ var i = #<self>.indexOf(#<substring>, #<offset>);
531
+ return (i == -1) ? #<nil> : i`
532
+ end
533
+
534
+ def =~(pattern) `
535
+ var i = #<self>.search(#<pattern>);
536
+ return (i == -1 ? #<nil> : i)`
537
+ end
538
+
539
+ def gsub(pattern, replacement=nil)
540
+ # from prototype.js
541
+ result, source, match = "", self, nil
542
+ `while(#<source>.length > 0) {
543
+ if (#<match> = #<source>.match(#<pattern>)) {
544
+ #<result> += #<source>.slice(0, #<match>.index);`
545
+ if replacement
546
+ result += replacement
547
+ else
548
+ result += yield(match.first).to_s
549
+ end
550
+ `#<source> = #<source>.slice(#<match>.index + #<match>[0].length);
551
+ } else {
552
+ #<result> += #<source>; #<source> = '';
553
+ }
554
+ } return #<result>`
555
+ end
556
+
557
+ def sub(pattern, replacement)
558
+ # FIXME: block
559
+ `#<self>.replace(pattern, replacement)`
560
+ end
561
+
562
+ def [](index, len=nil)
563
+ if len.nil?
564
+ # single character access
565
+ # FIXME: returns a string and not a Fixnum!
566
+ # But: Ruby 1.9+ has this behaviour!!!
567
+ `return #<self>.charAt(#<index>) || #<nil>`
568
+ else
569
+ # substring access
570
+ return nil if len < 0
571
+ `return #<self>.substring(#<index>, #<index>+#<len>)`
572
+ end
573
+ end
574
+ end
575
+
576
+ class Number
577
+ OBJECT_CONSTRUCTOR__ = "Number"
578
+
579
+ class << self
580
+ undef_method :new
581
+ undef_method :allocate
582
+ end
583
+
584
+ def to_s(base=10)
585
+ `return #<self>.toString(#<base>)`
586
+ end
587
+
588
+ def inspect
589
+ `return #<self>.toString()`
590
+ end
591
+
592
+ def +(x) `return #<self> + #<x>` end
593
+ def -(x) `return #<self> - #<x>` end
594
+ def -@() `return -#<self>` end
595
+ def +@() `return #<self>` end
596
+ def *(x) `return #<self> * #<x>` end
597
+ def /(x) `return #<self> / #<x>` end
598
+ def <(x) `return #<self> < #<x>` end
599
+ def <=(x) `return #<self> <= #<x>` end
600
+ def >(x) `return #<self> > #<x>` end
601
+ def >=(x) `return #<self> >= #<x>` end
602
+ def ==(x) `return #<self> == #<x>` end
603
+ def %(x) `return #<self> % #<x>` end
604
+ def |(x) `return #<self> | #<x>` end
605
+ def &(x) `return #<self> & #<x>` end
606
+ def ^(x) `return #<self> ^ #<x>` end
607
+ def ~() `return ~#<self>` end
608
+
609
+ def succ() `return #<self>+1` end
610
+
611
+ def times
612
+ i = 0
613
+ while i < self
614
+ yield i
615
+ i += 1
616
+ end
617
+ return self
618
+ end
619
+
620
+ def downto(x)
621
+ i = self
622
+ while i >= x
623
+ yield i
624
+ i -= 1
625
+ end
626
+ return self
627
+ end
628
+
629
+ def upto(x)
630
+ i = self
631
+ while i <= x
632
+ yield i
633
+ i += 1
634
+ end
635
+ return self
636
+ end
637
+
638
+ end
639
+
640
+ # for compatibility
641
+ class Fixnum < Number; end
642
+ class Bignum < Number; end
643
+ class Float < Number; end
644
+
645
+ #
646
+ # Every method that returns an element has to
647
+ # check this element for +null+. This is required
648
+ # to seamlessly use Javascript data without needing
649
+ # to convert it before usage.
650
+ #
651
+ # The reverse, passing a RubyJS Array to Javascript
652
+ # without conversion of +nil+ to +null+ is of course
653
+ # not possible!
654
+ #
655
+ # NOTE: Following condition holds true:
656
+ # v == null <=> v=null || v=undefined
657
+ #
658
+ class Array
659
+ OBJECT_CONSTRUCTOR__ = "Array"
660
+
661
+ include Enumerable
662
+
663
+ def each() `
664
+ var elem;
665
+ for (var i=0; i < #<self>.length; i++) {
666
+ elem = #<self>[i];`
667
+ yield `(elem == null ? #<nil> : elem)`
668
+ `}
669
+ return #<self>`
670
+ end
671
+
672
+ def each_with_index() `
673
+ var elem;
674
+ for (var i=0; i < #<self>.length; i++) {
675
+ elem = #<self>[i];`
676
+ yield `(elem == null ? #<nil> : elem)`, `i`
677
+ `}
678
+ return #<self>`
679
+ end
680
+
681
+ def join(sep="")
682
+ str = ""
683
+ self.each_with_index {|elem, i|
684
+ str += elem.to_s
685
+ str += sep if i != self.length-1
686
+ }
687
+ str
688
+ end
689
+
690
+ def to_a
691
+ self
692
+ end
693
+
694
+ def to_ary
695
+ self
696
+ end
697
+
698
+ def self.new
699
+ `return []`
700
+ end
701
+
702
+ # TODO: test that otherArray is array
703
+ def +(otherArray)
704
+ `return #<self>.concat(#<otherArray>)`
705
+ end
706
+
707
+ def dup
708
+ `return #<self>.concat()`
709
+ end
710
+
711
+ def reverse
712
+ `return #<self>.concat().reverse()`
713
+ end
714
+
715
+ def reverse!
716
+ `#<self>.reverse(); return #<self>`
717
+ end
718
+
719
+ def length
720
+ `return #<self>.length`
721
+ end
722
+
723
+ alias size length
724
+
725
+ def first
726
+ `var v = #<self>[0]; return (v == null ? #<nil> : v)`
727
+ end
728
+
729
+ def last
730
+ `var v = #<self>[#<self>.length - 1]; return (v == null ? #<nil> : v)`
731
+ end
732
+
733
+ def clear
734
+ `#<self>.length=0; return #<self>`
735
+ end
736
+
737
+ # TODO: check arrary bounds
738
+ def [](i)
739
+ `var v = #<self>[#<i>]; return (v == null ? #<nil> : v)`
740
+ end
741
+
742
+ def []=(i, val)
743
+ `return (#<self>[#<i>] = #<val>)`
744
+ end
745
+
746
+ def push(*args)
747
+ `#<self>.push.apply(#<self>, #<args>); return #<self>`
748
+ end
749
+
750
+ def <<(arg)
751
+ `#<self>.push(#<arg>); return #<self>`
752
+ end
753
+
754
+ def pop() `
755
+ var elem = #<self>.pop();
756
+ return (elem == null ? #<nil> : elem)`
757
+ end
758
+
759
+ def shift() `
760
+ var elem = #<self>.shift();
761
+ return (elem == null ? #<nil> : elem)`
762
+ end
763
+
764
+ def delete(obj) `
765
+ var del = false;
766
+ for (var i=0; i < #<self>.length; i++)
767
+ {
768
+ if (#<obj>.#<m:eql?>(#<nil>, #<self>[i]))
769
+ {
770
+ #<self>.splice(i,1);
771
+ del = true;
772
+ // stay at the current index unless we are at the last element!
773
+ if (i < #<self>.length-1) --i;
774
+ }
775
+ }
776
+ return del ? #<obj> : #<nil>`
777
+ end
778
+
779
+ def unshift(*args)
780
+ `#<self>.unshift.apply(#<self>, #<args>); return #<self>`
781
+ end
782
+
783
+ def empty?
784
+ `return (#<self>.length == 0)`
785
+ end
786
+
787
+ def to_s
788
+ map {|i| i.to_s}.join
789
+ end
790
+
791
+ def ==(obj)
792
+ self.eql?(obj)
793
+ end
794
+
795
+ def inspect
796
+ str = "["
797
+ str += self.map {|elem| elem.inspect}.join(", ")
798
+ str += "]"
799
+ str
800
+ end
801
+
802
+ def eql?(other)
803
+ each_with_index do |elem, i|
804
+ return false unless elem.eql? other[i]
805
+ end
806
+ end
807
+
808
+ def include?(candidate)
809
+ each do |elem|
810
+ return true if elem.eql?(candidate)
811
+ end
812
+ false
813
+ end
814
+ end
815
+
816
+ class Regexp
817
+ OBJECT_CONSTRUCTOR__ = "RegExp"
818
+ end
819
+
820
+ class MatchData
821
+ def initialize(match)
822
+ @match = match
823
+ end
824
+ end
825
+
826
+ #
827
+ # We prefix every element by a ":"
828
+ #
829
+ class Hash
830
+ include Enumerable
831
+
832
+ #
833
+ # Construct an empty Hash
834
+ #
835
+ def initialize() `
836
+ #<self>.#<attr:items> = {};
837
+ #<self>.#<attr:default_value> = #<nil>;
838
+ return #<nil>`
839
+ end
840
+
841
+ #
842
+ # Construct a Hash from key, value pairs, e.g.
843
+ #
844
+ # Hash.new_from_key_value_list(1,2, 3,4, 5,6)
845
+ #
846
+ # will result in
847
+ #
848
+ # {1 => 2, 3 => 4, 5 => 6}
849
+ #
850
+ def self.new_from_key_value_list(*list)
851
+ raise ArgumentError if list.length % 2 != 0
852
+ obj = allocate()
853
+ `
854
+ //
855
+ // we use an associate array to store the items. But unlike
856
+ // Javascript, the entries are arrays which contain the collisions.
857
+ // NOTE that we have to prefix the hash code with a prefix so that
858
+ // there are no collisions with methods etc.
859
+ // I prefix it for now with ":".
860
+ //
861
+ var items = {};
862
+ var hashed_key, current_key, current_val;
863
+
864
+ for (var i = 0; i < #<list>.length; i += 2)
865
+ {
866
+ current_key = #<list>[i];
867
+ current_val = #<list>[i+1];
868
+ hashed_key = ":" + current_key.#<m:hash>();
869
+
870
+ // make sure that a bucket exists
871
+ if (!items[hashed_key]) items[hashed_key] = [];
872
+
873
+ items[hashed_key].push(current_key, current_val);
874
+ }
875
+
876
+ #<obj>.#<attr:items> = items;
877
+ #<obj>.#<attr:default_value> = #<nil>;
878
+ return #<obj>;
879
+ `
880
+ end
881
+
882
+ def self.new_from_jsobject(jsobj)
883
+ obj = new()
884
+ end
885
+
886
+ def [](key) `
887
+ if (!#<self>.#<attr:items>)
888
+ {
889
+ // this is a Javascript Object, not a RubyJS Hash object.
890
+ // we directly look the key up. it's fast but not Ruby-like,
891
+ // so be careful!
892
+
893
+ var elem = #<self>[#<key>];
894
+ return (elem == null ? #<nil> : elem);
895
+ }
896
+
897
+ var hashed_key = ":" + #<key>.#<m:hash>();
898
+ var bucket = #<self>.#<attr:items>[hashed_key];
899
+
900
+ if (bucket)
901
+ {
902
+ //
903
+ // find the matching element inside the bucket
904
+ //
905
+
906
+ for (var i = 0; i < bucket.length; i += 2)
907
+ {
908
+ if (bucket[i].#<m:eql?>(#<nil>,#<key>))
909
+ return bucket[i+1];
910
+ }
911
+ }
912
+
913
+ // no matching key found -> return default value
914
+ return #<self>.#<attr:default_value>;
915
+ `
916
+ end
917
+
918
+ def []=(key, value) `
919
+ if (!#<self>.#<attr:items>)
920
+ {
921
+ // this is a Javascript Object, not a RubyJS Hash object.
922
+ // we directly look the key up. it's fast but not Ruby-like,
923
+ // so be careful!
924
+
925
+ #<self>[#<key>] = #<value>;
926
+ return #<value>;
927
+ }
928
+
929
+ var hashed_key = ":" + #<key>.#<m:hash>();
930
+ var bucket = #<self>.#<attr:items>[hashed_key];
931
+
932
+ if (bucket)
933
+ {
934
+ //
935
+ // find the matching element inside the bucket
936
+ //
937
+
938
+ for (var i = 0; i < bucket.length; i += 2)
939
+ {
940
+ if (bucket[i].#<m:eql?>(#<nil>,#<key>))
941
+ {
942
+ // overwrite value
943
+ bucket[i+1] = #<value>;
944
+ return #<value>;
945
+ }
946
+ }
947
+ // key not found in this bucket. append key, value pair to bucket
948
+ bucket.push(#<key>, #<value>);
949
+ }
950
+ else
951
+ {
952
+ //
953
+ // create new bucket
954
+ //
955
+ #<self>.#<attr:items>[hashed_key] = [#<key>, #<value>];
956
+ }
957
+ return #<value>;
958
+ `
959
+ end
960
+
961
+ def keys
962
+ map {|k,v| k}
963
+ end
964
+
965
+ def values
966
+ map {|k,v| v}
967
+ end
968
+
969
+ def each() `
970
+ if (!#<self>.#<attr:items>)
971
+ {
972
+ // this is a Javascript Object, not a RubyJS Hash object.
973
+ // we directly look the key up. it's fast but not Ruby-like,
974
+ // so be careful!
975
+ var key, value;
976
+ for (key in #<self>)
977
+ {
978
+ value = #<self>[key];`
979
+ yield `(key == null ? #<nil> : key)`, `(value == null ? #<nil> : value)`;
980
+ `
981
+ }
982
+
983
+ return #<nil>;
984
+ }
985
+
986
+ var key, bucket, i;
987
+ for (key in #<self>.#<attr:items>)
988
+ {
989
+ if (key.charAt(0) == ":")
990
+ {
991
+ bucket = #<self>.#<attr:items>[key];
992
+ for (i=0; i<bucket.length; i+=2)
993
+ {`
994
+ yield `bucket[i]`, `bucket[i+1]`
995
+ `
996
+ }
997
+ }
998
+ }
999
+ return #<nil>;
1000
+ `
1001
+ end
1002
+
1003
+ def inspect
1004
+ str = "{"
1005
+ str += map {|k, v| (k.inspect + "=>" + v.inspect) }.join(", ")
1006
+ str += "}"
1007
+ str
1008
+ end
1009
+
1010
+ def to_s
1011
+ strs = []
1012
+ each {|k, v| strs << k; strs << v}
1013
+ strs.join("")
1014
+ end
1015
+
1016
+ end