From 793e21959c3621091b56b096745121dfc223b7a6 Mon Sep 17 00:00:00 2001 From: thibault Date: Sun, 1 Dec 2024 18:27:50 -0500 Subject: [PATCH] Improve parent finding in aggregation list preparation --- doc/source/conf.py | 6 +-- doc/source/org-doc.rst | 64 +++++++++++++++++++++++++++----- hpp2plantuml.org | 52 +++++++++++++++++++++++--- src/hpp2plantuml/__init__.py | 2 +- src/hpp2plantuml/hpp2plantuml.py | 46 ++++++++++++++++++++--- 5 files changed, 146 insertions(+), 24 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 7bc0b54..63c96a5 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -79,9 +79,9 @@ # built documents. # # The short X.Y version. -version = u'v' + u'0.8.5' +version = u'v' + u'0.8.6' # The full version, including alpha/beta/rc tags. -release = u'v' + u'0.8.5' +release = u'v' + u'0.8.6' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -155,7 +155,7 @@ # The name for this set of Sphinx documents. # " v documentation" by default. # -# html_title = u'hpp2plantuml ' + u'v' + u'0.8.5' +# html_title = u'hpp2plantuml ' + u'v' + u'0.8.6' # A shorter title for the navigation bar. Default is the same as html_title. # diff --git a/doc/source/org-doc.rst b/doc/source/org-doc.rst index 2b30318..05c0e5a 100644 --- a/doc/source/org-doc.rst +++ b/doc/source/org-doc.rst @@ -13,7 +13,7 @@ The current version of the code is: :: :name: hpp2plantuml-version - 0.8.5 + 0.8.6 The source code can be found on GitHub: @@ -1541,17 +1541,24 @@ be used to avoid this sorting step. parent = parent_s[-1] obj_ns_list = obj_ns_list_base + parent_s[:-1] parent_obj = None - found = False pi = 0 - while not found and pi <= len(obj_ns_list): + while pi <= len(obj_ns_list): ns_list_trunc = -pi if pi > 0 else None obj_ns_c = obj_ns_list[:ns_list_trunc] + obj_match_list = [] for c, c_n, c_ns in zip(class_list_obj, class_list, class_list_ns): obj_other_ns = c_ns.split('::')[:-1] if obj_ns_c == obj_other_ns and (f_cmp(parent, c_n) or f_cmp(parent, c_ns)): - return c['obj'] + obj_match_list.append([c, c_n, c_ns]) + if len(obj_match_list) == 1: + return obj_match_list[0][0]['obj'] + elif len(obj_match_list) > 1: + obj_match_list = sorted(obj_match_list, key=lambda x: + re.search(r'\b{}\b'.format(x[1]), + parent).span()[0]) + return obj_match_list[0][0]['obj'] pi += 1 return None @@ -1618,7 +1625,7 @@ be used to avoid this sorting step. if s != ''] p_cl_plist = [s for s in var_obj.name.split('::') if s != ''] - if '{}*'.format(var_obj.name) in var_in: + if is_ptr(var_obj.name, var_in): rel_type = 'aggregation' else: rel_type = 'composition' @@ -1951,6 +1958,41 @@ block. return '' return '.'.join(namespace.split('::')) +Pointer type check +^^^^^^^^^^^^^^^^^^ + +.. code:: python + :name: py-help-pointer-type + + def is_ptr(obj_name, obj): + """Determine if object type represents a pointer + + Parameters + ---------- + obj_name : str + Object base name + obj : str + Full type + + Returns + ------- + bool + True if ``obj`` is determined to represent a point to an object of type + ``obj_name`` + + Examples + -------- + >>> is_ptr('Object', 'Object*') + True + >>> is_ptr('Object', 'unique_ptr') + True + >>> is_ptr('Object', 'unique_ptr') + False + """ + return ('{}*'.format(obj_name) in obj or + any('{}_ptr<{}>'.format(ptr_type, obj_name) in obj + for ptr_type in ['unique', 'shared', 'weak'])) + .. _sec-module-create-uml: Main function: create PlantUML from C++ @@ -2109,7 +2151,7 @@ to parse input arguments. The function passes the command line arguments to the required=False, default=None, metavar='JINJA-FILE', help='path to jinja2 template file') parser.add_argument('--version', action='version', - version='%(prog)s ' + '0.8.5') + version='%(prog)s ' + '0.8.6') args = parser.parse_args() if len(args.input_files) > 0: CreatePlantUMLFile(args.input_files, args.output_file, @@ -3430,7 +3472,7 @@ obtained using the source block described `sec-org-el-version`_. __title__ = "hpp2plantuml" __description__ = "Convert C++ header files to PlantUML" - __version__ = '0.8.5' + __version__ = '0.8.6' __uri__ = "https://github.com/thibaultmarin/hpp2plantuml" __doc__ = __description__ + " <" + __uri__ + ">" __author__ = "Thibault Marin" @@ -3941,9 +3983,9 @@ content of the file is mostly following the defaults, with a few exceptions: # built documents. # # The short X.Y version. - version = u'v' + u'0.8.5' + version = u'v' + u'0.8.6' # The full version, including alpha/beta/rc tags. - release = u'v' + u'0.8.5' + release = u'v' + u'0.8.6' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -4017,7 +4059,7 @@ content of the file is mostly following the defaults, with a few exceptions: # The name for this set of Sphinx documents. # " v documentation" by default. # - # html_title = u'hpp2plantuml ' + u'v' + u'0.8.5' + # html_title = u'hpp2plantuml ' + u'v' + u'0.8.6' # A shorter title for the navigation bar. Default is the same as html_title. # @@ -4400,6 +4442,8 @@ file is added for the ``numpydoc`` package. python: install: + - method: pip + path: . - requirements: doc/source/readthedocs-requirements.txt Org-mode setup diff --git a/hpp2plantuml.org b/hpp2plantuml.org index 1b3b4cd..96e6848 100644 --- a/hpp2plantuml.org +++ b/hpp2plantuml.org @@ -16,7 +16,7 @@ this single org-file. The current version of the code is: #+NAME: hpp2plantuml-version -: 0.8.5 +: 0.8.6 The source code can be found on GitHub: https://github.com/thibaultmarin/hpp2plantuml. @@ -1518,17 +1518,24 @@ class Diagram(object): parent = parent_s[-1] obj_ns_list = obj_ns_list_base + parent_s[:-1] parent_obj = None - found = False pi = 0 - while not found and pi <= len(obj_ns_list): + while pi <= len(obj_ns_list): ns_list_trunc = -pi if pi > 0 else None obj_ns_c = obj_ns_list[:ns_list_trunc] + obj_match_list = [] for c, c_n, c_ns in zip(class_list_obj, class_list, class_list_ns): obj_other_ns = c_ns.split('::')[:-1] if obj_ns_c == obj_other_ns and (f_cmp(parent, c_n) or f_cmp(parent, c_ns)): - return c['obj'] + obj_match_list.append([c, c_n, c_ns]) + if len(obj_match_list) == 1: + return obj_match_list[0][0]['obj'] + elif len(obj_match_list) > 1: + obj_match_list = sorted(obj_match_list, key=lambda x: + re.search(r'\b{}\b'.format(x[1]), + parent).span()[0]) + return obj_match_list[0][0]['obj'] pi += 1 return None @@ -1595,7 +1602,7 @@ class Diagram(object): if s != ''] p_cl_plist = [s for s in var_obj.name.split('::') if s != ''] - if '{}*'.format(var_obj.name) in var_in: + if is_ptr(var_obj.name, var_in): rel_type = 'aggregation' else: rel_type = 'composition' @@ -1928,6 +1935,41 @@ def get_namespace_link_name(namespace): #+END_SRC +*** Pointer type check + +#+NAME: py-help-pointer-type +#+BEGIN_SRC python +def is_ptr(obj_name, obj): + """Determine if object type represents a pointer + + Parameters + ---------- + obj_name : str + Object base name + obj : str + Full type + + Returns + ------- + bool + True if ``obj`` is determined to represent a point to an object of type + ``obj_name`` + + Examples + -------- + >>> is_ptr('Object', 'Object*') + True + >>> is_ptr('Object', 'unique_ptr') + True + >>> is_ptr('Object', 'unique_ptr') + False + """ + return ('{}*'.format(obj_name) in obj or + any('{}_ptr<{}>'.format(ptr_type, obj_name) in obj + for ptr_type in ['unique', 'shared', 'weak'])) +#+END_SRC + + ** DONE Main function: create PlantUML from C++ :PROPERTIES: :CUSTOM_ID: sec-module-create-uml diff --git a/src/hpp2plantuml/__init__.py b/src/hpp2plantuml/__init__.py index 26b28b4..b305a4f 100644 --- a/src/hpp2plantuml/__init__.py +++ b/src/hpp2plantuml/__init__.py @@ -106,7 +106,7 @@ __title__ = "hpp2plantuml" __description__ = "Convert C++ header files to PlantUML" -__version__ = '0.8.5' +__version__ = '0.8.6' __uri__ = "https://github.com/thibaultmarin/hpp2plantuml" __doc__ = __description__ + " <" + __uri__ + ">" __author__ = "Thibault Marin" diff --git a/src/hpp2plantuml/hpp2plantuml.py b/src/hpp2plantuml/hpp2plantuml.py index 442b298..edf0f47 100644 --- a/src/hpp2plantuml/hpp2plantuml.py +++ b/src/hpp2plantuml/hpp2plantuml.py @@ -1118,17 +1118,24 @@ def find_parent(self, parent_in, obj_ns_list_base, f_cmp=None): parent = parent_s[-1] obj_ns_list = obj_ns_list_base + parent_s[:-1] parent_obj = None - found = False pi = 0 - while not found and pi <= len(obj_ns_list): + while pi <= len(obj_ns_list): ns_list_trunc = -pi if pi > 0 else None obj_ns_c = obj_ns_list[:ns_list_trunc] + obj_match_list = [] for c, c_n, c_ns in zip(class_list_obj, class_list, class_list_ns): obj_other_ns = c_ns.split('::')[:-1] if obj_ns_c == obj_other_ns and (f_cmp(parent, c_n) or f_cmp(parent, c_ns)): - return c['obj'] + obj_match_list.append([c, c_n, c_ns]) + if len(obj_match_list) == 1: + return obj_match_list[0][0]['obj'] + elif len(obj_match_list) > 1: + obj_match_list = sorted(obj_match_list, key=lambda x: + re.search(r'\b{}\b'.format(x[1]), + parent).span()[0]) + return obj_match_list[0][0]['obj'] pi += 1 return None @@ -1195,7 +1202,7 @@ def build_aggregation_list(self): if s != ''] p_cl_plist = [s for s in var_obj.name.split('::') if s != ''] - if '{}*'.format(var_obj.name) in var_in: + if is_ptr(var_obj.name, var_in): rel_type = 'aggregation' else: rel_type = 'composition' @@ -1488,6 +1495,35 @@ def get_namespace_link_name(namespace): return '' return '.'.join(namespace.split('::')) +def is_ptr(obj_name, obj): + """Determine if object type represents a pointer + + Parameters + ---------- + obj_name : str + Object base name + obj : str + Full type + + Returns + ------- + bool + True if ``obj`` is determined to represent a point to an object of type + ``obj_name`` + + Examples + -------- + >>> is_ptr('Object', 'Object*') + True + >>> is_ptr('Object', 'unique_ptr') + True + >>> is_ptr('Object', 'unique_ptr') + False + """ + return ('{}*'.format(obj_name) in obj or + any('{}_ptr<{}>'.format(ptr_type, obj_name) in obj + for ptr_type in ['unique', 'shared', 'weak'])) + # %% Main function @@ -1548,7 +1584,7 @@ def main(): required=False, default=None, metavar='JINJA-FILE', help='path to jinja2 template file') parser.add_argument('--version', action='version', - version='%(prog)s ' + '0.8.5') + version='%(prog)s ' + '0.8.6') args = parser.parse_args() if len(args.input_files) > 0: CreatePlantUMLFile(args.input_files, args.output_file,