Skip to content

Commit

Permalink
Add a few class tests and update README.
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyong committed Jan 21, 2014
1 parent c2b9a43 commit 812b87d
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 46 deletions.
118 changes: 84 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
____/ \___| _| \___| _| _| \___|
```

# Selene

Simple C++11 friendly bindings to Lua.

## Building
Expand All @@ -26,67 +24,119 @@ addition, this will build all tests in the `test` directory.

## Usage

Currently, these bindings support calling lua function from C++ and vice versa.
### Establishing Lua Context

```c++
using namespace sel;
State state; // creates a Lua context
State state{true]; // creates a Lua context and loads standard Lua libraries
```
When a `sel::State` object goes out of scope, the Lua context is
automatically destroyed in addition to all objects associated with it
(including C++ objects).
### Calling Lua functions from C++
```lua
// test.lua
function foo()
end
function add(a, b)
return a + b
return a + b
end
function sum_and_difference(a, b)
return (a+b), (a-b);
return (a+b), (a-b);
end
function bar()
return 4, true, "hi"
return 4, true, "hi"
end
mytable = {}
function mytable.foo()
return 4
end
```

```c++
#include <selene.h>
#include <cassert>
sel::State state;
state.Load("/path/to/test.lua");

// Call function with no arguments or returns
state.Call("foo");

// Call function with two arguments that returns an int
int result = state.Call<int>("add", 5, 2);
assert(result == 7);


// Call function that returns multiple values
int sum, difference;
std::tie(sum, difference) = state.Call<int, int>("sum_and_difference", 3, 1);
assert(sum == 4 && difference == 2);

// Call function in table
result = state.CallField<int>("mytable", "foo");
assert(result == 4);
```
### Calling Free-standing C++ functions from Lua
```c++
int my_multiply(int a, int b) {
return (a*b);
}
int main() {
sel::State state;
state.Load("../test/test.lua");
sel::State state;
// Call function with no arguments or returns
state.Call("foo");
// Register the function to the Lua global "c_multiply"
state.Register("c_multiply", &my_multiply);
// Call function with two arguments that returns an int
int result = state.Call<int>("add", 5, 2);
assert(result == 7);
// Now we can call it (we can also call it from within lua)
result = state.Call<int>("my_multiply", 5, 2);
assert(result == 10);
```

// Multiple return types
int sum, difference;
std::tie(sum, difference) = state.Call<int, int>("sum_and_difference", 3, 1);
assert(sum == 4 && difference == 2);
You can also register functor objects, lambdas, and any fully
qualified `std::function`. See `test/interop_tests.h` for details.

### Registering Object Instances

// Heterogeneous return types
```c++
struct Foo {
int x;
bool y;
std::string z;
std::tie(x, y, z) = state.Call<int, bool, std::string>("bar");
assert(x == 4 && y == true && z == "hi");
Foo(int x_) : x(x_) {}

// Call C function from Lua
state.Register("c_multiply", &my_multiply);
result = state.Call<int>("my_multiply", 5, 2);
assert(result == 10);
int DoubleAdd(int y) { return 2 * (x + y); }
void SetX(int x_) { x = x_; }
};

std::cout << "Call tests finished successfully." << std::endl;
}
sel::State state;

// Instantiate a foo object with x initially set to 2
Foo foo(2);

// Binds the C++ instance foo to a table also called foo in Lua along
// with two methods bound to fields of that table
state.Register("foo", foo,
std::make_pair("double_add", &Foo::DoubleAdd),
std::make_pair("set_x", &Foo::SetX));

state.CallField("foo", "set_x", 4);
assert(foo.x == 4);

