Ability to include blocks from other file without using startuml

0 votes
asked Oct 11 in Wanted features by rd27 (310 points)

I would like to define a complex diagram in a file (let's call it file1.puml). Then define certain blocks of 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

related to an answer for: Include block from current file?

2 Answers

0 votes
answered Oct 11 by plantuml (134,510 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 by rd27 (310 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 by rd27 (310 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
0 votes
answered Oct 13 by plantuml (134,510 points)


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 by paxtaru (100 points)
edited Oct 16 by paxtaru
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 by plantuml (134,510 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 by paxtaru (100 points)
Thank you, it works perfectly now.
commented Oct 25 by paxtaru (100 points)
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
...