therubyracer-discourse 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +11 -0
  4. data/Changelog.md +247 -0
  5. data/Gemfile +9 -0
  6. data/README.md +176 -0
  7. data/Rakefile +42 -0
  8. data/benchmarks.rb +218 -0
  9. data/ext/v8/accessor.cc +181 -0
  10. data/ext/v8/array.cc +26 -0
  11. data/ext/v8/backref.cc +45 -0
  12. data/ext/v8/constants.cc +34 -0
  13. data/ext/v8/constraints.cc +52 -0
  14. data/ext/v8/context.cc +130 -0
  15. data/ext/v8/date.cc +18 -0
  16. data/ext/v8/exception.cc +38 -0
  17. data/ext/v8/extconf.rb +34 -0
  18. data/ext/v8/external.cc +43 -0
  19. data/ext/v8/function.cc +58 -0
  20. data/ext/v8/gc.cc +43 -0
  21. data/ext/v8/handles.cc +34 -0
  22. data/ext/v8/heap.cc +35 -0
  23. data/ext/v8/init.cc +39 -0
  24. data/ext/v8/invocation.cc +86 -0
  25. data/ext/v8/locker.cc +77 -0
  26. data/ext/v8/message.cc +51 -0
  27. data/ext/v8/object.cc +335 -0
  28. data/ext/v8/primitive.cc +8 -0
  29. data/ext/v8/rr.cc +83 -0
  30. data/ext/v8/rr.h +934 -0
  31. data/ext/v8/script.cc +115 -0
  32. data/ext/v8/signature.cc +18 -0
  33. data/ext/v8/stack.cc +76 -0
  34. data/ext/v8/string.cc +47 -0
  35. data/ext/v8/template.cc +175 -0
  36. data/ext/v8/trycatch.cc +87 -0
  37. data/ext/v8/v8.cc +87 -0
  38. data/ext/v8/value.cc +239 -0
  39. data/lib/v8.rb +30 -0
  40. data/lib/v8/access.rb +5 -0
  41. data/lib/v8/access/indices.rb +40 -0
  42. data/lib/v8/access/invocation.rb +47 -0
  43. data/lib/v8/access/names.rb +65 -0
  44. data/lib/v8/array.rb +26 -0
  45. data/lib/v8/context.rb +256 -0
  46. data/lib/v8/conversion.rb +36 -0
  47. data/lib/v8/conversion/array.rb +11 -0
  48. data/lib/v8/conversion/class.rb +119 -0
  49. data/lib/v8/conversion/code.rb +38 -0
  50. data/lib/v8/conversion/fixnum.rb +11 -0
  51. data/lib/v8/conversion/fundamental.rb +11 -0
  52. data/lib/v8/conversion/hash.rb +11 -0
  53. data/lib/v8/conversion/indentity.rb +31 -0
  54. data/lib/v8/conversion/method.rb +26 -0
  55. data/lib/v8/conversion/object.rb +28 -0
  56. data/lib/v8/conversion/primitive.rb +7 -0
  57. data/lib/v8/conversion/proc.rb +5 -0
  58. data/lib/v8/conversion/reference.rb +16 -0
  59. data/lib/v8/conversion/string.rb +12 -0
  60. data/lib/v8/conversion/symbol.rb +7 -0
  61. data/lib/v8/conversion/time.rb +13 -0
  62. data/lib/v8/error.rb +169 -0
  63. data/lib/v8/function.rb +28 -0
  64. data/lib/v8/object.rb +79 -0
  65. data/lib/v8/stack.rb +85 -0
  66. data/lib/v8/version.rb +3 -0
  67. data/lib/v8/weak.rb +73 -0
  68. data/spec/c/array_spec.rb +17 -0
  69. data/spec/c/constants_spec.rb +20 -0
  70. data/spec/c/exception_spec.rb +26 -0
  71. data/spec/c/external_spec.rb +9 -0
  72. data/spec/c/function_spec.rb +46 -0
  73. data/spec/c/handles_spec.rb +35 -0
  74. data/spec/c/locker_spec.rb +38 -0
  75. data/spec/c/object_spec.rb +46 -0
  76. data/spec/c/script_spec.rb +28 -0
  77. data/spec/c/string_spec.rb +16 -0
  78. data/spec/c/template_spec.rb +30 -0
  79. data/spec/c/trycatch_spec.rb +51 -0
  80. data/spec/mem/blunt_spec.rb +42 -0
  81. data/spec/redjs_spec.rb +10 -0
  82. data/spec/spec_helper.rb +45 -0
  83. data/spec/threading_spec.rb +64 -0
  84. data/spec/v8/context_spec.rb +19 -0
  85. data/spec/v8/conversion_spec.rb +52 -0
  86. data/spec/v8/error_spec.rb +165 -0
  87. data/spec/v8/function_spec.rb +9 -0
  88. data/spec/v8/object_spec.rb +15 -0
  89. data/thefrontside.png +0 -0
  90. data/therubyracer.gemspec +21 -0
  91. metadata +163 -0
