tomato 0.0.1.prealpha1 → 0.0.1.prealpha2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|