mustang 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/README.md +11 -1
  2. data/Rakefile +1 -1
  3. data/TODO.md +2 -1
  4. data/ext/v8/extconf.rb +3 -1
  5. data/ext/v8/v8_array.cpp +2 -0
  6. data/ext/v8/v8_context.cpp +32 -5
  7. data/ext/v8/v8_date.cpp +1 -0
  8. data/ext/v8/v8_external.cpp +1 -0
  9. data/ext/v8/v8_function.cpp +3 -0
  10. data/ext/v8/v8_integer.cpp +1 -0
  11. data/ext/v8/v8_macros.h +6 -0
  12. data/ext/v8/v8_main.cpp +3 -1
  13. data/ext/v8/v8_number.cpp +1 -0
  14. data/ext/v8/v8_object.cpp +2 -0
  15. data/ext/v8/v8_regexp.cpp +1 -0
  16. data/ext/v8/v8_string.cpp +1 -0
  17. data/ext/v8/v8_value.cpp +2 -0
  18. data/lib/mustang.rb +20 -27
  19. data/lib/mustang/context.rb +0 -26
  20. data/lib/{core_ext → mustang/core_ext}/class.rb +1 -1
  21. data/lib/{core_ext → mustang/core_ext}/object.rb +2 -4
  22. data/lib/{core_ext → mustang/core_ext}/symbol.rb +0 -0
  23. data/lib/{support → mustang/support}/delegated.rb +0 -0
  24. data/lib/mustang/v8/array.rb +21 -0
  25. data/lib/mustang/v8/context.rb +15 -0
  26. data/lib/mustang/v8/date.rb +20 -0
  27. data/lib/mustang/v8/error.rb +17 -0
  28. data/lib/mustang/v8/external.rb +16 -0
  29. data/lib/mustang/v8/function.rb +13 -0
  30. data/lib/mustang/v8/integer.rb +16 -0
  31. data/lib/mustang/v8/number.rb +16 -0
  32. data/lib/mustang/v8/object.rb +66 -0
  33. data/lib/mustang/v8/regexp.rb +23 -0
  34. data/lib/mustang/v8/string.rb +27 -0
  35. data/mustang.gemspec +1 -1
  36. data/spec/{core_ext → mustang/core_ext}/class_spec.rb +3 -3
  37. data/spec/{core_ext → mustang/core_ext}/object_spec.rb +3 -3
  38. data/spec/{core_ext → mustang/core_ext}/symbol_spec.rb +1 -1
  39. data/spec/{v8 → mustang/v8}/array_spec.rb +12 -5
  40. data/spec/{v8 → mustang/v8}/cast_spec.rb +10 -10
  41. data/spec/{v8 → mustang/v8}/context_spec.rb +52 -6
  42. data/spec/{v8 → mustang/v8}/data_spec.rb +4 -4
  43. data/spec/{v8 → mustang/v8}/date_spec.rb +12 -5
  44. data/spec/{v8 → mustang/v8}/empty_spec.rb +4 -4
  45. data/spec/{v8 → mustang/v8}/errors_spec.rb +9 -9
  46. data/spec/{v8 → mustang/v8}/external_spec.rb +14 -7
  47. data/spec/{v8 → mustang/v8}/function_spec.rb +20 -13
  48. data/spec/{v8 → mustang/v8}/integer_spec.rb +13 -6
  49. data/spec/{v8 → mustang/v8}/main_spec.rb +2 -2
  50. data/spec/{v8 → mustang/v8}/null_spec.rb +4 -4
  51. data/spec/{v8 → mustang/v8}/number_spec.rb +5 -5
  52. data/spec/{v8 → mustang/v8}/object_spec.rb +13 -6
  53. data/spec/mustang/v8/primitive_spec.rb +9 -0
  54. data/spec/{v8 → mustang/v8}/regexp_spec.rb +12 -5
  55. data/spec/{v8 → mustang/v8}/string_spec.rb +12 -5
  56. data/spec/{v8 → mustang/v8}/undefined_spec.rb +4 -4
  57. data/spec/mustang/v8/value_spec.rb +222 -0
  58. data/spec/spec_helper.rb +1 -1
  59. metadata +91 -62
  60. data/lib/v8/array.rb +0 -21
  61. data/lib/v8/context.rb +0 -13
  62. data/lib/v8/date.rb +0 -20
  63. data/lib/v8/error.rb +0 -15
  64. data/lib/v8/external.rb +0 -16
  65. data/lib/v8/function.rb +0 -11
  66. data/lib/v8/integer.rb +0 -16
  67. data/lib/v8/number.rb +0 -16
  68. data/lib/v8/object.rb +0 -66
  69. data/lib/v8/regexp.rb +0 -23
  70. data/lib/v8/string.rb +0 -27
  71. data/spec/v8/primitive_spec.rb +0 -9
  72. data/spec/v8/value_spec.rb +0 -215
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- This code is proudly sponsored by [Cubox, Agile Rails Devshop](http://cuboxsa.com)
1
+ Mustang development is proudly sponsored by [Cubox, Agile Rails Devshop](http://cuboxsa.com)
2
2
 
3
3
  # Mustang - V8 engine in Ruby's body
4
4
 
@@ -6,6 +6,12 @@ Mustang is ruby proxy library for awesome Google V8 JavaScript engine.
6
6
 
7
7
  ## Installation
8
8
 
9
+ Before you install mustang gem make sure you have `scons` installed.
10
+
11
+ $ sudo apt-get install scons # on debian
12
+ $ sudo pacman -S scons # on archlinux
13
+ $ brew install scons # on mac...
14
+
9
15
  Using rubygems:
10
16
 
11
17
  $ gem install mustang
@@ -28,6 +34,10 @@ For now it's only proof of concept. It implements very simple evaluation of java
28
34
  cxt.eval("var a=1;")
29
35
  cxt.eval("a+5;") # => 6
30
36
 
37
+ cxt[:puts] = method(:puts)
38
+ cxt.eval("puts(a)") # displays "1" on the screen
39
+ cxt[:a] # => 1
40
+
31
41
  ## Note on Patches/Pull Requests
32
42
 
33
43
  * Fork the project.
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ end
9
9
  begin
10
10
  require 'rake/extensiontask'
11
11
  Rake::ExtensionTask.new("v8") do |ext|
12
- ext.lib_dir = 'lib'
12
+ ext.lib_dir = 'lib/mustang'
13
13
  ext.source_pattern = "*.{cpp,h}"
14
14
  end
15
15
  rescue LoadError
data/TODO.md CHANGED
@@ -6,4 +6,5 @@
6
6
  * specs for support modules
7
7
  * v8 debug stuff
8
8
  * support for ObjectTemplates
9
- * reflecting ruby classes to FunctionTemplates
9
+ * reflecting ruby classes to FunctionTemplates
10
+ * getting entered context
@@ -52,8 +52,10 @@ find_library('v8', nil, lib)
52
52
  have_library('pthread')
53
53
  have_header('v8.h')
54
54
 
55
+ CONFIG['LDSHARED'] = '$(CXX) -shared' unless darwin?
56
+
55
57
  %w[-Wall -g -rdynamic -fPIC].each { |flag|
56
58
  $CPPFLAGS += " #{flag}" unless $CPPFLAGS.include?(flag)
57
59
  }
58
60
 
59
- create_makefile('v8')
61
+ create_makefile('mustang/v8')
@@ -36,6 +36,8 @@ Handle<Value> to_v8_array(VALUE value)
36
36
  static VALUE rb_v8_array_new(VALUE klass, VALUE data)
37
37
  {
38
38
  HandleScope scope;
39
+ PREVENT_CREATION_WITHOUT_CONTEXT();
40
+
39
41
  VALUE ary = rb_funcall2(data, rb_intern("to_a"), 0, NULL);
40
42
  VALUE self = v8_ref_new(klass, to_v8_array(ary));
41
43
 
@@ -11,6 +11,8 @@ UNWRAPPER(Context);
11
11
 
12
12
  /* V8::Context methods */
13
13
 
14
+ static VALUE rb_v8_context_enter(VALUE self);
15
+
14
16
  /*
15
17
  * call-seq:
16
18
  * V8::Context.new => new_context
@@ -24,6 +26,7 @@ static VALUE rb_v8_context_new(VALUE self)
24
26
  Persistent<Context> context(Context::New());
25
27
 
26
28
  VALUE ref = v8_ref_new(self, context);
29
+ rb_v8_context_enter(ref);
27
30
  rb_iv_set(ref, "@errors", rb_ary_new());
28
31
 
29
32
  context.Dispose();
@@ -129,6 +132,19 @@ static VALUE rb_v8_context_global(VALUE self)
129
132
  return to_ruby(global);
130
133
  }
131
134
 
135
+ /*
136
+ * call-seq:
137
+ * cxt.entered? => true or false
138
+ *
139
+ * Returns <code>true</code> when this context is entered.
140
+ *
141
+ */
142
+ static VALUE rb_v8_context_entered_p(VALUE self)
143
+ {
144
+ HandleScope scope;
145
+ return unwrap(self) == Context::GetEntered() ? Qtrue : Qfalse;
146
+ }
147
+
132
148
  /*
133
149
  * call-seq:
134
150
  * cxt.exit => nil
@@ -139,21 +155,31 @@ static VALUE rb_v8_context_global(VALUE self)
139
155
  static VALUE rb_v8_context_exit(VALUE self)
140
156
  {
141
157
  HandleScope scope;
142
- unwrap(self)->Exit();
158
+ Handle<Context> context;
159
+
160
+ if (Context::InContext()) {
161
+ context->Exit();
162
+ }
163
+
143
164
  return Qnil;
144
165
  }
145
166
 
146
167
  /*
147
168
  * call-seq:
148
- * cxt.entered? => true or false
169
+ * V8::Context.exit_all! => nil
149
170
  *
150
- * Returns <code>true</code> when this context is entered.
171
+ * Exits from all entered context.
151
172
  *
152
173
  */
153
- static VALUE rb_v8_context_entered_p(VALUE self)
174
+ static VALUE rb_v8_context_exit_all_bang(VALUE klass)
154
175
  {
155
176
  HandleScope scope;
156
- return unwrap(self) == Context::GetEntered() ? Qtrue : Qfalse;
177
+
178
+ while (Context::InContext()) {
179
+ Context::GetEntered()->Exit();
180
+ }
181
+
182
+ return Qnil;
157
183
  }
158
184
 
159
185
 
@@ -162,6 +188,7 @@ void Init_V8_Context()
162
188
  {
163
189
  rb_cV8Context = rb_define_class_under(rb_mV8, "Context", rb_cObject);
164
190
  rb_define_singleton_method(rb_cV8Context, "new", RUBY_METHOD_FUNC(rb_v8_context_new), 0);
191
+ rb_define_singleton_method(rb_cV8Context, "exit_all!", RUBY_METHOD_FUNC(rb_v8_context_exit_all_bang), 0);
165
192
  rb_define_method(rb_cV8Context, "evaluate", RUBY_METHOD_FUNC(rb_v8_context_evaluate), 2);
166
193
  rb_define_method(rb_cV8Context, "eval", RUBY_METHOD_FUNC(rb_v8_context_evaluate), 2);
167
194
  rb_define_method(rb_cV8Context, "prototype", RUBY_METHOD_FUNC(rb_v8_context_prototype), 0);
@@ -28,6 +28,7 @@ Handle<Value> to_v8_date(VALUE value)
28
28
  static VALUE rb_v8_date_new(VALUE klass, VALUE time)
29
29
  {
30
30
  HandleScope scope;
31
+ PREVENT_CREATION_WITHOUT_CONTEXT();
31
32
  return v8_ref_new(klass, to_v8_date(time));
32
33
  }
33
34
 
@@ -29,6 +29,7 @@ Handle<Value> to_v8_external(VALUE value)
29
29
  static VALUE rb_v8_external_new(VALUE klass, VALUE obj)
30
30
  {
31
31
  HandleScope scope;
32
+ PREVENT_CREATION_WITHOUT_CONTEXT();
32
33
  return v8_ref_new(klass, to_v8_external(obj));
33
34
  }
34
35
 
@@ -61,6 +61,8 @@ Handle<Value> to_v8_function(VALUE value)
61
61
  static VALUE rb_v8_function_new(int argc, VALUE *argv, VALUE klass)
62
62
  {
63
63
  HandleScope scope;
64
+ PREVENT_CREATION_WITHOUT_CONTEXT();
65
+
64
66
  VALUE orig;
65
67
 
66
68
  if (rb_block_given_p()) {
@@ -76,6 +78,7 @@ static VALUE rb_v8_function_new(int argc, VALUE *argv, VALUE klass)
76
78
 
77
79
  VALUE self = v8_ref_new(klass, to_v8_function(orig), orig);
78
80
  rb_iv_set(self, "@origin", orig);
81
+ rb_iv_set(self, "@receiver", Qnil);
79
82
  v8_set_peer(self);
80
83
 
81
84
  return self;
@@ -28,6 +28,7 @@ Handle<Value> to_v8_integer(VALUE value)
28
28
  static VALUE rb_v8_integer_new(VALUE klass, VALUE data)
29
29
  {
30
30
  HandleScope scope;
31
+ PREVENT_CREATION_WITHOUT_CONTEXT();
31
32
  VALUE num = rb_funcall2(data, rb_intern("to_i"), 0, NULL);
32
33
  return v8_ref_new(klass, to_v8_integer(num));
33
34
  }
@@ -27,4 +27,10 @@
27
27
  return v8_ref_get<T>(self); \
28
28
  }
29
29
 
30
+ #define PREVENT_CREATION_WITHOUT_CONTEXT() \
31
+ if (!Context::InContext()) { \
32
+ rb_raise(rb_eRuntimeError, "can't create V8 object without entering into context"); \
33
+ return Qnil; \
34
+ }
35
+
30
36
  #endif//__V8_MACROS_H
@@ -46,7 +46,9 @@ static VALUE rb_v8_version(VALUE self)
46
46
  /* V8 module initializer. */
47
47
  void Init_V8()
48
48
  {
49
- rb_mV8 = rb_define_module("V8");
49
+ VALUE rb_mMustang = rb_define_module("Mustang");
50
+
51
+ rb_mV8 = rb_define_module_under(rb_mMustang, "V8");
50
52
  rb_define_singleton_method(rb_mV8, "dead?", RUBY_METHOD_FUNC(rb_v8_dead_p), 0);
51
53
  rb_define_singleton_method(rb_mV8, "alive?", RUBY_METHOD_FUNC(rb_v8_alive_p), 0);
52
54
  rb_define_singleton_method(rb_mV8, "version", RUBY_METHOD_FUNC(rb_v8_version), 0);
@@ -28,6 +28,7 @@ Handle<Value> to_v8_number(VALUE value)
28
28
  static VALUE rb_v8_number_new(VALUE klass, VALUE data)
29
29
  {
30
30
  HandleScope scope;
31
+ PREVENT_CREATION_WITHOUT_CONTEXT();
31
32
  VALUE num = rb_funcall2(data, rb_intern("to_f"), 0, NULL);
32
33
  return v8_ref_new(klass, to_v8_number(num));
33
34
  }
@@ -51,6 +51,8 @@ Handle<Value> to_v8_object(VALUE value)
51
51
  static VALUE rb_v8_object_new(int argc, VALUE *argv, VALUE klass)
52
52
  {
53
53
  HandleScope scope;
54
+ PREVENT_CREATION_WITHOUT_CONTEXT();
55
+
54
56
  VALUE self;
55
57
 
56
58
  switch (argc) {
@@ -61,6 +61,7 @@ Handle<Value> to_v8_regexp(VALUE value)
61
61
  static VALUE rb_v8_regexp_new(int argc, VALUE *argv, VALUE klass)
62
62
  {
63
63
  HandleScope scope;
64
+ PREVENT_CREATION_WITHOUT_CONTEXT();
64
65
 
65
66
  if (argc == 1) {
66
67
  return v8_ref_new(klass, to_v8_regexp(argv[0]));
@@ -28,6 +28,7 @@ Handle<Value> to_v8_string(VALUE value)
28
28
  static VALUE rb_v8_string_new(VALUE klass, VALUE data)
29
29
  {
30
30
  HandleScope scope;
31
+ PREVENT_CREATION_WITHOUT_CONTEXT();
31
32
  VALUE str = rb_funcall2(data, rb_intern("to_s"), 0, NULL);
32
33
  return v8_ref_new(klass, to_v8_string(str));
33
34
  }
@@ -21,6 +21,8 @@ UNWRAPPER(Value);
21
21
  */
22
22
  static VALUE rb_v8_value_new(VALUE self, VALUE data)
23
23
  {
24
+ HandleScope scope;
25
+ PREVENT_CREATION_WITHOUT_CONTEXT();
24
26
  return v8_ref_new(self, to_v8(data));
25
27
  }
26
28
 
@@ -1,21 +1,21 @@
1
- require 'v8'
2
- require 'v8/context'
3
- require 'v8/object'
4
- require 'v8/string'
5
- require 'v8/integer'
6
- require 'v8/number'
7
- require 'v8/array'
8
- require 'v8/date'
9
- require 'v8/regexp'
10
- require 'v8/function'
11
- require 'v8/external'
12
- require 'v8/error'
13
-
14
- require 'support/delegated'
15
-
16
- require 'core_ext/object'
17
- require 'core_ext/class'
18
- require 'core_ext/symbol'
1
+ require 'mustang/support/delegated'
2
+
3
+ require 'mustang/v8'
4
+ require 'mustang/v8/context'
5
+ require 'mustang/v8/object'
6
+ require 'mustang/v8/string'
7
+ require 'mustang/v8/integer'
8
+ require 'mustang/v8/number'
9
+ require 'mustang/v8/array'
10
+ require 'mustang/v8/date'
11
+ require 'mustang/v8/regexp'
12
+ require 'mustang/v8/function'
13
+ require 'mustang/v8/external'
14
+ require 'mustang/v8/error'
15
+
16
+ require 'mustang/core_ext/object'
17
+ require 'mustang/core_ext/class'
18
+ require 'mustang/core_ext/symbol'
19
19
 
20
20
  require 'mustang/context'
21
21
 
@@ -26,19 +26,12 @@ module Mustang
26
26
  global
27
27
  end
28
28
 
29
- # Global context.
30
29
  def self.global
31
30
  @global or reset!
32
31
  end
33
32
 
34
- # Resets global context state. Appartently just creates new global
35
- # context and enters it.
33
+ # Resets global context state (just creates new global context and enters to it).
36
34
  def self.reset!(*args, &block)
37
- @global = GlobalContext.new(*args, &block)
35
+ @global = Context.new(*args, &block)
38
36
  end
39
-
40
- # We need enter into global context to avoid segfaults. Apart of my laziness
41
- # keeping one global context is much easier than handling errors in all
42
- # V8 datatypes implementation...
43
- enter
44
37
  end # Mustang
@@ -3,10 +3,6 @@ module Mustang
3
3
  class ScriptNotFoundError < Errno::ENOENT
4
4
  end
5
5
 
6
- # Raised when try to exit from global context.
7
- class ImmortalContextError < RuntimeError
8
- end
9
-
10
6
  # Extended and more user-friendly version of <tt>Mustang::V8::Context</tt>.
11
7
  class Context < V8::Context
12
8
  # Evaluates given javascript source. Before evaluation it's able to
@@ -43,27 +39,5 @@ module Mustang
43
39
  def errors
44
40
  @errors ||= []
45
41
  end
46
-
47
- # Returns <tt>true</tt> when it is global (immortal) context.
48
- def global?
49
- false
50
- end
51
42
  end # Context
52
-
53
- # This kind of context is used by <tt>Mustang</tt> module.
54
- class GlobalContext < Context
55
- def initialize(*)
56
- super
57
- enter
58
- end
59
-
60
- def exit
61
- # We have to disable exit, because global context is immortal.
62
- raise ImmortalContextError, "Global context can't be exited"
63
- end
64
-
65
- def global?
66
- true
67
- end
68
- end # GlobalContext
69
43
  end # Mustang
@@ -9,6 +9,6 @@ class Class
9
9
  klass = klass.superclass
10
10
  end
11
11
 
12
- result
12
+ result.map { |m| m.to_sym }
13
13
  end
14
14
  end # Class
@@ -1,12 +1,10 @@
1
- require 'v8'
2
-
3
1
  class Object
4
2
  # From now on each object can be easily converted to <tt>V8::*</tt> object
5
3
  # using <tt>#to_v8</tt> method.
6
- include V8::Cast
4
+ include Mustang::V8::Cast
7
5
 
8
6
  # Returns <tt>true</tt> when given object is reflected from within V8.
9
7
  def v8?
10
- kind_of?(V8::Data)
8
+ kind_of?(Mustang::V8::Data)
11
9
  end
12
10
  end # Object
@@ -0,0 +1,21 @@
1
+ module Mustang
2
+ module V8
3
+ class Array
4
+ include Comparable
5
+ include Enumerable
6
+ include Delegated
7
+
8
+ def <=>(other)
9
+ to_a <=> other
10
+ end
11
+
12
+ def each(*args, &block)
13
+ to_a.each(*args, &block)
14
+ end
15
+
16
+ def delegate
17
+ to_a
18
+ end
19
+ end # Array
20
+ end # V8
21
+ end # Mustang
@@ -0,0 +1,15 @@
1
+ module Mustang
2
+ module V8
3
+ class Context
4
+ def get(key)
5
+ prototype[key]
6
+ end
7
+ alias_method :[], :get
8
+
9
+ def set(key, value)
10
+ prototype[key] = value
11
+ end
12
+ alias_method :[]=, :set
13
+ end # Context
14
+ end # V8
15
+ end # Mustang
@@ -0,0 +1,20 @@
1
+ module Mustang
2
+ module V8
3
+ class Date
4
+ include Comparable
5
+ include Delegated
6
+
7
+ def to_time
8
+ Time.at(to_i);
9
+ end
10
+
11
+ def <=>(other)
12
+ to_time <=> other
13
+ end
14
+
15
+ def delegate
16
+ to_time
17
+ end
18
+ end # Date
19
+ end # V8
20
+ end # Mustang