typedef boost::function<naRef(naContext, raw_type&)> getter_t;
typedef boost::function<void(naContext, raw_type&, naRef)> setter_t;
typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
+ typedef boost::function<bool( naContext,
+ raw_type&,
+ const std::string&,
+ naRef )> fallback_setter_t;
class MethodHolder:
public internal::MethodHolder
);
}
+ if( !_fallback_setter )
+ _fallback_setter = base->_fallback_setter;
+
return *this;
}
return *this;
}
+ /**
+ * Register a function which is called upon setting an unknown member of
+ * this ghost.
+ */
+ Ghost& _set(const fallback_setter_t& setter)
+ {
+ _fallback_setter = setter;
+ return *this;
+ }
+
+ /**
+ * Register a method which is called upon setting an unknown member of
+ * this ghost.
+ *
+ * @code{cpp}
+ * class MyClass
+ * {
+ * public:
+ * bool setMember( const std::string& key,
+ * const std::string& value );
+ * }
+ *
+ * Ghost<MyClassPtr>::init("Test")
+ * ._set(&MyClass::setMember);
+ * @endcode
+ */
+ template<class Param>
+ Ghost _set(bool (raw_type::*setter)(const std::string&, Param))
+ {
+ // Setter signature: bool( naContext,
+ // raw_type&,
+ // const std::string&,
+ // naRef )
+ return _set(boost::bind(
+ setter,
+ _2,
+ _3,
+ boost::bind(from_nasal_ptr<Param>::get(), _1, _4)
+ ));
+ }
+
/**
* Register anything that accepts an object instance and a
* nasal::CallContext and returns naRef as method.
};
typedef std::auto_ptr<Ghost> GhostPtr;
- MemberMap _members;
+ MemberMap _members;
+ fallback_setter_t _fallback_setter;
explicit Ghost(const std::string& name):
GhostMetadata(name, &_ghost_type)
static void setMember(naContext c, void* g, naRef field, naRef val)
{
const std::string key = nasal::from_nasal<std::string>(c, field);
- typename MemberMap::iterator member =
- getSingletonPtr()->_members.find(key);
+ const MemberMap& members = getSingletonPtr()->_members;
- if( member == getSingletonPtr()->_members.end() )
- naRuntimeError(c, "ghost: No such member: %s", key.c_str());
+ typename MemberMap::const_iterator member = members.find(key);
+ if( member == members.end() )
+ {
+ fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
+ if( !fallback_set )
+ naRuntimeError(c, "ghost: No such member: %s", key.c_str());
+ else if( !fallback_set(c, *getRawPtr(g), key, val) )
+ naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
+ }
else if( member->second.setter.empty() )
naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
else if( member->second.func )
naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
-
- member->second.setter(c, *getRawPtr(g), val);
+ else
+ member->second.setter(c, *getRawPtr(g), val);
}
};
void setVar(const std::string v) { var = v; }
unsigned long getThis() const { return (unsigned long)this; }
+ bool genericSet(const std::string& key, const std::string& val)
+ {
+ return key == "test";
+ }
};
void baseVoidFunc(Base& b) {}
.method("int2args", &baseFunc2Args)
.method("bool2args", &Base::test2Args)
.method("str_ptr", &testPtr)
- .method("this", &Base::getThis);
+ .method("this", &Base::getThis)
+ ._set(&Base::genericSet);
Ghost<DerivedPtr>::init("DerivedPtr")
.bases<BasePtr>()
.member("x", &Derived::getX, &Derived::setX)
VERIFY( objects[1] == d2 );
VERIFY( objects[2] == d3 );
+ // Calling fallback setter for unset values
+ const char* src_code = "me.test = 3;";
+ int errLine = -1;
+ naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0,
+ (char*)src_code, strlen(src_code),
+ &errLine );
+ ret = naCallMethod(code, derived, 0, 0, naNil());
+
+ VERIFY( !naGetError(c) ) // TODO real error check (this seems to always
+ // return 0...
+ VERIFY( from_nasal<int>(c, ret) == 3 )
+
//----------------------------------------------------------------------------
// Test nasal::CallContext
//----------------------------------------------------------------------------