Console: Implement custom return-value formatter support
g0dil [Tue, 15 Apr 2008 22:22:44 +0000 (22:22 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@813 270642c3-0616-0410-b53a-bc976706d245

Console/ParsedCommand.cti
Console/ParsedCommand.hh
Console/ParsedCommand.ih
Console/ParsedCommand.mpp
Console/ParsedCommand.test.cc

index f4b523f..029fa2d 100644 (file)
@@ -126,9 +126,43 @@ senf::console::ParsedCommandAttributor<Overload>::ParsedCommandAttributor(Overlo
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::ParsedArgumentAttributorBase<Overload,Self>
 
+template <class Overload, class Self, class ReturnType>
+prefix_ Self
+senf::console::ParsedArgumentAttributorBase<Overload,Self,ReturnType>::doc(std::string const & doc)
+    const
+{
+    this->ParsedCommandAttributorBase::nodeDoc(doc);
+    return static_cast<Self const &>(*this);
+}
+
+template <class Overload, class Self, class ReturnType>
+prefix_ Self senf::console::ParsedArgumentAttributorBase<Overload,Self,ReturnType>::
+overloadDoc(std::string const & doc)
+    const
+{
+    this->ParsedCommandAttributorBase::overloadDoc(doc);
+    return static_cast<Self const &>(*this);
+}
+
+template <class Overload, class Self, class ReturnType>
+prefix_ Self senf::console::ParsedArgumentAttributorBase<Overload,Self,ReturnType>::
+formatter(typename Overload::Formatter f)
+    const
+{
+    this->overload().formatter(f);
+    return static_cast<Self const &>(*this);
+}
+
+template <class Overload, class Self, class ReturnType>
+prefix_
+senf::console::ParsedArgumentAttributorBase<Overload,Self,ReturnType>::
+ParsedArgumentAttributorBase(Overload & overload, unsigned index)
+    : ParsedCommandAttributor<Overload> (overload, index)
+{}
+
 template <class Overload, class Self>
 prefix_ Self
-senf::console::ParsedArgumentAttributorBase<Overload,Self>::doc(std::string const & doc)
+senf::console::ParsedArgumentAttributorBase<Overload,Self,void>::doc(std::string const & doc)
     const
 {
     this->ParsedCommandAttributorBase::nodeDoc(doc);
@@ -136,7 +170,7 @@ senf::console::ParsedArgumentAttributorBase<Overload,Self>::doc(std::string cons
 }
 
 template <class Overload, class Self>
-prefix_ Self senf::console::ParsedArgumentAttributorBase<Overload,Self>::
+prefix_ Self senf::console::ParsedArgumentAttributorBase<Overload,Self,void>::
 overloadDoc(std::string const & doc)
     const
 {
@@ -146,7 +180,7 @@ overloadDoc(std::string const & doc)
 
 template <class Overload, class Self>
 prefix_
-senf::console::ParsedArgumentAttributorBase<Overload,Self>::
+senf::console::ParsedArgumentAttributorBase<Overload,Self,void>::
 ParsedArgumentAttributorBase(Overload & overload, unsigned index)
     : ParsedCommandAttributor<Overload> (overload, index)
 {}
@@ -379,23 +413,6 @@ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & n
                              senf::membind(fn,&owner)) ) );
 }
 
-///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::CheckVoidReturn<Type>
-
-template <class Type>
-template <class Fn>
-prefix_ void senf::console::detail::CheckVoidReturn<Type>::call(Fn fn, std::ostream & os)
-{
-    ReturnValueTraits<Type>::format(fn(),os);
-    os << "\n";
-}
-
-template <class Fn>
-prefix_ void senf::console::detail::CheckVoidReturn<void>::call(Fn fn, std::ostream & os)
-{
-    fn();
-}
-
 ///////////////////////////////cti.e///////////////////////////////////////
 #undef prefix_
 
index 75724a8..a4ef298 100644 (file)
@@ -168,8 +168,11 @@ namespace console {
         \c std::ostream first argument.
 
         \implementation This class is specialized for each supported number of command arguments.
+
+        \todo Implement automatic binding of member functions for parser and formatter
      */
-    template <class FunctionTraits, unsigned arity=FunctionTraits::arity>
+    template <class FunctionTraits, class ReturnType=typename FunctionTraits::result_type, 
+              unsigned arity=FunctionTraits::arity>
     class ParsedCommandOverload : public ParsedCommandOverloadBase
     {
     public:
@@ -213,12 +216,11 @@ namespace console {
         template <class Type> void defaultValue(Type const & value) const;
         void typeName(std::string const & doc) const;
         void defaultDoc(std::string const & doc) const;
-        template <class Type, class Fn> void parser(Fn fn) const;
 
         ParsedCommandOverloadBase & overload() const;
         void overloadDoc(std::string const & doc) const;
-
         void nodeDoc(std::string const & doc) const;
+        template <class Type, class Fn> void parser(Fn fn) const;
         
     private:
         ParsedCommandOverloadBase & overload_;
@@ -404,13 +406,14 @@ namespace console {
 
         \see \ref console_autoparse
      */
-    template <class Overload, class Self>
+    template <class Overload, class Self, class ReturnType=typename Overload::traits::result_type>
     class ParsedArgumentAttributorBase
         : public ParsedCommandAttributor<Overload>
     {
     public:
         Self doc(std::string const & doc) const; ///< Set documentation for all overloads
         Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
+        Self formatter(typename Overload::Formatter f) const; ///< Set return value formatter
 
     protected:
         ParsedArgumentAttributorBase(Overload & overload, unsigned index);
@@ -418,6 +421,23 @@ namespace console {
     private:
     };
 
+#ifndef DOXYGEN
+
+    template <class Overload, class Self>
+    class ParsedArgumentAttributorBase<Overload, Self, void>
+        : public ParsedCommandAttributor<Overload>
+    {
+    public:
+        Self doc(std::string const & doc) const; ///< Set documentation for all overloads
+        Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
+
+    protected:
+        ParsedArgumentAttributorBase(Overload & overload, unsigned index);
+
+    private:
+    };
+
+#endif
     
     /** \brief Argument dependent ParsedCommandBase attributes
 
index 19a4de6..d4a89f8 100644 (file)
@@ -106,25 +106,13 @@ namespace detail {
             base_traits>
         ::type traits;
 
+        typedef typename senf::remove_cvref<typename base_traits::result_type>::type result_type;
+
         static const bool is_member = boost::is_member_pointer<base_type>::value;
         
         typedef typename senf::member_class<base_type>::type class_type;
     };
 
-    template <class Type>
-    struct CheckVoidReturn
-    {
-        template <class Fn>
-        static void call(Fn fn, std::ostream & os);
-    };
-
-    template <>
-    struct CheckVoidReturn<void>
-    {
-        template <class Fn>
-        static void call(Fn fn, std::ostream & os);
-    };
-
 #endif
 
 }}}
index f1d6833..bfa3ef3 100644 (file)
@@ -50,7 +50,7 @@
 #define mpp_ArgTypes_(z,n,d) typename traits::mpp_ArgTypeN(n)
 #define mpp_TrailingArgTypes() BOOST_PP_ENUM_TRAILING( BOOST_PP_ITERATION(), mpp_ArgTypes_, _ )
 
-#define mpp_Args_(z,n,d) boost::cref(mpp_ArgN(n))
+#define mpp_Args_(z,n,d) mpp_ArgN(n)
 #define mpp_TrailingArgs() BOOST_PP_ENUM_TRAILING( BOOST_PP_ITERATION(), mpp_Args_, _ )
 
 #define mpp_BindArgs_(z,n,d) BOOST_PP_CAT( _, BOOST_PP_INC(BOOST_PP_INC(n)))
 
 // Header file (.hh)
 
+template <class FunctionTraits, class ReturnValue>
+class ParsedCommandOverload<FunctionTraits, ReturnValue, BOOST_PP_ITERATION() >
+    : public ParsedCommandOverloadBase
+{
+public:
+    typedef boost::intrusive_ptr<ParsedCommandOverload> ptr;
+    typedef FunctionTraits traits;
+    typedef boost::function<typename traits::result_type(std::ostream &
+                                                         mpp_TrailingArgTypes())> Function;
+    typedef typename senf::remove_cvref<typename traits::result_type>::type result_type;
+    typedef boost::function<void (result_type const &, std::ostream &)> Formatter;
+
+#   define mpp_l(z,n,d)                                                                           \
+        typedef typename senf::remove_cvref< typename traits::mpp_ArgTypeN(n) >::type             \
+            mpp_ArgTypeN(n);
+    BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l, _ )
+#   undef mpp_l
+
+    static ptr create(Function fn);
+
+    void formatter(Formatter f);
+
+protected:
+
+private:
+    ParsedCommandOverload(Function fn);
+
+    virtual void v_execute(std::ostream & os, ParseCommandInfo const & command) const;
+
+    Function function_;
+    Formatter formatter_;
+};
+
 template <class FunctionTraits>
-class ParsedCommandOverload<FunctionTraits, BOOST_PP_ITERATION() >
+class ParsedCommandOverload<FunctionTraits, void, BOOST_PP_ITERATION() >
     : public ParsedCommandOverloadBase
 {
 public:
@@ -71,6 +104,7 @@ public:
     typedef FunctionTraits traits;
     typedef boost::function<typename traits::result_type(std::ostream &
                                                          mpp_TrailingArgTypes())> Function;
+    typedef void result_type;
 
 #   define mpp_l(z,n,d)                                                                           \
         typedef typename senf::remove_cvref< typename traits::mpp_ArgTypeN(n) >::type             \
@@ -96,16 +130,44 @@ private:
 
 // inline template implementation (.cti)
 
+template <class FunctionTraits, class ReturnValue>
+prefix_ typename senf::console::ParsedCommandOverload<FunctionTraits, ReturnValue, BOOST_PP_ITERATION() >::ptr
+senf::console::ParsedCommandOverload<FunctionTraits, ReturnValue, BOOST_PP_ITERATION() >::
+create(Function fn)
+{
+    return ptr(new ParsedCommandOverload(fn));
+}
+
+template <class FunctionTraits, class ReturnValue>
+void
+senf::console::ParsedCommandOverload<FunctionTraits, ReturnValue, BOOST_PP_ITERATION() >::
+formatter(Formatter f)
+{
+    formatter_ = f;
+}
+
+template <class FunctionTraits, class ReturnValue>
+prefix_
+senf::console::ParsedCommandOverload<FunctionTraits, ReturnValue, BOOST_PP_ITERATION()>::
+ParsedCommandOverload(Function fn)
+    : function_ (fn) 
+{
+#   define mpp_l(z,n,d) addParameter< mpp_ArgTypeN(n) >();
+    BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l, _ )
+#   undef mpp_l
+}
+
 template <class FunctionTraits>
-prefix_ typename senf::console::ParsedCommandOverload<FunctionTraits, BOOST_PP_ITERATION() >::ptr
-senf::console::ParsedCommandOverload<FunctionTraits, BOOST_PP_ITERATION() >::create(Function fn)
+prefix_ typename senf::console::ParsedCommandOverload<FunctionTraits, void, BOOST_PP_ITERATION() >::ptr
+senf::console::ParsedCommandOverload<FunctionTraits, void, BOOST_PP_ITERATION() >::
+create(Function fn)
 {
     return ptr(new ParsedCommandOverload(fn));
 }
 
 template <class FunctionTraits>
 prefix_
-senf::console::ParsedCommandOverload<FunctionTraits,BOOST_PP_ITERATION()>::
+senf::console::ParsedCommandOverload<FunctionTraits, void, BOOST_PP_ITERATION() >::
 ParsedCommandOverload(Function fn)
     : function_ (fn) 
 {
@@ -120,8 +182,44 @@ ParsedCommandOverload(Function fn)
 
 // non-inline template implementation (.ct)
 
+template <class FunctionTraits, class ReturnValue>
+prefix_ void senf::console::ParsedCommandOverload<FunctionTraits, ReturnValue, BOOST_PP_ITERATION() >::
+v_execute(std::ostream & os, ParseCommandInfo const & command)
+    const
+{
+    if ( command.arguments().size() > BOOST_PP_ITERATION() )
+        throw SyntaxErrorException("invalid number of arguments");
+    int nDefaults ( BOOST_PP_ITERATION() - command.arguments().size() );
+
+    typedef typename boost::range_const_reverse_iterator<ParseCommandInfo::ArgumentsRange>::type
+        riterator;
+    riterator i (boost::rbegin(command.arguments()));
+    riterator const i_end (boost::rend(command.arguments()));
+
+#   define mpp_l(z,n,d)                                                                           \
+        mpp_ArgTypeN(n) mpp_ArgN(n) (arg< mpp_ArgTypeN(n) >( n ).defaultValue);                   \
+        if (! arg(n).hasDefault || nDefaults-- <= 0) {                                            \
+            if (i == i_end)                                                                       \
+                throw SyntaxErrorException("invalid number of arguments");                        \
+            if (arg< mpp_ArgTypeN(n) >(n).parser)                                                 \
+                arg< mpp_ArgTypeN(n) >(n).parser( *(i++), mpp_ArgN(n) );                          \
+            else                                                                                  \
+                ArgumentTraits< mpp_ArgTypeN(n) >::parse( *(i++), mpp_ArgN(n) );                  \
+        }
+#   define mpp_l_(z,n,d) mpp_l(z, BOOST_PP_SUB(BOOST_PP_DEC(BOOST_PP_ITERATION()), n), d)
+    BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l_, _ ) 
+#   undef mpp_l
+#   undef mpp_l_
+
+    if (formatter_)
+        formatter_( function_(os mpp_TrailingArgs()), os );
+    else
+        ReturnValueTraits<result_type>::format( function_(os mpp_TrailingArgs()), os );
+    os << "\n";
+}
+
 template <class FunctionTraits>
-prefix_ void senf::console::ParsedCommandOverload<FunctionTraits, BOOST_PP_ITERATION() >::
+prefix_ void senf::console::ParsedCommandOverload<FunctionTraits, void, BOOST_PP_ITERATION() >::
 v_execute(std::ostream & os, ParseCommandInfo const & command)
     const
 {
@@ -149,10 +247,7 @@ v_execute(std::ostream & os, ParseCommandInfo const & command)
 #   undef mpp_l
 #   undef mpp_l_
 
-    detail::CheckVoidReturn<typename traits::result_type>::call(
-        boost::bind(function_, boost::ref(os)
-                    mpp_TrailingArgs()),
-        os );
+    function_(os mpp_TrailingArgs());
 }
 
 // ////////////////////////////////////////////////////////////////////////
index 39f028d..a9e47a4 100644 (file)
@@ -58,6 +58,8 @@ namespace {
             { out = "true"; }
     };
 
+    void testFormatter(double, std::ostream & os)
+    { os << "formatter"; }
 }
 
 BOOST_AUTO_UNIT_TEST(parsedCommand)
@@ -137,7 +139,17 @@ BOOST_AUTO_UNIT_TEST(parsedCommand)
             parser.parse("test/cb6 false",
                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
         BOOST_CHECK_EQUAL( ss.str(), "Value: true\n" );
-                     
+    }
+
+    {
+        std::stringstream ss;
+
+        dir.add("cb7", &cb2)
+            .formatter( &testFormatter );
+        BOOST_CHECK_NO_THROW(
+            parser.parse("test/cb7",
+                         boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
+        BOOST_CHECK_EQUAL( ss.str(), "formatter\n" );
     }
 
     {