Merge pull request #1131 from jgreywolf/1104(b)-SupportForAbstractMethodInClassDiagram

Class: Support for abstract methods
This commit is contained in:
Knut Sveidqvist
2019-12-11 19:43:32 +01:00
committed by GitHub
5 changed files with 93 additions and 15 deletions

View File

@@ -164,7 +164,31 @@ describe('Class diagram', () => {
cy.get('svg');
});
it('5: should render a simple class diagram with Generic class', () => {
it('5: should render a simple class diagram with abstract method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()*
`,
{}
);
cy.get('svg');
});
it('6: should render a simple class diagram with static method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()$
`,
{}
);
cy.get('svg');
});
it('7: should render a simple class diagram with Generic class', () => {
imgSnapshotTest(
`
classDiagram
@@ -184,7 +208,7 @@ describe('Class diagram', () => {
cy.get('svg');
});
it('6: should render a simple class diagram with Generic class and relations', () => {
it('8: should render a simple class diagram with Generic class and relations', () => {
imgSnapshotTest(
`
classDiagram

View File

@@ -105,17 +105,10 @@ Naming convention: a class name should be composed of alphanumeric (unicode allo
UML provides mechanisms to represent class members, such as attributes and methods, and additional information about them.
#### Visibility
To specify the visibility of a class member (i.e. any attribute or method), these notations may be placed before the member's name, but is it optional:
Mermaid distinguishes between attributes and functions/methods based on if the **parenthesis** `()` are present or not. The ones with `()` are treated as functions/methods, and others as attributes.
- `+` Public
- `-` Private
- `#` Protected
- `~` Package
Mermaid distinguishes between attributes and functions/methods based on if the **parenthesis** `()` are present or not. The one with `()` are treated as functions/methods, and others as attributes.
There are two ways to define the members of a class, and regardless of the whichever syntax is used to define the members, the output will still be same. The two different ways are :
There are two ways to define the members of a class, and regardless of whichever syntax is used to define the members, the output will still be same. The two different ways are :
- Associate a member of a class using **:** (colon) followed by member name, useful to define one member at a time. For example:
```
@@ -125,7 +118,7 @@ There are two ways to define the members of a class, and regardless of the which
BankAccount : +deposit(amount)
BankAccount : +withdrawl(amount)
```
```mermaid
``` mermaid
classDiagram
class BankAccount
BankAccount : +String owner
@@ -150,7 +143,22 @@ class BankAccount{
+BigDecimal balance
+deposit(amount)
+withdrawl(amount)
}```
}
```
#### Visibility
To specify the visibility of a class member (i.e. any attribute or method), these notations may be placed before the member's name, but it is optional:
- `+` Public
- `-` Private
- `#` Protected
- `~` Package
>_note_ you can also include additional _classifers_ to a method definition by adding the following notations to the end of the method, i.e.: after the `()`:
> - `*` Abstract e.g.: `someAbstractMethod()*`
> - `$` Static e.g.: `someStaticMethod()$`
## Defining Relationship
A relationship is a general term covering the specific types of logical connections found on class and object diagrams.

View File

@@ -94,7 +94,7 @@ export const addMember = function(className, member) {
if (memberString.startsWith('<<') && memberString.endsWith('>>')) {
// Remove leading and trailing brackets
theClass.annotations.push(memberString.substring(2, memberString.length - 2));
} else if (memberString.endsWith(')')) {
} else if (memberString.indexOf(')') > 0) {
theClass.methods.push(memberString);
} else if (memberString) {
theClass.members.push(memberString);

View File

@@ -442,5 +442,27 @@ describe('class diagram, ', function () {
expect(testClass.methods[0]).toBe('test()');
expect(testClass.methods[1]).toBe('foo()');
});
it('should handle abstract methods', function () {
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()*';
parser.parse(str);
const testClass = parser.yy.getClass('Class1');
expect(testClass.annotations.length).toBe(0);
expect(testClass.members.length).toBe(0);
expect(testClass.methods.length).toBe(1);
expect(testClass.methods[0]).toBe('someMethod()*');
});
it('should handle static methods', function () {
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()$';
parser.parse(str);
const testClass = parser.yy.getClass('Class1');
expect(testClass.annotations.length).toBe(0);
expect(testClass.members.length).toBe(0);
expect(testClass.methods.length).toBe(1);
expect(testClass.methods[0]).toBe('someMethod()$');
});
});
});

View File

@@ -281,10 +281,34 @@ const drawClass = function(elem, classDef) {
logger.info('Rendering class ' + classDef);
const addTspan = function(textEl, txt, isFirst) {
let displayText = txt;
let cssStyle = '';
let methodEnd = txt.indexOf(')') + 1;
if (methodEnd > 1 && methodEnd <= txt.length) {
let classifier = txt.substring(methodEnd);
switch (classifier) {
case '*':
cssStyle = 'font-style:italic;';
break;
case '$':
cssStyle = 'text-decoration:underline;';
break;
}
displayText = txt.substring(0, methodEnd);
}
const tSpan = textEl
.append('tspan')
.attr('x', conf.padding)
.text(txt);
.text(displayText);
if (cssStyle !== '') {
tSpan.attr('style', cssStyle);
}
if (!isFirst) {
tSpan.attr('dy', conf.textHeight);
}