2
\$\begingroup\$

After my previous code review, I'm sharing my new code, and asking for better ways (which always exist) to improve the code, even with new libraries. The only thing that important to me, is the way of receiving the parameters have to be the command line [I am using Linux OS, so it's highly common to use command line params].

Project hierarchy:

+src // All project's code
|
| --+ cmd // Command Line options parse & process 
|   |
|   | --- cmd_options_basic_data    // Inputs
|   | --- cmd_options_parser        // User inputs parser
|   | --- cmd_options_processor     // Inputs processor
|   | --- cmd_options_progress_data // Extra data from basic inputs
|   |
|
| --+ core // Project core algorithms
|   |
|   | --- activity_analyzer         // Main project's target - analyze a logger file
|   | --- anomalies_detector        // Detect anomalies in logger
|   | --- log_handler               // Call activity_analyzer / anomalies_detector as needed by user's input
|   |
|
| --+ useful_collections
|   |
|   | --- day                       // Single day class
|   | --- week                      // Days collection
|   | --- time_container            // Analyzer single time container (e.g. Day total time / Week total time / Weekend percents).
|   |
|
| --+ utilities // Libraries extensions & Exceptions
|   |
|   | --- boost_extensions
|   | --- std_extensions
|   | --- design_text               // Self made library to color text
|   | --- exceptions                // Relevant exceptions in project
|   |
|
| --- main
|

References


EDIT:

Points for CR:

  • Project hierarchy
  • Recommended libraries that can make the code cleaner.
  • Classes / Namespaces separation improvements.
  • New C++17/2a features that can improve this code.
  • Unclear code areas that requires more comments.

Selected code snippets

main.cpp

#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/date_time.hpp>
#include "useful_collections/week.h"
#include "core/log_handler.h"
#include "utilities/design_text.h"
#include "cmd/cmd_options_parser.h"
#include "cmd/cmd_options_processor.h"
#include "utilities/exceptions.h"

