[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [akonadi-next/feature/new_cli] akonadi2_cli: vastly simplify by getting rid of Module as a base clas
From:       Aaron Seigo <aseigo () kde ! org>
Date:       2015-12-23 11:09:12
Message-ID: E1aBhI8-0008IN-AY () scm ! kde ! org
[Download RAW message or body]

Git commit 071f4ef0122a8bfceeda9a10b41e85ad9a34a28d by Aaron Seigo.
Committed on 23/12/2015 at 10:43.
Pushed by aseigo into branch 'feature/new_cli'.

vastly simplify by getting rid of Module as a base class

just a move slightly more towards functional

M  +7    -4    akonadi2_cli/CMakeLists.txt
M  +1    -4    akonadi2_cli/main.cpp
M  +41   -75   akonadi2_cli/module.cpp
M  +25   -16   akonadi2_cli/module.h
R  +19   -14   akonadi2_cli/modules/core_syntax.cpp [from: \
akonadi2_cli/modules/help/help.cpp - 070% similarity] R  +5    -12   \
akonadi2_cli/modules/core_syntax.h [from: akonadi2_cli/modules/exit/exit.h - 083% \
similarity] D  +0    -39   akonadi2_cli/modules/exit/exit.cpp
D  +0    -37   akonadi2_cli/modules/help/help.h
M  +2    -2    akonadi2_cli/repl/replStates.cpp

http://commits.kde.org/akonadi-next/071f4ef0122a8bfceeda9a10b41e85ad9a34a28d

diff --git a/akonadi2_cli/CMakeLists.txt b/akonadi2_cli/CMakeLists.txt
index b5bdb46..a07140e 100644
--- a/akonadi2_cli/CMakeLists.txt
+++ b/akonadi2_cli/CMakeLists.txt
@@ -3,14 +3,17 @@ project(akonadi2_cli)
 find_package(Readline REQUIRED)
 
 
-set(akonadi2_SRCS
+set(akonadi2_cli_SRCS
     main.cpp
     module.cpp
-    modules/exit/exit.cpp
-    modules/help/help.cpp
+    modules/core_syntax.cpp
     repl/repl.cpp
     repl/replStates.cpp
     state.cpp)
 
-add_executable(${PROJECT_NAME} ${akonadi2_SRCS})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+
+add_executable(${PROJECT_NAME} ${akonadi2_cli_SRCS})
+target_link_libraries(${PROJECT_NAME} Qt5::Core ${Readline_LIBRARY})
+install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
 
diff --git a/akonadi2_cli/main.cpp b/akonadi2_cli/main.cpp
index 1a036d0..d23e070 100644
--- a/akonadi2_cli/main.cpp
+++ b/akonadi2_cli/main.cpp
@@ -36,9 +36,6 @@
 
 int main(int argc, char *argv[])
 {
-    // load all modules
-    Module::loadModules();
-
     const bool interactive = isatty(fileno(stdin));
     const bool startRepl = (argc == 1) && interactive;
     //TODO: make a json command parse cause that would be awesomesauce
@@ -67,5 +64,5 @@ int main(int argc, char *argv[])
 
     QStringList commands = app.arguments();
     commands.removeFirst();
-    return Module::run(commands);
+    return Module::self()->run(commands);
 }
diff --git a/akonadi2_cli/module.cpp b/akonadi2_cli/module.cpp
index 0b83d98..dfc58c8 100644
--- a/akonadi2_cli/module.cpp
+++ b/akonadi2_cli/module.cpp
@@ -24,83 +24,61 @@
 
 // TODO: needs a proper registry; making "core" modules plugins is
 //       almost certainly overkill, but this is not the way either
-#include "modules/exit/exit.h"
-#include "modules/help/help.h"
+#include "modules/core_syntax.h"
 
-QList<Module> Module::s_modules;
-State Module::s_state;
+Module *Module::s_module = 0;
 
 Module::Syntax::Syntax()
 {
 }
 
-Module::Syntax::Syntax(const QString &k, std::function<bool(const QStringList &, \
State &)> l, const QString &helpText, bool e) +Module::Syntax::Syntax(const QString \
&k, const QString &helpText, std::function<bool(const QStringList &, State &)> l, \
Interactivity inter)  : keyword(k),
-      lambda(l),
       help(helpText),
-      eventDriven(e)
+      interactivity(inter),
+      lambda(l)
 {
 }
 
 Module::Module()
 {
+    QVector<std::function<SyntaxList()> > syntaxModules;
+    syntaxModules << &CoreSyntax::syntax;
+    for (auto syntaxModule: syntaxModules) {
+        m_syntax += syntaxModule();
+    }
 }
 
-void Module::loadModules()
-{
-    addModule(CLI::Exit());
-    addModule(CLI::Help());
-}
-
-void Module::addModule(const Module &module)
-{
-    s_modules.append(module);
-}
-
-QList<Module> Module::modules()
-{
-    return s_modules;
-}
-
-Module::Command Module::match(const QStringList &commands)
+Module *Module::self()
 {
-    Command command;
-    for (const Module &module: s_modules) {
-        command = module.matches(commands);
-        if (command.first) {
-            break;
-        }
+    if (!s_module) {
+        s_module = new Module;
     }
 
-    return command;
+    return s_module;
 }
 
-Module::Syntax Module::syntax() const
+Module::SyntaxList Module::syntax() const
 {
     return m_syntax;
 }
 
-void Module::setSyntax(const Syntax &syntax)
-{
-    m_syntax = syntax;
-}
-
 bool Module::run(const QStringList &commands)
 {
     Command command = match(commands);
     if (command.first && command.first->lambda) {
-        bool rv = command.first->lambda(command.second, s_state);
-        if (rv && command.first->eventDriven) {
+        command.first->lambda(command.second, m_state);
+        if (command.first->interactivity == Syntax::EventDriven) {
             return QCoreApplication::instance()->exec();
         }
 
-        return rv;
+        return true;
     }
 
     return false;
 }
 
-Module::Command Module::matches(const QStringList &commandLine) const
+Module::Command Module::match(const QStringList &commandLine) const
 {
     if (commandLine.isEmpty()) {
         return Command();
@@ -108,20 +86,16 @@ Module::Command Module::matches(const QStringList &commandLine) \
const  
     QStringListIterator commandLineIt(commandLine);
 
-    if (commandLineIt.next() != m_syntax.keyword) {
-        return Command();
-    }
-
-    QListIterator<Syntax> syntaxIt(m_syntax.children);
-    const Syntax *syntax = &m_syntax;
+    QVectorIterator<Syntax> syntaxIt(m_syntax);
+    const Syntax *lastFullSyntax = 0;
     QStringList tailCommands;
     while (commandLineIt.hasNext() && syntaxIt.hasNext()) {
         const QString word = commandLineIt.next();
         while (syntaxIt.hasNext()) {
-            const Syntax &child = syntaxIt.next();
-            if (word == child.keyword) {
-                syntax = &child;
-                syntaxIt = child.children;
+            const Syntax &syntax = syntaxIt.next();
+            if (word == syntax.keyword) {
+                lastFullSyntax = &syntax;
+                syntaxIt = syntax.children;
             }
         }
 
@@ -131,55 +105,47 @@ Module::Command Module::matches(const QStringList &commandLine) \
const  }
     }
 
-    if (syntax && syntax->lambda) {
+    if (lastFullSyntax && lastFullSyntax->lambda) {
         while (commandLineIt.hasNext()) {
             tailCommands << commandLineIt.next();
         }
 
-        return std::make_pair(syntax, tailCommands);
+        return std::make_pair(lastFullSyntax, tailCommands);
     }
 
     return Command();
 }
 
-QVector<Module::Syntax> Module::nearestSyntax(const QStringList &words, const \
QString &fragment) +Module::SyntaxList Module::nearestSyntax(const QStringList \
&words, const QString &fragment) const  {
-    QVector<Module::Syntax> matches;
+    SyntaxList matches;
 
     //qDebug() << "words are" << words;
     if (words.isEmpty()) {
-        for (const Module &module: s_modules) {
-            if (module.syntax().keyword.startsWith(fragment)) {
-                matches.push_back(module.syntax());
+        for (const Syntax &syntax: m_syntax) {
+            if (syntax.keyword.startsWith(fragment)) {
+                matches.push_back(syntax);
             }
         }
     } else {
         QStringListIterator wordIt(words);
-        QString word = wordIt.next();
+        QVectorIterator<Syntax> syntaxIt(m_syntax);
         Syntax lastFullSyntax;
 
-        for (const Module &module: s_modules) {
-            if (module.syntax().keyword == word) {
-                lastFullSyntax = module.syntax();
-                QListIterator<Syntax> syntaxIt(module.syntax().children);
-                while (wordIt.hasNext()) {
-                    word = wordIt.next();
-                    while (syntaxIt.hasNext()) {
-                        const Syntax &child = syntaxIt.next();
-                        if (word == child.keyword) {
-                            lastFullSyntax = child;
-                            syntaxIt = child.children;
-                        }
-                    }
+        while (wordIt.hasNext()) {
+            QString word = wordIt.next();
+            while (syntaxIt.hasNext()) {
+                const Syntax &syntax = syntaxIt.next();
+                if (word == syntax.keyword) {
+                    lastFullSyntax = syntax;
+                    syntaxIt = syntax.children;
                 }
-
-                break;
             }
         }
 
         //qDebug() << "exiting with" << lastFullSyntax.keyword << words.last();
         if (lastFullSyntax.keyword == words.last()) {
-            QListIterator<Syntax> syntaxIt(lastFullSyntax.children);
+            syntaxIt = lastFullSyntax.children;
             while (syntaxIt.hasNext()) {
                 Syntax syntax = syntaxIt.next();
                 if (fragment.isEmpty() || syntax.keyword.startsWith(fragment)) {
diff --git a/akonadi2_cli/module.h b/akonadi2_cli/module.h
index 4f426b8..d2745d0 100644
--- a/akonadi2_cli/module.h
+++ b/akonadi2_cli/module.h
@@ -29,33 +29,42 @@ class Module
 public:
     struct Syntax
     {
+        enum Interactivity {
+            NotInteractive = 0,
+            EventDriven
+        };
+
         Syntax();
-        Syntax(const QString &keyword, std::function<bool(const QStringList &, State \
&)> lambda = std::function<bool(const QStringList &, State &)>(), const QString \
&helpText = QString(), bool eventDriven = false); +        Syntax(const QString \
&keyword, +               const QString &helpText = QString(),
+               std::function<bool(const QStringList &, State &)> lambda = \
std::function<bool(const QStringList &, State &)>(), +               Interactivity \
interactivity = NotInteractive); +
         QString keyword;
-        std::function<bool(const QStringList &, State &)> lambda;
-        QList<Syntax> children;
         QString help;
-        bool eventDriven;
+        Interactivity interactivity;
+        std::function<bool(const QStringList &, State &)> lambda;
+
+        QVector<Syntax> children;
     };
 
     typedef std::pair<const Syntax *, QStringList> Command;
+    typedef QVector<Module::Syntax> SyntaxList;
 
-    static void addModule(const Module &module);
-    static QList<Module> modules();
-    static Command match(const QStringList &commands);
-    static bool run(const QStringList &commands);
-    static void loadModules();
-    static QVector<Syntax>nearestSyntax(const QStringList &words, const QString \
&fragment); +    static Module *self();
 
-    Module();
-    Module::Syntax syntax() const;
-    void setSyntax(const Syntax &syntax);
+    SyntaxList syntax() const;
+    Command match(const QStringList &commands) const;
+    SyntaxList nearestSyntax(const QStringList &words, const QString &fragment) \
const; +
+    bool run(const QStringList &commands);
 
 private:
+    Module();
     Command matches(const QStringList &commands) const;
 
-    Syntax m_syntax;
-    static QList<Module> s_modules;
-    static State s_state;
+    SyntaxList m_syntax;
+    State m_state;
+    static Module *s_module;
 };
 
diff --git a/akonadi2_cli/modules/help/help.cpp \
b/akonadi2_cli/modules/core_syntax.cpp similarity index 70%
rename from akonadi2_cli/modules/help/help.cpp
rename to akonadi2_cli/modules/core_syntax.cpp
index aaff6fb..8324c31 100644
--- a/akonadi2_cli/modules/help/help.cpp
+++ b/akonadi2_cli/modules/core_syntax.cpp
@@ -17,39 +17,45 @@
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
  */
 
-#include "help.h"
+#include "core_syntax.h"
 
-#include <QObject>
+#include <QObject> // tr()
 #include <QSet>
 #include <QTextStream>
 
-#include "module.h"
+namespace CoreSyntax
+{
 
-namespace CLI
+Module::SyntaxList syntax()
 {
+    Module::SyntaxList syntax;
+    syntax << Module::Syntax("exit", QObject::tr("Exits the application. Ctrl-d also \
works!"), &CoreSyntax::exit); +    syntax << Module::Syntax(QObject::tr("help"), \
QObject::tr("Print command information: help [command]"), &CoreSyntax::showHelp); +   \
return syntax; +}
 
-Help::Help()
+bool exit(const QStringList &, State &)
 {
-    Syntax topLevel = Syntax(QObject::tr("help"), &Help::showHelp, \
                QObject::tr("Print command information: help [command]"));
-    setSyntax(topLevel);
+    ::exit(0);
+    return true;
 }
 
-bool Help::showHelp(const QStringList &commands, State &)
+bool showHelp(const QStringList &commands, State &)
 {
-    Module::Command command = Module::match(commands);
+    Module::Command command = Module::self()->match(commands);
     QTextStream stream(stdout);
     if (commands.isEmpty()) {
         stream << QObject::tr("Welcome to the Akonadi2 command line tool!") << "\n";
         stream << QObject::tr("Top-level commands:") << "\n";
         QSet<QString> sorted;
-        for (auto module: Module::modules()) {
-            sorted.insert(module.syntax().keyword);
+        for (auto syntax: Module::self()->syntax()) {
+            sorted.insert(syntax.keyword);
         }
 
         for (auto keyword: sorted) {
             stream << "\t" << keyword << "\n";
         }
-    } else if (const Syntax *syntax = command.first) {
+    } else if (const Module::Syntax *syntax = command.first) {
         //TODO: get parent!
         stream << QObject::tr("Command `%1`").arg(syntax->keyword);
 
@@ -72,9 +78,8 @@ bool Help::showHelp(const QStringList &commands, State &)
     } else {
         stream << "Unknown command: " << commands.join(" ") << "\n";
     }
-
     return true;
 }
 
-} // namespace CLI
+} // namespace CoreSyntax
 
diff --git a/akonadi2_cli/modules/exit/exit.h b/akonadi2_cli/modules/core_syntax.h
similarity index 83%
rename from akonadi2_cli/modules/exit/exit.h
rename to akonadi2_cli/modules/core_syntax.h
index 5ed4174..beb8528 100644
--- a/akonadi2_cli/modules/exit/exit.h
+++ b/akonadi2_cli/modules/core_syntax.h
@@ -21,17 +21,10 @@
 
 #include "module.h"
 
-namespace CLI
+namespace CoreSyntax
 {
-
-class Exit : public Module
-{
-public:
-    Exit();
-
-private:
-    static bool exit(const QStringList &commands, State &state);
-};
-
-} // namespace CLI
+    Module::SyntaxList syntax();
+    bool exit(const QStringList &commands, State &state);
+    bool showHelp(const QStringList &commands, State &);
+}
 
diff --git a/akonadi2_cli/modules/exit/exit.cpp b/akonadi2_cli/modules/exit/exit.cpp
deleted file mode 100644
index 64828be..0000000
--- a/akonadi2_cli/modules/exit/exit.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the
- *   Free Software Foundation, Inc.,
- *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- */
-
-#include "exit.h"
-
-#include <QObject>
-
-namespace CLI
-{
-
-Exit::Exit()
-{
-    setSyntax(Syntax("exit", &Exit::exit, QObject::tr("Exits the application. Ctrl-d \
                also works!")));
-}
-
-bool Exit::exit(const QStringList &, State &)
-{
-    ::exit(0);
-    return true;
-}
-
-} // namespace CLI
-
diff --git a/akonadi2_cli/modules/help/help.h b/akonadi2_cli/modules/help/help.h
deleted file mode 100644
index df1cfc2..0000000
--- a/akonadi2_cli/modules/help/help.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the
- *   Free Software Foundation, Inc.,
- *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- */
-
-#pragma once
-
-#include "module.h"
-
-namespace CLI
-{
-
-class Help : public Module
-{
-public:
-    Help();
-
-private:
-    static bool showHelp(const QStringList &commands, State &state);
-};
-
-} // namespace CLI
-
diff --git a/akonadi2_cli/repl/replStates.cpp b/akonadi2_cli/repl/replStates.cpp
index e87dd5f..efa1353 100644
--- a/akonadi2_cli/repl/replStates.cpp
+++ b/akonadi2_cli/repl/replStates.cpp
@@ -107,7 +107,7 @@ void EvalState::onEntry(QEvent *event)
         if (m_complete) {
             //emit output("Processing ... " + command);
             const QStringList commands = command.split(" ");
-            Module::run(commands);
+            Module::self()->run(commands);
             emit completed();
         }
     }
@@ -143,7 +143,7 @@ static char **akonadi2_cli_tab_completion(const char *text, int \
start, int end)  
 static char *akonadi2_cli_next_tab_complete_match(const char *text, int state)
 {
-    QVector<Module::Syntax> nearest = \
Module::nearestSyntax(tab_completion_full_state, QString(text)); +    \
QVector<Module::Syntax> nearest = \
Module::self()->nearestSyntax(tab_completion_full_state, QString(text));  
     if (nearest.size() > state) {
         return qstrdup(nearest[state].keyword.toUtf8());


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic