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'); 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( imgSnapshotTest(
` `
classDiagram classDiagram
@@ -184,7 +208,7 @@ describe('Class diagram', () => {
cy.get('svg'); 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( imgSnapshotTest(
` `
classDiagram 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. UML provides mechanisms to represent class members, such as attributes and methods, and additional information about them.
#### Visibility 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.
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:
- `+` 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 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 the 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: - Associate a member of a class using **:** (colon) followed by member name, useful to define one member at a time. For example:
``` ```
@@ -150,7 +143,22 @@ class BankAccount{
+BigDecimal balance +BigDecimal balance
+deposit(amount) +deposit(amount)
+withdrawl(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 ## Defining Relationship
A relationship is a general term covering the specific types of logical connections found on class and object diagrams. 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('>>')) { if (memberString.startsWith('<<') && memberString.endsWith('>>')) {
// Remove leading and trailing brackets // Remove leading and trailing brackets
theClass.annotations.push(memberString.substring(2, memberString.length - 2)); theClass.annotations.push(memberString.substring(2, memberString.length - 2));
} else if (memberString.endsWith(')')) { } else if (memberString.indexOf(')') > 0) {
theClass.methods.push(memberString); theClass.methods.push(memberString);
} else if (memberString) { } else if (memberString) {
theClass.members.push(memberString); theClass.members.push(memberString);

View File

@@ -442,5 +442,27 @@ describe('class diagram, ', function () {
expect(testClass.methods[0]).toBe('test()'); expect(testClass.methods[0]).toBe('test()');
expect(testClass.methods[1]).toBe('foo()'); 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); logger.info('Rendering class ' + classDef);
const addTspan = function(textEl, txt, isFirst) { 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 const tSpan = textEl
.append('tspan') .append('tspan')
.attr('x', conf.padding) .attr('x', conf.padding)
.text(txt); .text(displayText);
if (cssStyle !== '') {
tSpan.attr('style', cssStyle);
}
if (!isFirst) { if (!isFirst) {
tSpan.attr('dy', conf.textHeight); tSpan.attr('dy', conf.textHeight);
} }