Added element_types diagram filter (#131)

This commit is contained in:
Bartek Kryza
2023-05-08 22:53:21 +02:00
parent f8876b1ed0
commit dec4b7bc3d
11 changed files with 141 additions and 0 deletions

View File

@@ -30,6 +30,7 @@
* `namespaces` - list of namespaces to include
* `relationships` - list of relationships to include
* `elements` - list of elements, i.e. specific classes, enums, templates to include
* `element_types` - list of element types e.g. `enum`, `class`, `concept`
* `access` - list of visibility scopes to include (e.g. `private`)
* `subclasses` - include only subclasses of specified classes (and themselves)
* `specializations` - include all specializations or instantiations of a given template
@@ -40,6 +41,7 @@
* `namespaces` - list of namespaces to exclude
* `relationships` - list of relationships to exclude
* `elements` - list of elements, i.e. specific classes, enums, templates to exclude
* `element_types` - list of element types e.g. `enum`, `class`, `concept`
* `access` - list of visibility scopes to exclude (e.g. `private`)
* `subclasses` - exclude subclasses of specified classes (and themselves)
* `specializations` - exclude all specializations or instantiations of a given template

View File

@@ -4,6 +4,7 @@
* [`namespaces`](#namespaces)
* [`elements`](#elements)
* [`element_types`](#element_types)
* [`paths`](#paths)
* [`context`](#context)
* [`relationships`](#relationships)
@@ -53,6 +54,17 @@ from an included namespace:
- ns1::ns2::MyClass
```
## `element_types`
Allows to include or exclude elements of specific type from the diagram, for instance
to remove all enums from a diagram add the following:
```yaml
exclude:
element_types:
- enum
```
## `paths`
This filter allows to include or exclude from the diagram elements declared

View File

@@ -220,6 +220,22 @@ tvl::value_t element_filter::match(
});
}
element_type_filter::element_type_filter(
filter_t type, std::vector<std::string> element_types)
: filter_visitor{type}
, element_types_{std::move(element_types)}
{
}
tvl::value_t element_type_filter::match(
const diagram &d, const element &e) const
{
return tvl::any_of(element_types_.begin(), element_types_.end(),
[&e](const auto &element_type) {
return e.type_name() == element_type;
});
}
subclass_filter::subclass_filter(filter_t type, std::vector<std::string> roots)
: filter_visitor{type}
, roots_{std::move(roots)}
@@ -531,6 +547,9 @@ void diagram_filter::init_filters(const config::diagram &c)
element_filters.emplace_back(std::make_unique<element_filter>(
filter_t::kInclusive, c.include().elements));
element_filters.emplace_back(std::make_unique<element_type_filter>(
filter_t::kInclusive, c.include().element_types));
if (c.type() == diagram_t::kClass) {
element_filters.emplace_back(std::make_unique<subclass_filter>(
filter_t::kInclusive, c.include().subclasses));
@@ -609,6 +628,9 @@ void diagram_filter::init_filters(const config::diagram &c)
add_exclusive_filter(std::make_unique<element_filter>(
filter_t::kExclusive, c.exclude().elements));
add_exclusive_filter(std::make_unique<element_type_filter>(
filter_t::kExclusive, c.exclude().element_types));
add_exclusive_filter(std::make_unique<relationship_filter>(
filter_t::kExclusive, c.exclude().relationships));

View File

@@ -127,6 +127,17 @@ private:
std::vector<std::string> elements_;
};
struct element_type_filter : public filter_visitor {
element_type_filter(filter_t type, std::vector<std::string> element_types);
~element_type_filter() override = default;
tvl::value_t match(const diagram &d, const element &e) const override;
private:
std::vector<std::string> element_types_;
};
struct subclass_filter : public filter_visitor {
subclass_filter(filter_t type, std::vector<std::string> roots);

View File

@@ -61,6 +61,12 @@ struct filter {
std::vector<std::string> elements;
// E.g.:
// - class
// - enum
// - concept
std::vector<std::string> element_types;
// E.g.:
// - inheritance/extension
// - dependency

View File

@@ -301,6 +301,10 @@ template <> struct convert<filter> {
if (node["elements"])
rhs.elements = node["elements"].as<decltype(rhs.elements)>();
if (node["element_types"])
rhs.element_types =
node["element_types"].as<decltype(rhs.element_types)>();
if (node["access"])
rhs.access = node["access"].as<decltype(rhs.access)>();

View File

@@ -60,6 +60,8 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
out << YAML::Key << "dependencies" << YAML::Value << f.dependencies;
if (!f.elements.empty())
out << YAML::Key << "elements" << YAML::Value << f.elements;
if (!f.element_types.empty())
out << YAML::Key << "element_types" << YAML::Value << f.element_types;
if (!f.paths.empty())
out << YAML::Key << "paths" << YAML::Value << f.paths;
if (!f.relationships.empty())

15
tests/t00063/.clang-uml Normal file
View File

@@ -0,0 +1,15 @@
compilation_database_dir: ..
output_directory: puml
diagrams:
t00063_class:
type: class
glob:
- ../../tests/t00063/t00063.cc
include:
namespaces:
- clanguml::t00063
exclude:
element_types:
- enum
using_namespace:
- clanguml::t00063

9
tests/t00063/t00063.cc Normal file
View File

@@ -0,0 +1,9 @@
namespace clanguml {
namespace t00063 {
class A { };
enum B { b1, b2, b3 };
enum class C { c1, c2, c3 };
}
}

57
tests/t00063/test_case.h Normal file
View File

@@ -0,0 +1,57 @@
/**
* tests/t00063/test_case.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
TEST_CASE("t00063", "[test-case][class]")
{
auto [config, db] = load_config("t00063");
auto diagram = config.diagrams["t00063_class"];
REQUIRE(diagram->name == "t00063_class");
auto model = generate_class_diagram(*db, diagram);
REQUIRE(model->name() == "t00063_class");
{
auto puml = generate_class_puml(diagram, *model);
AliasMatcher _A(puml);
REQUIRE_THAT(puml, StartsWith("@startuml"));
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
REQUIRE_THAT(puml, IsClass(_A("A")));
REQUIRE_THAT(puml, !IsEnum(_A("B")));
REQUIRE_THAT(puml, !IsEnum(_A("C")));
save_puml(
config.output_directory() + "/" + diagram->name + ".puml", puml);
}
{
auto j = generate_class_json(diagram, *model);
using namespace json;
REQUIRE(IsClass(j, "A"));
REQUIRE(!IsEnum(j, "B"));
REQUIRE(!IsEnum(j, "C"));
save_json(config.output_directory() + "/" + diagram->name + ".json", j);
}
}

View File

@@ -299,6 +299,7 @@ using namespace clanguml::test::matchers;
#include "t00060/test_case.h"
#include "t00061/test_case.h"
#include "t00062/test_case.h"
#include "t00063/test_case.h"
///
/// Sequence diagram tests