Added regex support to elements filter
This commit is contained in:
@@ -216,7 +216,8 @@ tvl::value_t namespace_filter::match(
|
|||||||
[&e](const auto &nsit) { return e.get_namespace().starts_with(nsit); });
|
[&e](const auto &nsit) { return e.get_namespace().starts_with(nsit); });
|
||||||
}
|
}
|
||||||
|
|
||||||
element_filter::element_filter(filter_t type, std::vector<std::string> elements)
|
element_filter::element_filter(
|
||||||
|
filter_t type, std::vector<config::string_or_regex> elements)
|
||||||
: filter_visitor{type}
|
: filter_visitor{type}
|
||||||
, elements_{std::move(elements)}
|
, elements_{std::move(elements)}
|
||||||
{
|
{
|
||||||
@@ -227,8 +228,8 @@ tvl::value_t element_filter::match(
|
|||||||
{
|
{
|
||||||
return tvl::any_of(
|
return tvl::any_of(
|
||||||
elements_.begin(), elements_.end(), [&e](const auto &el) {
|
elements_.begin(), elements_.end(), [&e](const auto &el) {
|
||||||
return (e.full_name(false) == el) ||
|
return ((el == e.full_name(false)) ||
|
||||||
(fmt::format("::{}", e.full_name(false)) == el);
|
(el == fmt::format("::{}", e.full_name(false))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,14 +125,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct element_filter : public filter_visitor {
|
struct element_filter : public filter_visitor {
|
||||||
element_filter(filter_t type, std::vector<std::string> elements);
|
element_filter(
|
||||||
|
filter_t type, std::vector<config::string_or_regex> elements);
|
||||||
|
|
||||||
~element_filter() override = default;
|
~element_filter() override = default;
|
||||||
|
|
||||||
tvl::value_t match(const diagram &d, const element &e) const override;
|
tvl::value_t match(const diagram &d, const element &e) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> elements_;
|
std::vector<config::string_or_regex> elements_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct element_type_filter : public filter_visitor {
|
struct element_type_filter : public filter_visitor {
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
namespace clanguml::config {
|
namespace clanguml::config {
|
||||||
|
|
||||||
|
std::string to_string(const std::string &s) { return s; }
|
||||||
|
|
||||||
std::string to_string(const hint_t t)
|
std::string to_string(const hint_t t)
|
||||||
{
|
{
|
||||||
switch (t) {
|
switch (t) {
|
||||||
@@ -85,6 +87,8 @@ std::string to_string(method_type mt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string to_string(string_or_regex sr) { return sr.to_string(); }
|
||||||
|
|
||||||
std::string to_string(const comment_parser_t cp)
|
std::string to_string(const comment_parser_t cp)
|
||||||
{
|
{
|
||||||
switch (cp) {
|
switch (cp) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -35,6 +36,80 @@
|
|||||||
namespace clanguml {
|
namespace clanguml {
|
||||||
namespace config {
|
namespace config {
|
||||||
|
|
||||||
|
std::string to_string(const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrapper around std::regex, which contains original pattern
|
||||||
|
*/
|
||||||
|
struct regex {
|
||||||
|
regex(std::regex r, std::string p)
|
||||||
|
: regexp{std::move(r)}
|
||||||
|
, pattern{std::move(p)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool operator==(const std::string &v)
|
||||||
|
{
|
||||||
|
return std::regex_match(v, regexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::regex regexp;
|
||||||
|
std::string pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct or_regex {
|
||||||
|
or_regex() = default;
|
||||||
|
|
||||||
|
or_regex(T v)
|
||||||
|
: value_{std::move(v)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
or_regex(std::regex r, std::string p)
|
||||||
|
: value_{regex{std::move(r), std::move(p)}}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
or_regex &operator=(const T &v)
|
||||||
|
{
|
||||||
|
value_ = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
or_regex &operator=(const regex &v)
|
||||||
|
{
|
||||||
|
value_ = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool operator==(const T &v) const
|
||||||
|
{
|
||||||
|
if (std::holds_alternative<regex>(value_))
|
||||||
|
return std::regex_match(v, std::get<regex>(value_).regexp);
|
||||||
|
|
||||||
|
return std::get<T>(value_) == v;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
if (std::holds_alternative<regex>(value_))
|
||||||
|
return std::get<regex>(value_).pattern;
|
||||||
|
|
||||||
|
return clanguml::config::to_string(std::get<T>(value_));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::variant<T, regex> &value() const { return value_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<T, regex> value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using string_or_regex = or_regex<std::string>;
|
||||||
|
|
||||||
|
std::string to_string(string_or_regex sr);
|
||||||
|
|
||||||
|
using namespace_or_regex = std::variant<common::model::namespace_, regex>;
|
||||||
|
|
||||||
enum class method_arguments { full, abbreviated, none };
|
enum class method_arguments { full, abbreviated, none };
|
||||||
|
|
||||||
enum class method_type {
|
enum class method_type {
|
||||||
@@ -75,7 +150,7 @@ struct diagram_template {
|
|||||||
struct filter {
|
struct filter {
|
||||||
std::vector<common::model::namespace_> namespaces;
|
std::vector<common::model::namespace_> namespaces;
|
||||||
|
|
||||||
std::vector<std::string> elements;
|
std::vector<string_or_regex> elements;
|
||||||
|
|
||||||
// E.g.:
|
// E.g.:
|
||||||
// - class
|
// - class
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ using clanguml::config::plantuml;
|
|||||||
using clanguml::config::relationship_hint_t;
|
using clanguml::config::relationship_hint_t;
|
||||||
using clanguml::config::sequence_diagram;
|
using clanguml::config::sequence_diagram;
|
||||||
using clanguml::config::source_location;
|
using clanguml::config::source_location;
|
||||||
|
using clanguml::config::string_or_regex;
|
||||||
|
|
||||||
inline bool has_key(const YAML::Node &n, const std::string &key)
|
inline bool has_key(const YAML::Node &n, const std::string &key)
|
||||||
{
|
{
|
||||||
@@ -342,6 +343,23 @@ template <> struct convert<plantuml> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct convert<string_or_regex> {
|
||||||
|
static bool decode(const Node &node, string_or_regex &rhs)
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
if (node.IsMap()) {
|
||||||
|
auto pattern = node["r"].as<std::string>();
|
||||||
|
auto rx = std::regex(pattern);
|
||||||
|
rhs = string_or_regex{std::move(rx), std::move(pattern)};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rhs = string_or_regex{node.as<std::string>()};
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// filter Yaml decoder
|
// filter Yaml decoder
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -52,6 +52,19 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const method_type &m)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YAML::Emitter &operator<<(YAML::Emitter &out, const string_or_regex &m)
|
||||||
|
{
|
||||||
|
if (std::holds_alternative<std::string>(m.value())) {
|
||||||
|
out << std::get<std::string>(m.value());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out << YAML::Key << "r" << YAML::Value
|
||||||
|
<< std::get<regex>(m.value()).pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
||||||
{
|
{
|
||||||
out << YAML::BeginMap;
|
out << YAML::BeginMap;
|
||||||
|
|||||||
@@ -30,3 +30,13 @@ diagrams:
|
|||||||
method_types:
|
method_types:
|
||||||
- deleted
|
- deleted
|
||||||
- destructor
|
- destructor
|
||||||
|
regex_elements_test:
|
||||||
|
type: class
|
||||||
|
include:
|
||||||
|
elements:
|
||||||
|
- ns1::ClassA
|
||||||
|
- r: 'ns1::ns2::Class.+'
|
||||||
|
- r: 'ns1::.+::ns3::.+'
|
||||||
|
exclude:
|
||||||
|
elements:
|
||||||
|
- ns1::ns2::ClassZ
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "catch.h"
|
#include "catch.h"
|
||||||
|
|
||||||
|
#include "class_diagram/model/class.h"
|
||||||
#include "common/model/diagram_filter.h"
|
#include "common/model/diagram_filter.h"
|
||||||
#include "common/model/source_file.h"
|
#include "common/model/source_file.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
@@ -104,3 +105,43 @@ TEST_CASE("Test method_types exclude filter", "[unit-test]")
|
|||||||
|
|
||||||
CHECK(!filter.should_include(cm));
|
CHECK(!filter.should_include(cm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test elements regexp filter", "[unit-test]")
|
||||||
|
{
|
||||||
|
using clanguml::class_diagram::model::class_method;
|
||||||
|
using clanguml::common::model::access_t;
|
||||||
|
using clanguml::common::model::diagram_filter;
|
||||||
|
using clanguml::common::model::namespace_;
|
||||||
|
using clanguml::common::model::source_file;
|
||||||
|
|
||||||
|
using clanguml::class_diagram::model::class_;
|
||||||
|
|
||||||
|
auto cfg = clanguml::config::load("./test_config_data/filters.yml");
|
||||||
|
|
||||||
|
auto &config = *cfg.diagrams["regex_elements_test"];
|
||||||
|
clanguml::class_diagram::model::diagram diagram;
|
||||||
|
|
||||||
|
diagram_filter filter(diagram, config);
|
||||||
|
|
||||||
|
class_ c{{}};
|
||||||
|
|
||||||
|
c.set_namespace(namespace_{"ns1"});
|
||||||
|
c.set_name("ClassA");
|
||||||
|
|
||||||
|
CHECK(filter.should_include(c));
|
||||||
|
|
||||||
|
c.set_namespace(namespace_{"ns1::ns2"});
|
||||||
|
c.set_name("ClassA");
|
||||||
|
|
||||||
|
CHECK(filter.should_include(c));
|
||||||
|
|
||||||
|
c.set_namespace(namespace_{"ns1::ns2"});
|
||||||
|
c.set_name("ClassZ");
|
||||||
|
|
||||||
|
CHECK(!filter.should_include(c));
|
||||||
|
|
||||||
|
c.set_namespace(namespace_{"ns1::ns5::ns3"});
|
||||||
|
c.set_name("ClassA");
|
||||||
|
|
||||||
|
CHECK(filter.should_include(c));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user