Added binding to free functions (and renamed hierarchy)

This commit is contained in:
Phil Nash 2013-05-20 08:31:12 +01:00
parent d4305377b7
commit d44f2cf40f

View File

@ -52,41 +52,41 @@ namespace Clara {
} }
template<typename ConfigT> template<typename ConfigT>
struct IBoundMember { struct IArgFunction {
virtual ~IBoundMember() {} virtual ~IArgFunction() {}
virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual void set( ConfigT& config, std::string const& value ) const = 0;
virtual void setFlag( ConfigT& config ) const = 0; virtual void setFlag( ConfigT& config ) const = 0;
virtual bool takesArg() const = 0; virtual bool takesArg() const = 0;
virtual IBoundMember* clone() const = 0; virtual IArgFunction* clone() const = 0;
}; };
template<typename ConfigT> template<typename ConfigT>
class BoundField { class BoundArgFunction {
public: public:
BoundField( IBoundMember<ConfigT>* _boundMember ) : boundMember( _boundMember ) {} BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
BoundField( BoundField const& other ) : boundMember( other.boundMember->clone() ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj->clone() ) {}
BoundField& operator = ( BoundField const& other ) { BoundArgFunction& operator = ( BoundArgFunction const& other ) {
IBoundMember<ConfigT> newMember = other.clone(); IArgFunction<ConfigT> newFunctionObj = other.clone();
delete boundMember; delete functionObj;
boundMember = newMember; functionObj = newFunctionObj;
return *this; return *this;
} }
~BoundField() { delete boundMember; } ~BoundArgFunction() { delete functionObj; }
void set( ConfigT& config, std::string const& value ) const { void set( ConfigT& config, std::string const& value ) const {
boundMember->set( config, value ); functionObj->set( config, value );
} }
void setFlag( ConfigT& config ) const { void setFlag( ConfigT& config ) const {
boundMember->setFlag( config ); functionObj->setFlag( config );
} }
bool takesArg() const { return boundMember->takesArg(); } bool takesArg() const { return functionObj->takesArg(); }
private: private:
IBoundMember<ConfigT>* boundMember; IArgFunction<ConfigT>* functionObj;
}; };
template<typename C, typename M> template<typename C, typename M>
struct BoundDataMember : IBoundMember<C>{ struct BoundDataMember : IArgFunction<C>{
BoundDataMember( M C::* _member ) : member( _member ) {} BoundDataMember( M C::* _member ) : member( _member ) {}
virtual void set( C& p, std::string const& stringValue ) const { virtual void set( C& p, std::string const& stringValue ) const {
convertInto( stringValue, p.*member ); convertInto( stringValue, p.*member );
@ -95,11 +95,11 @@ namespace Clara {
convertInto( true, p.*member ); convertInto( true, p.*member );
} }
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IBoundMember<C>* clone() const { return new BoundDataMember( *this ); } virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
M C::* member; M C::* member;
}; };
template<typename C, typename M> template<typename C, typename M>
struct BoundUnaryMethod : IBoundMember<C>{ struct BoundUnaryMethod : IArgFunction<C>{
BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
virtual void set( C& p, std::string const& stringValue ) const { virtual void set( C& p, std::string const& stringValue ) const {
typename RemoveConstRef<M>::type value; typename RemoveConstRef<M>::type value;
@ -112,11 +112,11 @@ namespace Clara {
(p.*member)( value ); (p.*member)( value );
} }
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IBoundMember<C>* clone() const { return new BoundUnaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
void (C::*member)( M ); void (C::*member)( M );
}; };
template<typename C> template<typename C>
struct BoundNullaryMethod : IBoundMember<C>{ struct BoundNullaryMethod : IArgFunction<C>{
BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
virtual void set( C& p, std::string const& stringValue ) const { virtual void set( C& p, std::string const& stringValue ) const {
bool value; bool value;
@ -128,21 +128,42 @@ namespace Clara {
(p.*member)(); (p.*member)();
} }
virtual bool takesArg() const { return false; } virtual bool takesArg() const { return false; }
virtual IBoundMember<C>* clone() const { return new BoundNullaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
void (C::*member)(); void (C::*member)();
}; };
template<typename C>
struct BoundUnaryFunction : IArgFunction<C>{
BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
virtual void set( C& obj, std::string const& stringValue ) const {
bool value;
convertInto( stringValue, value );
if( value )
function( obj );
}
virtual void setFlag( C& p ) const {
function( p );
}
virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
void (*function)( C& );
};
template<typename C, typename M> template<typename C, typename M>
BoundField<C> makeBoundField( M C::* _member ) { BoundArgFunction<C> makeBoundField( M C::* _member ) {
return BoundField<C>( new BoundDataMember<C,M>( _member ) ); return BoundArgFunction<C>( new BoundDataMember<C,M>( _member ) );
} }
template<typename C, typename M> template<typename C, typename M>
BoundField<C> makeBoundField( void (C::*_member)( M ) ) { BoundArgFunction<C> makeBoundField( void (C::*_member)( M ) ) {
return BoundField<C>( new BoundUnaryMethod<C,M>( _member ) ); return BoundArgFunction<C>( new BoundUnaryMethod<C,M>( _member ) );
} }
template<typename C> template<typename C>
BoundField<C> makeBoundField( void (C::*_member)() ) { BoundArgFunction<C> makeBoundField( void (C::*_member)() ) {
return BoundField<C>( new BoundNullaryMethod<C>( _member ) ); return BoundArgFunction<C>( new BoundNullaryMethod<C>( _member ) );
}
template<typename C>
BoundArgFunction<C> makeBoundField( void (*_function)( C& ) ) {
return BoundArgFunction<C>( new BoundUnaryFunction<C>( _function ) );
} }
} // namespace Detail } // namespace Detail
@ -228,7 +249,7 @@ namespace Clara {
}; };
struct Arg { struct Arg {
Arg( Detail::BoundField<ConfigT> const& _boundField ) : boundField( _boundField ) {} Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
bool hasShortName( std::string const& shortName ) const { bool hasShortName( std::string const& shortName ) const {
for( std::vector<std::string>::const_iterator for( std::vector<std::string>::const_iterator
@ -280,7 +301,7 @@ namespace Clara {
return oss.str(); return oss.str();
} }
Detail::BoundField<ConfigT> boundField; Detail::BoundArgFunction<ConfigT> boundField;
std::vector<std::string> shortNames; std::vector<std::string> shortNames;
std::string longName; std::string longName;
std::string description; std::string description;
@ -542,12 +563,14 @@ struct Config {
std::vector<std::string> warnings; std::vector<std::string> warnings;
std::vector<std::string> testsOrTags; std::vector<std::string> testsOrTags;
void abortAfterFirst() { abortAfter = 1; } // void abortAfterFirst() { abortAfter = 1; }
void abortAfterX( int x ) { abortAfter = x; } void abortAfterX( int x ) { abortAfter = x; }
void addWarning( std::string const& _warning ) { warnings.push_back( _warning ); } void addWarning( std::string const& _warning ) { warnings.push_back( _warning ); }
void addTestOrTags( std::string const& _testSpec ) { testsOrTags.push_back( _testSpec ); } void addTestOrTags( std::string const& _testSpec ) { testsOrTags.push_back( _testSpec ); }
}; };
inline void abortAfterFirst( Config& config ) { config.abortAfter = 1; }
SCENARIO( "New Catch commandline interface", "[cli]" ) { SCENARIO( "New Catch commandline interface", "[cli]" ) {
@ -589,10 +612,10 @@ SCENARIO( "New Catch commandline interface", "[cli]" ) {
.describe( "output filename" ) .describe( "output filename" )
.shortOpt( "o") .shortOpt( "o")
.longOpt( "out" ) .longOpt( "out" )
.argName( "file name" ); .argName( "filename" );
cli.bind( &Config::reporter ) cli.bind( &Config::reporter )
.describe( "e.g. console | xml | junit" ) .describe( "reporter to use - defaults to console" )
.shortOpt( "r") .shortOpt( "r")
.longOpt( "reporter" ) .longOpt( "reporter" )
.argName( "reporter name[:filename]" ); .argName( "reporter name[:filename]" );
@ -603,7 +626,7 @@ SCENARIO( "New Catch commandline interface", "[cli]" ) {
.longOpt( "name" ) .longOpt( "name" )
.argName( "name" ); .argName( "name" );
cli.bind( &Config::abortAfterFirst ) cli.bind( &abortAfterFirst )
.describe( "abort at first failure" ) .describe( "abort at first failure" )
.shortOpt( "a") .shortOpt( "a")
.longOpt( "abort" ); .longOpt( "abort" );
@ -645,6 +668,14 @@ SCENARIO( "New Catch commandline interface", "[cli]" ) {
CHECK( config.breakIntoDebugger ); CHECK( config.breakIntoDebugger );
} }
} }
WHEN( "A flag is set via a nullary method" ) {
CHECK( config.abortAfter == 0 );
const char* argv[] = { "test", "-a" };
parseInto( cli, argv, config );
REQUIRE( config.abortAfter == 1 );
}
} }
} }