31

I'm playing with creating Node.js modules in C++, but I'm stumped on the v8::Arguments class. Lets say I have a Javascript class for sending emails, which has a method with this signature:

Mailer::sendEmail(Array recipients, String sender, String message);

Which would be called like this:

mailer.sendEmail(["joe@gmail.com", "sally@gmail.com"], "fred@gmail.com", "Hi there");

Now in C++ land, I have a class function with this signature:

SendEmail(const v8::Arguments& args)

Which is backing my Mailer::sendEmail method in Javascript land. The SendEmail function will create a new instance of my Emailer class, which itself has a class function with this signature:

send(std::list<std::string> recipients, std::string from, std::string message)

And this is where I'm lost. I don't know how to take the values from args, and convert them into regular C++ types, so I can pass the values to my send function. As I understand it, the 3 values passed to Mailer::sendEmail will be available in args[0], args[1], and args[2]. I even understand I can do some type checking like if (!args[0]->IsArray()), but actually converting args[0] to std::list<std::string> is what I don't know how to do.

Edit: I found a hackish way of doing this, but I still think V8 has some built in methods to handle this in a cleaner way.

static Handle<Value> SendEmail(const Arguments& args)
{
    HandleScope scope;

    list<string> values;
    Local<Object> obj = args[0]->ToObject();
    Local<Array> props = obj->GetPropertyNames();

    // Iterate through args[0], adding each element to our list
    for(unsigned int i = 0; i < props->Length(); i++) {
        String::AsciiValue val(obj->Get(i)->ToString());
        values.push_front(string(*val));
    }

    // Display the values in the list for debugging purposes
    for (list<string>::iterator it = values.begin(); it != values.end(); it++) {
        cout << *it << endl;
    }

    return scope.Close(args.This());
}
mellowsoon
  • 22,273
  • 19
  • 57
  • 75

3 Answers3

50

I know this is an older topic, but the way I tend to do this is as follows:

Handle<Value> MethodName (const Arguments& args) {

    // get the param
    v8::String::Utf8Value param1(args[0]->ToString());

    // convert it to string
    std::string foo = std::string(*param1);    

}
Ryan
  • 7,733
  • 10
  • 61
  • 106
  • 3
    While not attactive I am pretty sure you can collapse the above into: `std::string param1(*v8::String::Utf8Value(args[0]->ToString()));` – graham.reeds Jul 12 '13 at 08:24
7

If you are using NaN (native abstractions for node) then try this code:

std::string myString(*NanAsciiString(args[0])); 
Segfault
  • 8,036
  • 3
  • 35
  • 54
  • 5
    `NanAsciiString` has been removed. Use `Nan::Utf8String` instead. E.g., `std::string arg0 = *Nan::Utf8String(info[0]);` – junvar Sep 11 '18 at 14:09
6

The best way I can find to convert to and from JS types and C++ types, is using v8-juice, which provides type casting methods. Specifically I'm using v8-convert, which is a spin off of v8-juice, that includes only the conversion methods.

Converting args[0] to std::list is one line:

std::list<std::string> values = cvv8::CastFromJS<std::list<std::string> >(args[0]);
mellowsoon
  • 22,273
  • 19
  • 57
  • 75
  • 5
    Warning about V8 Juice: https://code.google.com/p/v8-juice/ ACHTUNG ACHTUNG ACHTUNG: as of August 19, 2013 this project is being abandoned due to the degree of incompatible changes in the core v8 made during the first half of of 2013. The v8 API is being changed drastically in ways incompatible with every single v8-using.... – Logan Aug 19 '14 at 00:29