tomato 0.0.1.prealpha1 → 0.0.1.prealpha2
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.rdoc +115 -31
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/ext/tomato/Makefile +32 -37
- data/ext/tomato/binding_methods.cpp +47 -20
- data/ext/tomato/binding_methods.h +8 -0
- data/ext/tomato/binding_methods.o +0 -0
- data/ext/tomato/conversions_to_js.cpp +15 -61
- data/ext/tomato/conversions_to_js.o +0 -0
- data/ext/tomato/conversions_to_rb.cpp +31 -8
- data/ext/tomato/conversions_to_rb.o +0 -0
- data/ext/tomato/depend +2 -1
- data/ext/tomato/errors.o +0 -0
- data/ext/tomato/extconf.rb +1 -1
- data/ext/tomato/mkmf.log +5 -5
- data/ext/tomato/object_chain.cpp +241 -0
- data/ext/tomato/object_chain.o +0 -0
- data/ext/tomato/tomato.bundle +0 -0
- data/ext/tomato/tomato.cpp +22 -2
- data/ext/tomato/tomato.h +5 -1
- data/ext/tomato/tomato.o +0 -0
- data/ext/tomato/v8.o +0 -0
- data/lib/tomato.rb +104 -2
- data/pkg/tomato-0.0.1.prealpha1.gem +0 -0
- data/spec/lib/bound_class_spec.rb +48 -0
- data/spec/lib/bound_methods_spec.rb +20 -0
- data/spec/lib/bound_object_spec.rb +33 -0
- data/spec/lib/conversions_spec.rb +16 -37
- data/t.rb +6 -0
- data/tomato.gemspec +14 -3
- metadata +30 -6
Binary file
|
data/ext/tomato/tomato.bundle
CHANGED
Binary file
|
data/ext/tomato/tomato.cpp
CHANGED
@@ -13,6 +13,20 @@ static VALUE fTomato_execute(VALUE self, const char *javascript, const char *fil
|
|
13
13
|
static void tomato_mark(V8Tomato *tomato);
|
14
14
|
static void tomato_free(V8Tomato *tomato);
|
15
15
|
|
16
|
+
static v8::Handle<v8::Value> debug(const Arguments &args)
|
17
|
+
{
|
18
|
+
Handle<Value> arg;
|
19
|
+
V8Tomato *tomato = (V8Tomato *)(Handle<External>::Cast(args.Holder()->Get(String::New("_tomato")))->Value());
|
20
|
+
for (int i = 0; i < args.Length(); i++)
|
21
|
+
{
|
22
|
+
arg = args[i];
|
23
|
+
if (i > 0) printf(", ");
|
24
|
+
String::Utf8Value str(inspect_js(tomato, args[i]));
|
25
|
+
printf("<%s>", ToCString(str));
|
26
|
+
}
|
27
|
+
printf("\n");
|
28
|
+
return Null();
|
29
|
+
}
|
16
30
|
|
17
31
|
extern "C"
|
18
32
|
void Init_tomato(void)
|
@@ -37,7 +51,10 @@ void Init_tomato(void)
|
|
37
51
|
|
38
52
|
/* instance method "bind_method" */
|
39
53
|
rb_define_method(cTomato, "_bind_method", (ruby_method_vararg *)&fTomato_bind_method, -1);
|
40
|
-
|
54
|
+
|
55
|
+
/* instance method "_bind_class" */
|
56
|
+
rb_define_method(cTomato, "_bind_class", (ruby_method_vararg *)&fTomato_bind_class, 2);
|
57
|
+
|
41
58
|
/* init error-specific junk */
|
42
59
|
err_init();
|
43
60
|
}
|
@@ -50,9 +67,11 @@ static VALUE fTomato_allocate(VALUE klass)
|
|
50
67
|
|
51
68
|
HandleScope handle_scope;
|
52
69
|
Handle<ObjectTemplate> global = ObjectTemplate::New();
|
70
|
+
global->Set(String::New("debug"), FunctionTemplate::New(debug));
|
71
|
+
global->Set(String::New("_tomato"), External::New(tomato), DontEnum);
|
53
72
|
tomato->context = Context::New(NULL, global);
|
54
73
|
tomato->rb_instance = instance;
|
55
|
-
|
74
|
+
|
56
75
|
return instance;
|
57
76
|
}
|
58
77
|
|
@@ -68,6 +87,7 @@ static VALUE fTomato_version(VALUE self)
|
|
68
87
|
return rb_str_new2(V8::GetVersion());
|
69
88
|
}
|
70
89
|
|
90
|
+
/* Runs a String of JavaScript code. */
|
71
91
|
static VALUE fTomato_run(int argc, VALUE *argv, VALUE self)
|
72
92
|
{
|
73
93
|
if (argc == 0)
|
data/ext/tomato/tomato.h
CHANGED
@@ -28,9 +28,13 @@ extern VALUE cTomato;
|
|
28
28
|
extern VALUE cTomatoError;
|
29
29
|
extern VALUE rb_cTime;
|
30
30
|
|
31
|
+
/* in object_chain.cpp */
|
32
|
+
extern Handle<Value> find_or_create_object_chain(V8Tomato *tomato, VALUE chain);
|
33
|
+
extern VALUE fTomato_bind_class(VALUE self, VALUE klass, VALUE chain);
|
34
|
+
|
31
35
|
/* in conversions_to_rb.cpp */
|
32
36
|
extern VALUE ruby_value_of(V8Tomato *tomato, Handle<Value> result);
|
33
|
-
extern
|
37
|
+
extern Handle<Value> inspect_js(V8Tomato *tomato, Handle<Value> obj);
|
34
38
|
|
35
39
|
/* in conversions_to_js.cpp */
|
36
40
|
extern Handle<Value> js_value_of(V8Tomato *tomato, VALUE value);
|
data/ext/tomato/tomato.o
CHANGED
Binary file
|
data/ext/tomato/v8.o
CHANGED
Binary file
|
data/lib/tomato.rb
CHANGED
@@ -1,12 +1,114 @@
|
|
1
1
|
$LOAD_PATH << File.expand_path("../../ext/tomato", __FILE__)
|
2
2
|
require 'tomato.so'
|
3
|
+
require 'sc-core-ext'
|
3
4
|
|
4
5
|
class Tomato
|
5
|
-
|
6
|
-
|
6
|
+
# Bind a method to the JavaScript world. If no other arguments are given, the method will be called on this
|
7
|
+
# instance of Tomato. For instance, the following code:
|
8
|
+
# t = Tomato.new
|
9
|
+
# t.bind_method(:inspect)
|
10
|
+
# t.run("inspect();")
|
11
|
+
# ...will result in calling t.inspect.
|
12
|
+
#
|
13
|
+
# To bind the method to a specific object, pass the object itself in as a second argument or with an :object
|
14
|
+
# option:
|
15
|
+
# t.bind_method(:inspect, my_funky_object)
|
16
|
+
# t.run("inspect();")
|
17
|
+
# # -or-
|
18
|
+
# t.bind_method(:inspect, :object => my_funky_object)
|
19
|
+
# t.run("inspect();")
|
20
|
+
#
|
21
|
+
# Both of the above examples would result in a call to my_funky_object.inspect.
|
22
|
+
#
|
23
|
+
# You can also pass a :to option to bind the method to a specific object. If the specified object chain
|
24
|
+
# does not exist, Tomato will generate generic objects to suit. Examples:
|
25
|
+
#
|
26
|
+
# t.bind_method(:inspect, my_funky_object, :to => "funky")
|
27
|
+
# t.run("funky.inspect();")
|
28
|
+
#
|
29
|
+
# t.bind_method(:inspect, my_funky_object, :to => "funky_objects.my_object")
|
30
|
+
# t.run("funky_objects.my_object.inspect();")
|
31
|
+
#
|
32
|
+
def bind_method(method_name, *args)
|
33
|
+
options = args.extract_options!
|
34
|
+
receiver = options[:object] || args.first || self
|
35
|
+
chain = options[:to] ? split_chain(options[:to]) : nil
|
36
|
+
# Bind the method to JS.
|
37
|
+
_bind_method(method_name, receiver_index(receiver), chain)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Binds an entire Ruby object to the specified JavaScript object chain.
|
41
|
+
#
|
42
|
+
# If the chain is omitted, and the object itself is a Class, then the chain will be the qualified name
|
43
|
+
# of the class.
|
44
|
+
#
|
45
|
+
# Example:
|
46
|
+
# tomato.bind_object(Time)
|
47
|
+
# tomato.run("Time.now()")
|
48
|
+
# #=> 2010-06-25 18:02:52 -0400
|
49
|
+
#
|
50
|
+
# The same goes for Modules.
|
51
|
+
#
|
52
|
+
# Finally, if the chain is omitted and the object is an instance of a Class and not a Class itself, then
|
53
|
+
# the object will be bound to "ruby.[unqualified_name]". If the unqualified name is already in use, it will
|
54
|
+
# be overwritten.
|
55
|
+
#
|
56
|
+
# Example:
|
57
|
+
# time = Time.now
|
58
|
+
# tomato.bind_object(time)
|
59
|
+
# tomato.run("ruby.time.to_s()")
|
60
|
+
# #=> "2010-06-25 18:08:06 -0400"
|
61
|
+
# tomato.bind_object(time)
|
62
|
+
# tomato.run("ruby.time.to_s()")
|
63
|
+
# #=> "2010-06-25 18:08:29 -0400"
|
64
|
+
def bind_object(obj, chain = nil)
|
65
|
+
if (obj.kind_of?(Class) || obj.kind_of?(Module))
|
66
|
+
if chain.nil?
|
67
|
+
chain = obj.name.gsub(/\:\:/, '.')
|
68
|
+
chain = chain[1..-1] if chain[0] == ?.
|
69
|
+
end
|
70
|
+
# This sets up an object chain with the last created object as a Function, which can
|
71
|
+
# then be instiated with "new [Object]()" in JS.
|
72
|
+
#
|
73
|
+
# Objects of the same name in the chain are replaced, but their sub-objects are copied over
|
74
|
+
# so it should be transparent to the user.
|
75
|
+
return false unless _bind_class(receiver_index(obj), split_chain(chain))
|
76
|
+
elsif chain.nil?
|
77
|
+
unqualified_name = obj.class.name.gsub(/.*\:\:([^\:])?$/, '\1').underscore
|
78
|
+
chain = "ruby.#{unqualified_name}"
|
79
|
+
end
|
80
|
+
|
81
|
+
obj.public_methods.each do |method_name|
|
82
|
+
bind_method(method_name, obj, :to => chain)
|
83
|
+
end
|
84
|
+
obj
|
85
|
+
end
|
86
|
+
|
87
|
+
# Attempts to bind this object to the JavaScript world. If it's a String or Symbol, it will be treated
|
88
|
+
# as a call to #bind_method; otherwise, a call to #bind_object.
|
89
|
+
def bind(target, *args)
|
90
|
+
if target.kind_of?(String) || target.kind_of?(Symbol)
|
91
|
+
bind_method(target, *args)
|
92
|
+
else
|
93
|
+
bind_object(target, *args)
|
94
|
+
end
|
7
95
|
end
|
8
96
|
|
9
97
|
def inspect
|
10
98
|
"#<Tomato>"
|
11
99
|
end
|
100
|
+
|
101
|
+
private
|
102
|
+
def split_chain(str)
|
103
|
+
str.split(/\./)
|
104
|
+
end
|
105
|
+
|
106
|
+
def receivers
|
107
|
+
@receivers ||= []
|
108
|
+
end
|
109
|
+
|
110
|
+
def receiver_index(receiver)
|
111
|
+
receivers << receiver unless receivers.include?(receiver)
|
112
|
+
receivers.index(receiver)
|
113
|
+
end
|
12
114
|
end
|
Binary file
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Tomato bound objects" do
|
4
|
+
subject { Tomato.new }
|
5
|
+
|
6
|
+
class ::TestObject
|
7
|
+
attr_accessor :i
|
8
|
+
|
9
|
+
def initialize; @i = 1; end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
other.kind_of?(TestObject)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should map attribute getters to corresponding Ruby methods" do
|
17
|
+
subject.bind_object(TestObject, "TO")
|
18
|
+
subject.run('var v = new TO(); v.i;').should == 1
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should map attribute setters to corresponding Ruby methods" do
|
22
|
+
subject.bind_object(TestObject, "TO")
|
23
|
+
result = subject.run('var v = new TO(); v.i = 5; v;')
|
24
|
+
result.i.should == 5
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be bind-able with an explicit chain" do
|
28
|
+
subject.bind_object(TestObject, "TO")
|
29
|
+
proc { subject.run("new TO();") }.should_not raise_error
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be instantiatable" do
|
33
|
+
subject.bind_object(TestObject)
|
34
|
+
subject.run("new TestObject();").should == TestObject.new
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not lose sub-objects" do
|
38
|
+
subject.bind_object("hello", "TestObject.string")
|
39
|
+
subject.bind_object(TestObject)
|
40
|
+
subject.run("TestObject.string.inspect()").should == '"hello"'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should allow sub-bindings" do
|
44
|
+
subject.bind_object(TestObject)
|
45
|
+
subject.bind_object("hello", "TestObject.string")
|
46
|
+
subject.run("TestObject.string.inspect()").should == '"hello"'
|
47
|
+
end
|
48
|
+
end
|
@@ -8,6 +8,26 @@ describe "Tomato bound methods" do
|
|
8
8
|
proc { subject.run("(inspect());") }.should_not raise_error
|
9
9
|
end
|
10
10
|
|
11
|
+
it "should map Ruby methods to JS on a specific object within JS" do
|
12
|
+
subject.bind_method(:inspect, "hello", :to => "greeting")
|
13
|
+
subject.run("greeting.inspect();").should == '"hello"'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should map Ruby methods to JS on an object chain within JS" do
|
17
|
+
subject.bind_method(:inspect, "hello", :to => "greeting.first")
|
18
|
+
subject.run("greeting.first.inspect();").should == '"hello"'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should map Ruby methods to Javascript on a specific object without a hash" do
|
22
|
+
subject.bind_method(:inspect, "hello").should == true
|
23
|
+
subject.run("(inspect());").should == '"hello"'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should map Ruby methods to Javascript on a specific object with a hash" do
|
27
|
+
subject.bind_method(:inspect, :object => "hello").should == true
|
28
|
+
subject.run("(inspect());").should == '"hello"'
|
29
|
+
end
|
30
|
+
|
11
31
|
it "should accept arguments" do
|
12
32
|
subject.bind_method(:echo)
|
13
33
|
def subject.echo(i); i; end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Tomato bound objects" do
|
4
|
+
subject { Tomato.new }
|
5
|
+
|
6
|
+
it "should bind a Ruby class to an implicit chain" do
|
7
|
+
now = Time.now.to_i
|
8
|
+
|
9
|
+
subject.bind_object(Time)
|
10
|
+
subject.run("Time.at(#{now})").should == Time.at(now)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should bind a Ruby object to an explicit chain" do
|
14
|
+
time = Time.now
|
15
|
+
subject.bind_object(time, "current_time")
|
16
|
+
subject.run("current_time.to_s()").should == time.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should bind a Ruby object's singleton methods" do
|
20
|
+
time = Time.now
|
21
|
+
def time.as_string; to_s; end
|
22
|
+
time.should respond_to(:as_string)
|
23
|
+
|
24
|
+
subject.bind_object(time, "current_time")
|
25
|
+
subject.run("current_time.as_string()").should == time.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should bind a Ruby object to an implicit chain under 'ruby.[unqualified_object_class_name]'" do
|
29
|
+
time = Time.now
|
30
|
+
subject.bind_object(time)
|
31
|
+
subject.run("ruby.time.to_s()").should == time.to_s
|
32
|
+
end
|
33
|
+
end
|
@@ -1,9 +1,23 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Tomato conversions" do
|
4
|
-
|
5
|
-
subject { Tomato.new }
|
4
|
+
subject { Tomato.new }
|
6
5
|
|
6
|
+
context "from JS to Ruby" do
|
7
|
+
it "should handle objects" do
|
8
|
+
pending "how to do it? JSON?"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should handle classes" do
|
12
|
+
pending "how to do it? Prototype?"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should handle modules" do
|
16
|
+
pending "how to do it? Prototype?"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "from Ruby to JS to Ruby" do
|
7
21
|
def handle(value)
|
8
22
|
$test_value = value
|
9
23
|
def subject.a_method; $test_value; end
|
@@ -27,18 +41,6 @@ describe "Tomato conversions" do
|
|
27
41
|
handle(nil).should == nil
|
28
42
|
end
|
29
43
|
|
30
|
-
it "should handle objects" do
|
31
|
-
pending "how to do it? JSON?"
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should handle classes" do
|
35
|
-
pending "how to do it? Prototype?"
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should handle modules" do
|
39
|
-
pending "how to do it? Prototype?"
|
40
|
-
end
|
41
|
-
|
42
44
|
it "should handle floats" do
|
43
45
|
handle(1.05).should == 1.05
|
44
46
|
end
|
@@ -87,28 +89,5 @@ describe "Tomato conversions" do
|
|
87
89
|
it "should handle symbols" do
|
88
90
|
handle(:symbol).should == :symbol
|
89
91
|
end
|
90
|
-
=begin
|
91
|
-
case T_NIL :
|
92
|
-
case T_OBJECT :
|
93
|
-
//case T_CLASS :
|
94
|
-
//case T_MODULE :
|
95
|
-
case T_FLOAT :
|
96
|
-
case T_STRING :
|
97
|
-
case T_REGEXP :
|
98
|
-
case T_ARRAY :
|
99
|
-
case T_HASH :
|
100
|
-
//case T_STRUCT :
|
101
|
-
case T_BIGNUM :
|
102
|
-
case T_FIXNUM :
|
103
|
-
//case T_COMPLEX :
|
104
|
-
//case T_RATIONAL:
|
105
|
-
//case T_FILE :
|
106
|
-
case T_TRUE :
|
107
|
-
case T_FALSE :
|
108
|
-
//case T_DATA :
|
109
|
-
case T_SYMBOL :
|
110
|
-
symbol_from(object)
|
111
|
-
break;
|
112
|
-
=end
|
113
92
|
end
|
114
93
|
end
|
data/t.rb
ADDED
data/tomato.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tomato}
|
8
|
-
s.version = "0.0.1.
|
8
|
+
s.version = "0.0.1.prealpha2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Colin MacKenzie IV"]
|
12
|
-
s.date = %q{2010-06-
|
12
|
+
s.date = %q{2010-06-26}
|
13
13
|
s.description = %q{Leverages Google's V8 JavaScript library to interface Ruby code with JavaScript code.}
|
14
14
|
s.email = %q{sinisterchipmunk@gmail.com}
|
15
15
|
s.extensions = ["ext/tomato/extconf.rb"]
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
"ext/tomato/IMPORTANT",
|
26
26
|
"ext/tomato/Makefile",
|
27
27
|
"ext/tomato/binding_methods.cpp",
|
28
|
+
"ext/tomato/binding_methods.h",
|
28
29
|
"ext/tomato/binding_methods.o",
|
29
30
|
"ext/tomato/conversions_to_js.cpp",
|
30
31
|
"ext/tomato/conversions_to_js.o",
|
@@ -3330,6 +3331,8 @@ Gem::Specification.new do |s|
|
|
3330
3331
|
"ext/tomato/external/v8/tools/windows-tick-processor.bat",
|
3331
3332
|
"ext/tomato/external/v8/tools/windows-tick-processor.py",
|
3332
3333
|
"ext/tomato/mkmf.log",
|
3334
|
+
"ext/tomato/object_chain.cpp",
|
3335
|
+
"ext/tomato/object_chain.o",
|
3333
3336
|
"ext/tomato/tomato.bundle",
|
3334
3337
|
"ext/tomato/tomato.cpp",
|
3335
3338
|
"ext/tomato/tomato.h",
|
@@ -3339,10 +3342,13 @@ Gem::Specification.new do |s|
|
|
3339
3342
|
"lib/tomato.rb",
|
3340
3343
|
"pkg/tomato-0.0.1.gem",
|
3341
3344
|
"pkg/tomato-0.0.1.prealpha1.gem",
|
3345
|
+
"spec/lib/bound_class_spec.rb",
|
3342
3346
|
"spec/lib/bound_methods_spec.rb",
|
3347
|
+
"spec/lib/bound_object_spec.rb",
|
3343
3348
|
"spec/lib/conversions_spec.rb",
|
3344
3349
|
"spec/lib/tomato_spec.rb",
|
3345
3350
|
"spec/spec_helper.rb",
|
3351
|
+
"t.rb",
|
3346
3352
|
"tomato.gemspec"
|
3347
3353
|
]
|
3348
3354
|
s.homepage = %q{http://www.thoughtsincomputation.com}
|
@@ -3351,7 +3357,9 @@ Gem::Specification.new do |s|
|
|
3351
3357
|
s.rubygems_version = %q{1.3.7}
|
3352
3358
|
s.summary = %q{Leverages Google's V8 JavaScript library to interface Ruby code with JavaScript code.}
|
3353
3359
|
s.test_files = [
|
3354
|
-
"spec/lib/
|
3360
|
+
"spec/lib/bound_class_spec.rb",
|
3361
|
+
"spec/lib/bound_methods_spec.rb",
|
3362
|
+
"spec/lib/bound_object_spec.rb",
|
3355
3363
|
"spec/lib/conversions_spec.rb",
|
3356
3364
|
"spec/lib/tomato_spec.rb",
|
3357
3365
|
"spec/spec_helper.rb"
|
@@ -3362,11 +3370,14 @@ Gem::Specification.new do |s|
|
|
3362
3370
|
s.specification_version = 3
|
3363
3371
|
|
3364
3372
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
3373
|
+
s.add_runtime_dependency(%q<sc-core-ext>, [">= 1.2.0"])
|
3365
3374
|
s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
3366
3375
|
else
|
3376
|
+
s.add_dependency(%q<sc-core-ext>, [">= 1.2.0"])
|
3367
3377
|
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
3368
3378
|
end
|
3369
3379
|
else
|
3380
|
+
s.add_dependency(%q<sc-core-ext>, [">= 1.2.0"])
|
3370
3381
|
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
3371
3382
|
end
|
3372
3383
|
end
|