Ability to include blocks of code from one PlantUML file into another

+1 vote
asked Oct 11, 2017 in Closed feature request by rd27 (460 points)
I would like to define a complex diagram in a file (let's call it file1.puml). Then define certain blocks of it for import into other files.

For example, I might have a complex diagram of A -> B -> C -> D. I would like to import just the D part. So in other files I can show D without all of the stuff it depends on.

I tried using startuml(id=) for this as follows for file1.puml:

@startuml

' A stuff

' B stuff

' C stuff

@enduml

@startuml(id=BASICS)

' D stuff

@enduml

This works for including using "file1.puml!BASICS", but the problem is that file1.puml when rendered only shows last startuml block (BASICS in this case).

I'm wondering about adding something like @startid/@endid (similar to the startdef mentioned in linked answer). It would have the same include by name/number functionality for !include, but wouldn't have the @startuml aspect (so whole file1.puml would be rendered when viewed).

An added bonus would be if it could be used multiple places in a file. So you could have the following and "!includeid file1.puml!BASICS" would include both A and B stuff.

@startuml

' A stuff

@startid BASICS

' B stuff

@endid

' C stuff

@startid BASICS

' D stuff

@endif

@enduml

Thanks!

dave

2 Answers

+2 votes
answered Oct 13, 2017 by plantuml (294,660 points)
selected Mar 21, 2018 by Anthony-Gaudino
 
Best answer


With last beta https://www.dropbox.com/s/koo42q3d9gxw288/plantuml.jar?dl=0 , you can have:

file1.puml:
@startuml
!startsub FOO1
A->A : stuffA2
!endsub
B->B : stuffB2
C->C : stuffC2
D->D : stuffD2
!includesub FOO1
@enduml



file2.puml:
@startuml
B->B : stuffB3
C->C : stuffC3
D->D : stuffD3
!includesub file1.puml!FOO1
@enduml


It's a first draft, so there are probably some issues.
Feedback welcome!

Regards,

commented Oct 16, 2017 by anonymous
edited Oct 16, 2017 by
This is exactly the feature I'm looking for, thank you very much for putting this in.  I do have a use case that's not working now:
  
file1.puml:
@startuml
!startsub FOO1
A->A : stuffA1
!endsub
@enduml

file2.puml:
@startuml
!startsubFOO2
B->B : stuffB1
!includesub file1.puml!FOO1
C->C : stuffC1
!endsub
@enduml

file3.puml:
@startuml
E->E : stuffE1
!includesub file2.puml!FOO2
@enduml

When looking at the UML for file 3, it doesn't display the includesub that was used in file 2.  I think enabling this can lead to crashes if people accidentally put in an infinite loop, but having this could be really helpful for larger systems.

What do you all think?
commented Oct 17, 2017 by plantuml (294,660 points)
Thanks for your test and your feedback.
Should be fixed in last beta
https://www.dropbox.com/s/koo42q3d9gxw288/plantuml.jar?dl=0
Regards,
commented Oct 17, 2017 by anonymous
Thank you, it works perfectly now.
commented Oct 25, 2017 by anonymous
Looks like I keep breaking it.  Here's my setup which if I try to render TestEF.puml it fails... and interestingly enough, if I don't use the "include" in all the PUML files, it works fine:

TestList.iuml:
!define a "Service A"
!define b "Service B"
!define c "Service C"
!define d "Service D"
!define e "Service E"
!define f "Service F"

TestAB.puml:
@startuml
!include TestList.iuml
!startsub AB
a -> b : A sends something to B
b --> a : OK
!endsub
@enduml

TestCD.puml:
@startuml
!include TestList.iuml
!startsub CD
c -> d : C sends something to D
d -> a : D sends something to A
!includesub TestAB.puml!AB
a --> d : OK
d --> c : OK
!endsub
@enduml

TestEF.puml:
@startuml
!include TestList.iuml
!startsub EF
e -> f : E sends something to F
f -> c : F sends something to C
!includesub TestCD.puml!CD
c --> f : OK
f --> e : OK
!endsub
@enduml
commented Aug 9, 2018 by mhaaz (200 points)
Was this ever completely fixed? It looks awesome to have a full-fledged domain model (every class/interface/enum in its own file, with *all* fields) while diagram files only define relationships and include certain subsections of (relevant) fields from the class definition files..! This would empower us to write classes once, reuse them everywhere.
commented Oct 11, 2018 by rd27 (460 points)
Thanks again for adding this, it's very handy!
commented Apr 16, 2019 by rd27 (460 points)
+2 votes
answered Oct 11, 2017 by plantuml (294,660 points)

Ok, we like the idea, even if all this is going to be very complex!

Let's say we create two new commands !startsub/!endsub which are used to mark subpart of a PlantUML diagram.
(Note that we used exclamation mark here, and not arobase)

file1.puml:
@startuml
A -> A : stuff1
!startsub BASIC
B -> B : stuff2
!endsub
C -> C : stuff3
!startsub BASIC
D -> D : stuff4
!endsub
@enduml


This file file1.puml would be rendered exactly as if it were:
@startuml
A -> A : stuff1
B -> B : stuff2
C -> C : stuff3
D -> D : stuff4
@enduml

which is your need, if I understand correctly

However, this would allow you to have another file2.puml like this:
@startuml
title this contains only B and D
!includesub file1.puml!BASIC
@enduml


This file would be rendered exactly as if:
@startuml
title this contains only B and D
B -> B : stuff2
D -> D : stuff4
@enduml


Do we have correctly get the needs ?

Thanks

commented Oct 12, 2017 by rd27 (460 points)
Yes, that sounds great.

Another related idea is if a user could include specific items by name. For example in file3.uml they could do:

!includeitem file1.puml!A
!includeitem file1.puml!B

The value is less obvious with this example, but definitely there if A had contents.

As an added bonus, relationships would be brought over if both sides of their shapes were brought over. So in the above example A->A and  B->B and A->B could be brought over.
commented Oct 12, 2017 by rd27 (460 points)
Another related idea would be if when a file is included a __IS_INCLUDED macro is set while the file is parsed. That allows a file to have different contents when it is being included vs being viewed directly.

A good example use of this would be for a formatting rules. Here is format.puml file. When working on it the user can see the test shapes like database_test. So they can see how their formatting changes are working locally. When imported just formatting rules are included.

hide stereotype

skinparam database {
  backgroundColor #MediumAquaMarine
  backgroundColor<<sink>> #MediumTurquoise
}

skinparam rectangle {
  roundCorner 25
  }

!ifndef __IS_INCLUDED
database database_test
database database_sink_test <<sink>>
rectangle rectangle_test
!endif

If the new startsub functionality exists then it could extended to have a well known sub named "__IGNORE_ON_INCLUDE" sub name.When including a __IGNORE_ON_INCLUDE sub is ignored. But it can be explicitly included using !include filename!__IGNORE_ON_INCLUDE. So last section could be:

!startsub __IGNORE_ON_INCLUDE
database database_test
database database_sink_test <<sink>>
rectangle rectangle_test
!endsub
...