int result = state.CallField("foo", "double_add", 3);
assert(result == 14);
```
You can also register functor objects, lambdas, and any fully
qualified `std::function`. See `test/tests.h` for details.
In the above example, the functions `foo.double_add` and `foo.set_x`
will also be accessible from within Lua after registration occurs.
## Writeup
You can read more about this project in the blogpost that describes it
[here](http://www.jeremyong.com/blog/2014/01/10/interfacing-lua-with-templates-in-c-plus-plus-11/).
Expand All @@ -97,6 +147,6 @@ and in the second part
The following features are planned, although nothing is guaranteed:
- Object oriented type aware table interface with Lua
- Object lifetime handling
- Smarter Lua module loading
- Hooks for module reloading
4 changes: 3 additions & 1 deletion test/Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ static std::vector<bool(*)()> tests = {
test_add,
test_multi_return,
test_heterogeneous_return,
test_call_field,
test_call_c_function,
test_call_c_fun_from_lua,
test_no_return,
Expand All @@ -20,7 +21,8 @@ static std::vector<bool(*)()> tests = {
test_multivalue_c_fun_from_lua,
test_c_fun_destructor,
test_register_class,
test_mutate_instance
test_mutate_instance,
test_multiple_methods
};


Expand Down
18 changes: 15 additions & 3 deletions test/class_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ struct Foo {
int DoubleAdd(int y) {
return 2 * (x + y);
}
void SetX(int x2) {
x = x2;
void SetX(int x_) {
x = x_;
}
};

Expand All @@ -19,7 +19,7 @@ bool test_register_class() {
state.Register("foo_instance",
foo_instance,
std::make_pair("double_add", &Foo::DoubleAdd));
int answer = state.CallField<int>("foo_instance", "double_add", 3);
const int answer = state.CallField<int>("foo_instance", "double_add", 3);
return (answer == 8);
}

Expand All @@ -32,3 +32,15 @@ bool test_mutate_instance() {
state.CallField("foo_instance", "set_x", 4);
return (foo_instance.x == 4);
}

bool test_multiple_methods() {
Foo foo_instance(1);
sel::State state;
state.Register("foo_instance",
foo_instance,
std::make_pair("double_add", &Foo::DoubleAdd),
std::make_pair("set_x", &Foo::SetX));
state.CallField("foo_instance", "set_x", 4);
const int answer = state.CallField<int>("foo_instance", "double_add", 3);
return (answer == 14);
}
23 changes: 15 additions & 8 deletions test/interop_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,30 @@ bool test_heterogeneous_return() {
bool y;
std::string z;
std::tie(x, y, z) = state.Call<int, bool, std::string>("bar");
return (x == 4 && y == true && z == "hi");
return x == 4 && y == true && z == "hi";
}

bool test_call_field() {
sel::State state;
state.Load("../test/test.lua");
int answer = state.CallField<int>("mytable", "foo");
return answer == 4;
}

bool test_call_c_function() {
sel::State state;
state.Load("../test/test.lua");
state.Register("cadd", std::function<int(int, int)>(my_add));
int answer = state.Call<int>("cadd", 3, 6);
return (answer == 9);
return answer == 9;
}

bool test_call_c_fun_from_lua() {
sel::State state;
state.Load("../test/test.lua");
state.Register("cadd", std::function<int(int, int)>(my_add));
int answer = state.Call<int>("execute");
return (answer == 11);
return answer == 11;
}

bool test_no_return() {
Expand All @@ -70,15 +77,15 @@ bool test_call_lambda() {
std::function<int(int, int)> mult = [](int x, int y){ return x * y; };
state.Register("cmultiply", mult);
int answer = state.Call<int>("cmultiply", 5, 6);
return (answer == 30);
return answer == 30;
}

bool test_call_normal_c_fun() {
sel::State state;
state.Load("../test/test.lua");
state.Register("cadd", &my_add);
const int answer = state.Call<int>("cadd", 4, 20);
return (answer == 24);
return answer == 24;
}

bool test_call_normal_c_fun_many_times() {
Expand Down Expand Up @@ -107,7 +114,7 @@ bool test_call_functor() {
state.Load("../test/test.lua");
state.Register("c_the_answer", std::function<int()>(functor));
int answer = state.Call<int>("c_the_answer");
return (answer == 42);
return answer == 42;

}

Expand All @@ -121,15 +128,15 @@ bool test_multivalue_c_fun_return() {
state.Register("test_fun", &my_sum_and_difference);
int sum, difference;
std::tie(sum, difference) = state.Call<int, int>("test_fun", -2, 2);
return (sum == 0 && difference == -4);
return sum == 0 && difference == -4;
}

bool test_multivalue_c_fun_from_lua() {
sel::State state;
state.Load("../test/test.lua");
state.Register("doozy_c", &my_sum_and_difference);
int answer = state.Call<int>("doozy", 5);
return (answer == -75);
return answer == -75;
}

bool test_c_fun_destructor() {
Expand Down
5 changes: 5 additions & 0 deletions test/test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ function doozy(a)
x, y = doozy_c(a, 2 * a)
return x * y
end

mytable = {}
function mytable.foo()
return 4
end

0 comments on commit 812b87d

Please sign in to comment.