Getting started with SpiderApe:

The fun all starts in the source tree, in src/client/main.cpp. There are many examples of using the features in src/ape/builtins.cpp and src/plugins/nc/ncwrapper.*pp. A slew of sample/test JS scripts live under src/client/scripts/....

Below we will show a couple short demonstrations...

If you just want to run arbitrary JS code, and not add your own functions or classes:
#include <sf.net/ape/spiderape.hpp>
// If using the 2005.10.03 release of Ape, instead include:
// #include <s11n.net/ape/spiderape.hpp>

ape::MonkeyWrapper js;
jsval myjsval;
js.eval_source( "a = 10", // arbitrary JS code
                myjsval, // return value
                "my inlined script" // script name, for error reporting
              );
Of course, eval_source() also accepts stream as an input source, and eval_file() accepts a filename.

Conversions between JS and native types:
// Assume: JSContext * cx = some JS context, like js.context()
using namespace ape;

// Typical POD conversions...
// Assume jv1..jvN are jsval vars:
std::string foo = jsval_to_std_string( cx, jv1 );
char const * cstring = jsval_to_cstring( cx, jv2 ); // JS owns the string!
char ch = jsval_to_char( cx, jv3 ); // converts ints or one-char strings
jsval jch = char_to_jsval( cx, ch ); // converts to a one-char string

// For template-inclined users, an equivalent approach:
std::string bar = jsval_to<std::string>( cx, jv1 );
char const * cstring2  = jsval_to<char const *>( cx, jv1 );

// And best of all, we can also plug in our own objects
// to the system:
ape::NCWindow * win = jsval_to<NCWindow>( cx, jv3 );


More powerful conversions:
using namespace ape;

// For demonstration, my_function() sets i to an unspecified
// non-0 value returns the string form of the number.
std::string my_function( int & i )
{
  std::ostringstream os;
  i = 42;
  os << i;
  return os.str();
}

//... now assume we are in the native impl of a conventional JS function...
// Assume we are passed an integer.

// Bind a native integer to the argument:
int nati = 0;
scoped_binder<int> sentry( cx, argv[0], nati );

// Forward argv to my_function(), applying type conversions, and
// convert return value to JS:
*rval = std_string_to_jsval(
	   fwd_to_func1<std::string,int &>( my_function, cx, obj, argc, argv )
	)
  );

// Now nati holds the value assigned to it in my_function().
// The JS/Native binding to nati is removed when sentry goes out of scope,
// providing a simplified exception safety compared to directly using
// the lower-level bind/undbind_native() functions.

Class<>: Here is an example of creating a new JS-side class:
#include <sf.net/ape/ape.hpp>
#include <sf.net/ape/class.hpp>

struct MyClass
{
private:
	JSContext * m_cx;
	JSObject * m_jo;
public:
	/** Required ctor. */
	MyClass( JSContext *cx, JSObject *obj, uintN argc, jsval * argv, jsval * rval )
	: m_cx(cx), m_jo(obj)
	{
	}

	// Functions we want to bind:

	double multiply( int lhs, int rhs )
	{ return lhs * rhs; }

	std::string concat( std::string const & lhs, std::string const & rhs )
	{ return lhs + rhs; }

	/**
	Init function to create and register the JS
	class. This need not be a member, but should
	be called before creating your MonkeyWrapper(s).
	This registers MyClass with
	ape::standard_class_initializers(), which means
	that MonkeyWrappers created after this is called
	will have access to MyClass.

	Calling this more than once may result in
	undefined behaviour.
	*/
	static void define_js_class()
	{
		// define JS class and function names:
		static const char * cName = "MyClass";
		static const char * fMult = "multiply";
		static const char * fConcat = "concat";
		static const char * fPrint = "print";

		// Start the class init process:
		typedef ape::Class<cName,MyClass> C;
		C::impl & ci = C().Implement();
	
		// Add members:
		ci.Member<fMult,double,int,int>( &MyClass::multiply );
		ci.Member<fConcat,std::string,std::string const &,
				std::string const &>( &MyClass::concat );
		ci.Member<fPrint>( ape::ape_print ); // support added 2006.03.16,
		// ^^^ Here we bind an arbitrary JSFunction as a member function.

		// Finalize the definition process:
		ci.Define();
	}
};

// From your main app/init routine you must then initialize MyClass ...

MyClass::define_js_class();

// All MonkeyWrappers created after define_js_class() is called
// have access to the class in script code:

var m = new MyClass();
m.print( m.multiply(3,4),
       m.concat( "hi, ", "world" )
      );
By adding some code to the ctor you can add additional member functions when the object is created:
	MyClass( JSContext *cx, JSObject *obj, uintN argc, jsval * argv, jsval * rval )
	{
		ape::scriptable sc(cx,obj);
		sc.add_function( "divide", "function(a,b) { return a/b; }" );
		sc.add_function( "eval", ape::ape_eval );
		sc.add_function( "debug", "function(){ this.print('MyClass Debug:',arguments); }" );
	}
You can also call those functions from C++ code. For example, assume we add the following member function to MyClass:
void do_something()
{
	ape::scriptable sc(this->m_cx,this->m_jo);
	jsval rv;
	sc.eval( "this.tmp = this.divide(4,2)", &rv );
	// ^^^ 2 == jsval_to_int(rv)
	sc.eval( "this.debug('divide(4,2) ==',this.tmp)", &rv );
	sc.eval( "delete this.tmp", &rv );
}