@@ -0,0 +1,65 @@
1
+ require 'set'
2
+ class V8::Access
3
+ module Names
4
+ def names(obj)
5
+ accessible_names(obj)
6
+ end
7
+
8
+ def get(obj, name, &dontintercept)
9
+ methods = accessible_names(obj)
10
+ if methods.include?(name)
11
+ method = obj.method(name)
12
+ method.arity == 0 ? method.call : method.unbind
13
+ elsif obj.respond_to?(:[]) && !special?(name)
14
+ obj.send(:[], name, &dontintercept)
15
+ else
16
+ yield
17
+ end
18
+ end
19
+
20
+ def set(obj, name, value, &dontintercept)
21
+ setter = name + "="
22
+ methods = accessible_names(obj, true)
23
+ if methods.include?(setter)
24
+ obj.send(setter, value)
25
+ elsif obj.respond_to?(:[]=) && !special?(name)
26
+ obj.send(:[]=, name, value, &dontintercept)
27
+ else
28
+ yield
29
+ end
30
+ end
31
+
32
+ def query(obj, name, attributes, &dontintercept)
33
+ if obj.respond_to?(name)
34
+ attributes.dont_delete
35
+ unless obj.respond_to?(name + "=")
36
+ attributes.read_only
37
+ end
38
+ else
39
+ yield
40
+ end
41
+ end
42
+
43
+ def delete(obj, name, &dontintercept)
44
+ yield
45
+ end
46
+
47
+ def accessible_names(obj, special_methods = false)
48
+ obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods|
49
+ ancestors = obj.class.ancestors.dup
50
+ while ancestor = ancestors.shift
51
+ break if ancestor == ::Object
52
+ methods.merge(ancestor.public_instance_methods(false).map {|m| m.to_s})
53
+ end
54
+ methods.reject!(&special?) unless special_methods
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def special?(name = nil)
61
+ @special ||= lambda {|m| m == "[]" || m == "[]=" || m =~ /=$/}
62
+ name.nil? ? @special : @special[name]
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,26 @@
1
+ class V8::Array < V8::Object
2
+
3
+ def initialize(native_or_length = nil)
4
+ super do
5
+ if native_or_length.is_a?(Numeric)
6
+ V8::C::Array::New(native_or_length)
7
+ elsif native_or_length.is_a?(V8::C::Array)
8
+ native_or_length
9
+ else
10
+ V8::C::Array::New()
11
+ end
12
+ end
13
+ end
14
+
15
+ def each
16
+ @context.enter do
17
+ 0.upto(@native.Length() - 1) do |i|
18
+ yield @context.to_ruby(@native.Get(i))
19
+ end
20
+ end
21
+ end
22
+
23
+ def length
24
+ @native.Length()
25
+ end
26
+ end
@@ -0,0 +1,256 @@
1
+ require 'stringio'
2
+ module V8
3
+ # All JavaScript must be executed in a context. This context consists of a global scope containing the
4
+ # standard JavaScript objects¨and functions like Object, String, Array, as well as any objects or
5
+ # functions from Ruby which have been embedded into it from the containing enviroment. E.g.
6
+ #
7
+ # V8::Context.new do |cxt|
8
+ # cxt['num'] = 5
9
+ # cxt.eval('num + 5') #=> 10
10
+ # end
11
+ #
12
+ # The same object may appear in any number of contexts, but only one context may be executing JavaScript code
13
+ # in any given thread. If a new context is opened in a thread in which a context is already opened, the second
14
+ # context will "mask" the old context e.g.
15
+ #
16
+ # six = 6
17
+ # Context.new do |cxt|
18
+ # cxt['num'] = 5
19
+ # cxt.eval('num') # => 5
20
+ # Context.new do |cxt|
21
+ # cxt['num'] = 10
22
+ # cxt.eval('num') # => 10
23
+ # cxt.eval('++num') # => 11
24
+ # end
25
+ # cxt.eval('num') # => 5
26
+ # end
27
+ class Context
28
+ include V8::Error::Try
29
+
30
+ # @!attribute [r] conversion
31
+ # @return [V8::Conversion] conversion behavior for this context
32
+ attr_reader :conversion
33
+
34
+ # @!attrribute [r] access
35
+ # @return [V8::Access] Ruby access behavior for this context
36
+ attr_reader :access
37
+
38
+ # @!attribute [r] native
39
+ # @return [V8::C::Context] the underlying C++ object
40
+ attr_reader :native
41
+
42
+ # maximum execution time for script in milliseconds
43
+ attr_reader :timeout
44
+
45
+ # Creates a new context.
46
+ #
47
+ # If passed the `:with` option, that object will be used as
48
+ # the global scope of the newly creating context. e.g.
49
+ #
50
+ # scope = Object.new
51
+ # def scope.hello; "Hi"; end
52
+ # V8::Context.new(:with => scope) do |cxt|
53
+ # cxt['hello'] #=> 'Hi'
54
+ # end
55
+ #
56
+ # If passed the `:timeout` option, every eval will timeout once
57
+ # N milliseconds elapse
58
+ #
59
+ # @param [Hash<Symbol, Object>] options initial context configuration
60
+ # * :with scope serves as the global scope of the new context
61
+ # @yield [V8::Context] the newly created context
62
+ def initialize(options = {})
63
+ @conversion = Conversion.new
64
+ @access = Access.new
65
+ @timeout = options[:timeout]
66
+ if global = options[:with]
67
+ Context.new.enter do
68
+ global_template = global.class.to_template.InstanceTemplate()
69
+ @native = V8::C::Context::New(nil, global_template)
70
+ end
71
+ enter {link global, @native.Global()}
72
+ else
73
+ V8::C::Locker() do
74
+ @native = V8::C::Context::New()
75
+ end
76
+ end
77
+ yield self if block_given?
78
+ end
79
+
80
+ # Compile and execute a string of JavaScript source.
81
+ #
82
+ # If `source` is an IO object it will be read fully before being evaluated
83
+ #
84
+ # @param [String,IO] source the source code to compile and execute
85
+ # @param [String] filename the name to use for this code when generating stack traces
86
+ # @param [Integer] line the line number to start with
87
+ # @return [Object] the result of the evaluation
88
+ def eval(source, filename = '<eval>', line = 1)
89
+ if IO === source || StringIO === source
90
+ source = source.read
91
+ end
92
+ enter do
93
+ script = try { V8::C::Script::New(source.to_s, filename.to_s) }
94
+ if @timeout
95
+ to_ruby try {script.RunWithTimeout(@timeout)}
96
+ else
97
+ to_ruby try {script.Run()}
98
+ end
99
+ end
100
+ end
101
+
102
+ # Read a value from the global scope of this context
103
+ #
104
+ # @param [Object] key the name of the value to read
105
+ # @return [Object] value the value at `key`
106
+ def [](key)
107
+ enter do
108
+ to_ruby(@native.Global().Get(to_v8(key)))
109
+ end
110
+ end
111
+
112
+ # Binds `value` to the name `key` in the global scope of this context.
113
+ #
114
+ # @param [Object] key the name to bind to
115
+ # @param [Object] value the value to bind
116
+ def []=(key, value)
117
+ enter do
118
+ @native.Global().Set(to_v8(key), to_v8(value))
119
+ end
120
+ return value
121
+ end
122
+
123
+ # Destroy this context and release any internal references it may
124
+ # contain to embedded Ruby objects.
125
+ #
126
+ # A disposed context may never again be used for anything, and all
127
+ # objects created with it will become unusable.
128
+ def dispose
129
+ return unless @native
130
+ @native.Dispose()
131
+ @native = nil
132
+ V8::C::V8::ContextDisposedNotification()
133
+ def self.enter
134
+ fail "cannot enter a context which has already been disposed"
135
+ end
136
+ end
137
+
138
+ # Returns this context's global object. This will be a `V8::Object`
139
+ # if no scope was provided or just an `Object` if a Ruby object
140
+ # is serving as the global scope.
141
+ #
142
+ # @return [Object] scope the context's global scope.
143
+ def scope
144
+ enter { to_ruby @native.Global() }
145
+ end
146
+
147
+ # Converts a v8 C++ object into its ruby counterpart. This is method
148
+ # is used to translate all values passed to Ruby from JavaScript, either
149
+ # as return values or as callback parameters.
150
+ #
151
+ # @param [V8::C::Object] v8_object the native c++ object to convert.
152
+ # @return [Object] to pass to Ruby
153
+ # @see V8::Conversion for how to customize and extend this mechanism
154
+ def to_ruby(v8_object)
155
+ @conversion.to_ruby(v8_object)
156
+ end
157
+
158
+ # Converts a Ruby object into a native v8 C++ object. This method is
159
+ # used to translate all values passed to JavaScript from Ruby, either
160
+ # as return value or as callback parameters.
161
+ #
162
+ # @param [Object] ruby_object the Ruby object to convert
163
+ # @return [V8::C::Object] to pass to V8
164
+ # @see V8::Conversion for customizing and extending this mechanism
165
+ def to_v8(ruby_object)
166
+ @conversion.to_v8(ruby_object)
167
+ end
168
+
169
+ # Marks a Ruby object and a v8 C++ Object as being the same. In other
170
+ # words whenever `ruby_object` is passed to v8, the result of the
171
+ # conversion should be `v8_object`. Conversely, whenever `v8_object`
172
+ # is passed to Ruby, the result of the conversion should be `ruby_object`.
173
+ # The Ruby Racer uses this mechanism to maintain referential integrity
174
+ # between Ruby and JavaScript peers
175
+ #
176
+ # @param [Object] ruby_object the Ruby half of the object identity
177
+ # @param [V8::C::Object] v8_object the V8 half of the object identity.
178
+ # @see V8::Conversion::Identity
179
+ def link(ruby_object, v8_object)
180
+ @conversion.equate ruby_object, v8_object
181
+ end
182
+
183
+ # Links `ruby_object` and `v8_object` inside the currently entered
184
+ # context. This is an error if no context has been entered.
185
+ #
186
+ # @param [Object] ruby_object the Ruby half of the object identity
187
+ # @param [V8::C::Object] v8_object the V8 half of the object identity.
188
+ def self.link(ruby_object, v8_object)
189
+ current.link ruby_object, v8_object
190
+ end
191
+
192
+ # Run some Ruby code in the context of this context.
193
+ #
194
+ # This will acquire the V8 interpreter lock (possibly blocking
195
+ # until it is available), and prepare V8 for JavaScript execution.
196
+ #
197
+ # Only one context may be running at a time per thread.
198
+ #
199
+ # @return [Object] the result of executing `block`
200
+ def enter(&block)
201
+ if !entered?
202
+ lock_scope_and_enter(&block)
203
+ else
204
+ yield
205
+ end
206
+ end
207
+
208
+ # Indicates if this context is the currently entered context
209
+ #
210
+ # @return true if this context is currently entered
211
+ def entered?
212
+ Context.current == self
213
+ end
214
+
215
+ # Get the currently entered context.
216
+ #
217
+ # @return [V8::Context] currently entered context, nil if none entered.
218
+ def self.current
219
+ Thread.current[:v8_context]
220
+ end
221
+
222
+ # Compile and execute the contents of the file with path `filename`
223
+ # as JavaScript code.
224
+ #
225
+ # @param [String] filename path to the file to execute.
226
+ # @return [Object] the result of the evaluation.
227
+ def load(filename)
228
+ File.open(filename) do |file|
229
+ self.eval file, filename
230
+ end
231
+ end
232
+
233
+ private
234
+
235
+ def self.current=(context)
236
+ Thread.current[:v8_context] = context
237
+ end
238
+
239
+ def lock_scope_and_enter
240
+ current = Context.current
241
+ Context.current = self
242
+ V8::C::Locker() do
243
+ V8::C::HandleScope() do
244
+ begin
245
+ @native.Enter()
246
+ yield if block_given?
247
+ ensure
248
+ @native.Exit()
249
+ end
250
+ end
251
+ end
252
+ ensure
253
+ Context.current = current
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,36 @@
1
+
2
+ class V8::Conversion
3
+ include Fundamental
4
+ include Identity
5
+
6
+ def to_ruby(v8_object)
7
+ super v8_object
8
+ end
9
+
10
+ def to_v8(ruby_object)
11
+ super ruby_object
12
+ end
13
+ end
14
+
15
+ for type in [TrueClass, FalseClass, NilClass, Float] do
16
+ type.class_eval do
17
+ include V8::Conversion::Primitive
18
+ end
19
+ end
20
+
21
+ for type in [Class, Object, Array, Hash, String, Symbol, Time, Proc, Method, Fixnum] do
22
+ type.class_eval do
23
+ include V8::Conversion.const_get(type.name)
24
+ end
25
+ end
26
+
27
+ class UnboundMethod
28
+ include V8::Conversion::Method
29
+ end
30
+
31
+ for type in [:Object, :String, :Date] do
32
+ V8::C::const_get(type).class_eval do
33
+ include V8::Conversion::const_get("Native#{type}")
34
+ end
35
+ end
36
+
@@ -0,0 +1,11 @@
1
+ class V8::Conversion
2
+ module Array
3
+ def to_v8
4
+ array = V8::Array.new(length)
5
+ each_with_index do |item, i|
6
+ array[i] = item
7
+ end
8
+ return array.to_v8
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,119 @@
1
+ class V8::Conversion
2
+ module Class
3
+ include V8::Conversion::Code
4
+
5
+ def to_template
6
+ weakcell(:constructor) do
7
+ template = V8::C::FunctionTemplate::New(V8::Conversion::Constructor.new(self))
8
+ prototype = template.InstanceTemplate()
9
+ prototype.SetNamedPropertyHandler(V8::Conversion::Get, V8::Conversion::Set)
10
+ prototype.SetIndexedPropertyHandler(V8::Conversion::IGet, V8::Conversion::ISet)
11
+ if self != ::Object && superclass != ::Object && superclass != ::Class
12
+ template.Inherit(superclass.to_template)
13
+ end
14
+ template
15
+ end
16
+ end
17
+ end
18
+
19
+ class Constructor
20
+ include V8::Error::Protect
21
+
22
+ def initialize(cls)
23
+ @class = cls
24
+ end
25
+
26
+ def call(arguments)
27
+ arguments.extend Args
28
+ protect do
29
+ if arguments.linkage_call?
30
+ arguments.link
31
+ else
32
+ arguments.construct @class
33
+ end
34
+ end
35
+ return arguments.This()
36
+ end
37
+
38
+ module Args
39
+ def linkage_call?
40
+ self.Length() == 1 && self[0].IsExternal()
41
+ end
42
+
43
+ def link
44
+ external = self[0]
45
+ This().SetHiddenValue("rr::implementation", external)
46
+ context.link external.Value(), This()
47
+ end
48
+
49
+ def construct(cls)
50
+ context.link cls.new(*to_args), This()
51
+ end
52
+
53
+ def context
54
+ V8::Context.current
55
+ end
56
+
57
+ def to_args
58
+ args = ::Array.new(Length())
59
+ 0.upto(args.length - 1) do |i|
60
+ args[i] = self[i]
61
+ end
62
+ return args
63
+ end
64
+ end
65
+ end
66
+
67
+ module Accessor
68
+ include V8::Error::Protect
69
+ def intercept(info, key, &block)
70
+ context = V8::Context.current
71
+ access = context.access
72
+ object = context.to_ruby(info.This())
73
+ handles_property = true
74
+ dontintercept = proc do
75
+ handles_property = false
76
+ end
77
+ protect do
78
+ result = block.call(context, access, object, context.to_ruby(key), dontintercept)
79
+ handles_property ? context.to_v8(result) : V8::C::Value::Empty
80
+ end
81
+ end
82
+ end
83
+
84
+ class Get
85
+ extend Accessor
86
+ def self.call(property, info)
87
+ intercept(info, property) do |context, access, object, key, dontintercept|
88
+ access.get(object, key, &dontintercept)
89
+ end
90
+ end
91
+ end
92
+
93
+ class Set
94
+ extend Accessor
95
+ def self.call(property, value, info)
96
+ intercept(info, property) do |context, access, object, key, dontintercept|
97
+ access.set(object, key, context.to_ruby(value), &dontintercept)
98
+ end
99
+ end
100
+ end
101
+
102
+ class IGet
103
+ extend Accessor
104
+ def self.call(property, info)
105
+ intercept(info, property) do |context, access, object, key, dontintercept|
106
+ access.iget(object, key, &dontintercept)
107
+ end
108
+ end
109
+ end
110
+
111
+ class ISet
112
+ extend Accessor
113
+ def self.call(property, value, info)
114
+ intercept(info, property) do |context, access, object, key, dontintercept|
115
+ access.iset(object, key, context.to_ruby(value), &dontintercept)
116
+ end
117
+ end
118
+ end
119
+ end