int main(int ac, char* av[]) {
    cmd_options_parser command_line_options(ac, av);
    cmd_options_basic_data cmd_basic_data = command_line_options.get_data();
    cmd_options_processor cmd_processor(cmd_basic_data);
    cmd_options_progress_data cmd_progress_data;

    /// Process basic cmd params
    try {
        cmd_progress_data = cmd_processor.process_basic_cmd_data();
    } catch (exceptions::HelpMessageProducedException &) {
        return EXIT_SUCCESS;
    } catch (exceptions::FileNotFoundException &file_not_found_e) {
        std::cerr << file_not_found_e.what() << std::endl;
        return EXIT_FAILURE;
    } catch (std::exception &e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    /// Log handler initialize
    log_handler log_analyzer(
            cmd_basic_data.analyze_verbose,
            cmd_basic_data.analyze_activity,
            cmd_basic_data.log_file_path,
            cmd_basic_data.anomaly_detection,
            cmd_basic_data.normal_login_word
    );
    log_analyzer.config_analyzer_params(cmd_progress_data.week_start_day, cmd_basic_data.sleep_hours_per_day, cmd_basic_data.study_hours_in_week);

    /// Log handler process
    log_analyzer.process();

    return EXIT_SUCCESS;
}

week.h

#ifndef COMPUTERMONITORINGSTATISTICSPARSER_WEEK_H
#define COMPUTERMONITORINGSTATISTICSPARSER_WEEK_H

#include <iostream>
#include "day.h"

class week {
public:
    /**
     * Ctor
     *
     * @brief Initialize days list
     */
    explicit week();

    /**
     * @brief Prints days list
     */
    std::string get_textual_days_list() const;

    /**
     * @brief Get day object that represent the given day_name
     *
     * @param day_name - Day's full / short name.
     *
     * @note non-case sensitivity
     *
     * @throw DayNotFoundException - if given day not found in days_list.
     *
     * @return day object of the given string day
     */
    day get_day(const std::string &day_name) const;

private:
    void initialize_days_list();

    std::vector<day> days_list;
};

std::ostream& operator<<(std::ostream& cout, const week& week_ref);

#endif //COMPUTERMONITORINGSTATISTICSPARSER_WEEK_H

week.cpp

#include "week.h"
#include "../utilities/exceptions.h"

week::week() {
    initialize_days_list();
}

std::string week::get_textual_days_list() const {
    std::stringstream ss;
    ss << "Available days:\n";
    ss << "\tSun [Sunday]\n";
    ss << "\tMon [Monday]\n";
    ss << "\tTue [Tuesday]\n";
    ss << "\tWed [Wednesday]\n";
    ss << "\tThu [Thursday]\n";
    ss << "\tFri [Friday]\n";
    ss << "\tSat [Saturday]" << std::endl;
    return ss.str();
}

day week::get_day(const std::string &day_name) const {
    if (auto selected_day = std::find(days_list.begin(), days_list.end(), boost::to_lower_copy(day_name));
            selected_day != days_list.end()) { // Selected day exists
        return *selected_day;
    }
    if (day_name == "help") {
        std::cout << *this << std::endl;
        throw exceptions::HelpMessageProducedException();
    }
    throw exceptions::DayNotFoundException();
}

void week::initialize_days_list() {
    days_list = {
            {"sunday",    boost::date_time::weekdays::Sunday},
            {"monday",    boost::date_time::weekdays::Monday},
            {"tuesday",   boost::date_time::weekdays::Tuesday},
            {"wednesday", boost::date_time::weekdays::Wednesday},
            {"thursday",  boost::date_time::weekdays::Thursday},
            {"friday",    boost::date_time::weekdays::Friday},
            {"saturday",  boost::date_time::weekdays::Saturday}
    };
}

std::ostream& operator<<(std::ostream& cout, const week& week_ref) {
    return cout << week_ref.get_textual_days_list();
}

cmd_options_parser.h & cmd_options_parser.cpp
Almost no changes from the last time. Previously called cmd_options.h/.cpp.

cmd_options_processor.h

#ifndef COMPUTERMONITORINGSTATISTICSPARSER_CMD_OPTIONS_PROCESSOR_H
#define COMPUTERMONITORINGSTATISTICSPARSER_CMD_OPTIONS_PROCESSOR_H

#include <iostream>
#include <boost/date_time/date_defs.hpp>
#include "cmd_options_basic_data.h"
#include "cmd_options_progress_data.h"

class cmd_options_processor {
public:

    /**
     * Ctor
     *
     * @brief initialize _options_data
     */
    explicit cmd_options_processor(const cmd_options_basic_data &options_data);

    /**
     * @brief Call basic params handlers
     *
     * @throw HelpMessageProducedException
     * @throw FileNotFoundException
     * @throw std::runtime_error - if unexpected error occurred
     */
    [[nodiscard]] cmd_options_progress_data process_basic_cmd_data() const;

private:

    /**
     * @brief --help / -h option handler
     *
     * @throw HelpMessageProducedException - if help flag was on
     */
    void help_message_handler() const;

    /**
     * @brief --log-path / -l option handler
     *
     * @throw FileNotFoundException - if logger file not found
     */
    void logger_path_handler() const;

    /**
     * @brief --week-start-day / -d option handler
     *
     * @throw HelpMessageProducedException - if day not found.
     * @throw std::runtime_error - if unexpected error occurred during the day search.
     *
     * @return week_start_day member value of cmd_options_progress_data
     */
    [[nodiscard]] boost::date_time::weekdays week_start_day_handler() const;

    cmd_options_basic_data _options_data;
};


#endif //COMPUTERMONITORINGSTATISTICSPARSER_CMD_OPTIONS_PROCESSOR_H

cmd_options_processor.cpp

#include "cmd_options_processor.h"
#include "../utilities/exceptions.h"
#include "../useful_collections/week.h"
#include "../core/log_handler.h"
#include <boost/filesystem.hpp>

cmd_options_processor::cmd_options_processor(const cmd_options_basic_data &options_data)
        : _options_data(options_data) {
}

cmd_options_progress_data cmd_options_processor::process_basic_cmd_data() const {
    try {
        cmd_options_progress_data extracted_data;
        help_message_handler();
        logger_path_handler();
        extracted_data.week_start_day = week_start_day_handler();
        return extracted_data;
    } catch (...) {
        throw;
    }
}

void cmd_options_processor::help_message_handler() const {
    if (_options_data.help) {
        std::cout << _options_data.visible_options << "\n";
        throw exceptions::HelpMessageProducedException();
    }
}

void cmd_options_processor::logger_path_handler() const {
    if (!boost::filesystem::exists(_options_data.log_file_path)) {
        throw exceptions::FileNotFoundException();
    }
}

boost::date_time::weekdays cmd_options_processor::week_start_day_handler() const {
    try {
        week w;
        return w.get_day(_options_data.week_start_day).day_symbol;
    } catch (exceptions::HelpMessageProducedException &hd_e) {
        throw;
    } catch (exceptions::DayNotFoundException &dnf_e) {
        std::cout << "Unfamiliar day, for options list use '-d [ --week-start-day ] help'." << std::endl;
        throw exceptions::HelpMessageProducedException();
    } catch (std::exception &e) {
        throw std::runtime_error("Unexpected error occurred during day searching.");
    }
}

log_handler.h

#ifndef COMPUTERMONITORINGSTATISTICSPARSER_LOG_HANDLER_H
#define COMPUTERMONITORINGSTATISTICSPARSER_LOG_HANDLER_H

#include <iostream>
#include <boost/date_time.hpp>
#include "../useful_collections/time_container.h"
#include "activity_analyzer.h"
#include "anomalies_detector.h"

class log_handler {
public:
    log_handler(bool analyze_verbose,
                bool enable_analyze,
            const std::string &log_path,
            bool anomalies_verbose,
            const std::string &normal_login_word);

    void config_analyzer_params(boost::date_time::weekdays week_start_day, u_short sleep_hours_per_day, u_short study_day_hours_in_week);

    void process();

private:

    activity_analyzer analyzer;
    anomalies_detector detector;
    bool enable_analyze;

};

#endif //COMPUTERMONITORINGSTATISTICSPARSER_LOG_HANDLER_H

log_handler.cpp

#include "log_handler.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <iomanip>
#include <chrono>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include "../utilities/std_extensions.h"
#include "../utilities/boost_extensions.h"
#include "../utilities/design_text.h"

using namespace design_text;

log_handler::log_handler(bool analyze_verbose,
                         bool enable_analyze,
                         const std::string &log_path,
                         bool anomalies_verbose,
                         const std::string &normal_login_word)
        : enable_analyze(enable_analyze),
          analyzer(analyze_verbose, log_path),
          detector(log_path, anomalies_verbose, normal_login_word) {
}

void log_handler::config_analyzer_params(boost::date_time::weekdays week_start_day, u_short sleep_hours_per_day, u_short study_day_hours_in_week) {
    analyzer.config_analyze_params(week_start_day, sleep_hours_per_day, study_day_hours_in_week);
}

void log_handler::process() {
    // Anomalies detector
    detector.detect();
    if (enable_analyze) // Analyze logger times
        analyzer.analyze();
    if (detector.is_error()) // Produce anomalies warning if needed
        std::cout << "\n\n" << design_text::make_colored(std::stringstream() << "*** Anomaly detected! ***", design_text::Color::NONE, design_text::Color::RED, true) << std::endl;
}
\$\endgroup\$
0

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.