Documentation ¶
Overview ¶
Package mdd provides the metamodel for [qb] Model Driven Development. [qb]MDD focuses on creating a precise data model of the problem domain. Implementation aspects should be considered later when the model is used for implementation. Dynamic aspects are not the subject of [qb]MDD. It stems from quite some years of experience with model driven software development. The roots certainly lie in the collaboration with the brilliant minds behind the work on the long-ago code generation framework XCoder. The core concepts are:
Small but useful type system:
Atom – Opaque type from which other types are created
Enum – Just a set of distinct names
Class – Similar to what you know from e.g. UML
The Model represents your universe – the scope you are working on.
A Package groups closely related parts of your universe. Packages enforce a DAG on package dependencies for a clean architecture. Dependencies are derived from your model.
An Association represents a set of links between objects. If classes are the players on your team, then associations are the team's line-up for the next match. They are not part of a class. Associations organize classes to play together well in your use cases.
The only generator that comes with this Go module is and remains a diagram generator in the puml package, which is currently targeted for PlantUML.
Inheritance ¶
Without behaviour, this is the inheritance rule:
Each object of a subclass must be a valid instance of each base class i.e., the object restricted to the set of properties of that base class must be in that base class.
This rule comes with consequences:
- Redefining attributes requires covariance, i.e. the value domain of a redefining attribute in a subclass must be a subset of the redefined attribute's value domain.
Inheritance comes with (at least) one incredible ability: If you have important parts in your system that work well with a general concept, you can transparently introduce new special cases without touching those general parts - let alone breaking general parts. As the rule above shows, for pure data structures inheritance can be boiled down to set theory and algebra. If you take behaviour into account it gets far more complex. Be aware of the LSP!
Unfortunately, turning the abstract idea of inheritance into implementations requires experience, good design, and an awareness that you are minting something that should last for some time.
One final caveat, if inheritance is new to you: Inheritance is too often characterized as an "is-a" relationship. If you take the statement "7 is a number", you are already on the wrong track! Learn to distinguish inheritance and instantiation! In other words if you focus on structure only:
7 ∊ ℕ ~ Instantiation ≠ {7} ⊂ ℕ ~ Inheritance 😉
Multiple Inheritance ¶
[qb]MDD is intended to model the terms of the subject domain, not to prescribe artefacts in programming. Here, multiple inheritance can be the most suitable means of expression for a situation. Therefore, multiple inheritance is supported. It is not encouraged to use multiple inheritance imprudently. – It is not your new shiny toy!
Whoever implements a generator for [qb]MDD is encouraged to support multiple inheritance.
With multiple inheritance, you have to explain how to handle ambiguities i.e. inheriting more than one property with the same name:
Ambiguities between Attributes and Association Ends are not allowed.
Ambiguous association ends are not allowed (yet).
Ambiguous attributes without conflict are accepted. Attributes are conflicting if their type or their multiplicity or both differ. (TODO: What about derived?)
If possible, conflicting ambiguous attributes are automatically redefined to match the inheritance rule.
Attribute order is determined via base class linearization. It is the concatenation of the list of all non-redefined attributes of the classes in the linearized class list.
Base class linearization: The class-list of classes without base classes is the class itself. For classes with base classes it's the linearization of the 1st base-class subsequently concatenated with the reduced linearization of the following bases plus the class itself. The reduced linearization of a subsequent base-class b is the linearization of b in which all elements that are already included in the linearization to be formed are removed.
Mixing in Classes ¶
In the OOP world, classes and mixins are related concepts where mixins typically drop the substitutability requirement that applies to classes. Again, a need for mixins primarily arises when one tries to map the abstract idea of inheritance to an implementation. – Having something like mixins in [qb]MDD is a concession to practical considerations.
Anyway, if you remove the inheritance rule from [qb]MDD classes, the result – an “MDD mixin” – becomes a simple concept. Mixing classes into other classes is the same as adding all, including inherited, attributes of the mixin to the receiving class.
Mixed-in attributes can be overwritten – either explicitly or by subsequent mixins. Overwriting does neither check type nor multiplicity.
Explicitly defined attributes cannot be overwritten.
Maintainability, Mixins and Inheritance ¶
On many projects, I've seen design decisions made with the only question in mind: "Will it work?" But the question "How much work will it be to change it?" is the more important guide in the long run, especially when it comes to inheritance vs. mixin. Not that I had a crystal ball that would allow me to see the future that it would take to make such decisions without error. But there is one question that should be asked!
First, remember that both inheritance and mixins are means of reuse. That is, things defined once in a mixin or base class will most likely be used in at least two different places. So, take a close look at your problem domain and ask yourself:
If I change this common definition, do I always want all uses of that definition to change as well?
If your answer is "yes," you have found a structural similarity that is intentional - not by accident. These often correspond to a taxonomic hierarchy in your problem domain and can be implemented very well by inheritance. Purely structural reuse, as supported by mixins, is often motivated by a rather random structural match, in my experience. This bears the risk of causing unintended changes by changing the mixin. But neither inheritance nor mixins are a one-size-fits-all tools. Choose wisely!
Entities ¶
Like UML, [qb]MDD supports entities in that a class can be marked to be an entity. In the context of [qb]MDD, entities can be thought of as complementary to keys. An entity can be identified as one and the same "thing" regardless of its keys, if any. I.e. even if all of its properties change, the entity remains the same. An entity cannot have Comparability == NotComparable.
Comparability, Keys and Collections ¶
Each Type has a Comparability. It indicates whether it can be determined that two values of a type are Equal and whether it can be determined for each two values whether one is Less than the other. If neither of both is the case a type is NotComparable. If a type supports both, Equal and Less, the comparability Orders the type.
Comparability of Atom types is defined by the modeler. Enum types always support Equal and may be defined to also support Less when setting mdd.Enum.Ordered = true. For Class types things are more complicate. A class that represents an entity always supports Equal. For anything else one has to define keys for the class.
A Key can be used for determining whether and how objects of a class are compared with each other. A class can have more than one key defined. A key with an empty name is the default key of the class. A key also has a comparability that is determined from the properties of the class that are part of the key. A key that supports Equal can be defined as a global key, meaning that it uniquely identifies the objects of that class.
(TODO key-properties of class type -> class's key)
Collection properties, i.e. collections with a maximum multiplicity greater than one, can be defined as ordered or unique. For this, the comparability of the type of the property must support this. To make a collection unique the type must be Equal comparable. To make a collection ordered the type must be Less comparable.
Error Handling ¶
[qb]MDD is intended for modelling as code. That is, it is expected to be used via the mmb package to create a model by writing Go programs. A simple error strategy is sufficient for this:
If an error occurs, one must consider the model to be broken and throw it away.
Index ¶
- Constants
- func MultMaxCompare(m, n uint) int
- type AssocEnd
- func (e *AssocEnd) Class() *Class
- func (p *AssocEnd) Collection() (Collection, *Key)
- func (e *AssocEnd) Counterpart() *AssocEnd
- func (p *AssocEnd) Derived() bool
- func (e *AssocEnd) FQName() NamePath
- func (a *AssocEnd) Model() *Model
- func (p *AssocEnd) Mult() Multiplicity
- func (p *AssocEnd) Name() Name
- func (e *AssocEnd) Owner() ModelElement
- func (e *AssocEnd) OwningAssoc() *Association
- func (p *AssocEnd) SetCollection(coll Collection, key *Key) error
- func (p *AssocEnd) SetDerived(flag bool) error
- func (e *AssocEnd) SetTag(key, tag any) error
- func (p *AssocEnd) String() string
- func (p *AssocEnd) Type() Type
- type Association
- func (a *Association) BiDi() bool
- func (a *Association) End(n Name) (end *AssocEnd, ambiguous bool)
- func (a *Association) EndTo(c *Class) (end *AssocEnd, ambiguous bool)
- func (a *Association) Ends() (aEnd, bEnd *AssocEnd)
- func (a *Association) FQName() NamePath
- func (a *Association) IndexEnd(i EndIndex) *AssocEnd
- func (a *Association) Model() *Model
- func (a *Association) Name() Name
- func (a *Association) SetTag(key, tag any) error
- func (t *Association) Tag(k any) any
- func (a *Association) Within() *Package
- type Atom
- func (t *Atom) Compare(u Type) (bool, int)
- func (t *Atom) Compares() Comparability
- func (t *Atom) FQName() NamePath
- func (t *Atom) Lang(l string) any
- func (t *Atom) Model() *Model
- func (t *Atom) Name() Name
- func (t *Atom) Package() *Package
- func (t *Atom) Restrict(ts ...*Atom) error
- func (t *Atom) Restricts(u *Atom) int
- func (t *Atom) SetLang(lang string, mapped any)
- func (t *Atom) SetTag(key, tag any) error
- func (t *Atom) String() string
- func (t *Atom) Use() []Property
- type Attribute
- func (p *Attribute) Collection() (Collection, *Key)
- func (p *Attribute) Derived() bool
- func (a *Attribute) FQName() NamePath
- func (a *Attribute) Keys() []*Key
- func (a *Attribute) Mixed() *Attribute
- func (a *Attribute) Model() *Model
- func (p *Attribute) Mult() Multiplicity
- func (p *Attribute) Name() Name
- func (a *Attribute) Owner() ModelElement
- func (a *Attribute) OwningClass() *Class
- func (a *Attribute) Redefines() []*Attribute
- func (p *Attribute) SetCollection(coll Collection, key *Key) error
- func (a *Attribute) SetDerived(flag bool) error
- func (a *Attribute) SetTag(key, tag any) error
- func (p *Attribute) String() string
- func (p *Attribute) Type() Type
- type Class
- func (c *Class) Abstract() bool
- func (c *Class) AllAttributes() (atts []*Attribute)
- func (c *Class) AppendMixins(ms []*Class) []*Class
- func (c *Class) AppendOwnAttributes(to []*Attribute) []*Attribute
- func (c *Class) AppendProperties(to []Property) []Property
- func (c *Class) Associated() []*AssocEnd
- func (c *Class) AttCompares() Comparability
- func (c *Class) Attributes() []*Attribute
- func (c *Class) BaseList() (ls []*Class)
- func (c *Class) Bases() []*Class
- func (t *Class) Compare(u Type) (bool, int)
- func (c *Class) Compares() Comparability
- func (c *Class) Derived() []*Class
- func (c *Class) EachProperty(do func(Property) error) error
- func (c *Class) Entity() bool
- func (c *Class) Extends(t *Class) bool
- func (t *Class) FQName() NamePath
- func (c *Class) HasMixedFrom(m *Class) *Attribute
- func (c *Class) HasMixin(m *Class) bool
- func (c *Class) IsMixedInto(m *Class) bool
- func (t *Class) Key(n Name) *Key
- func (t *Class) KeyString(s string) *Key
- func (t *Class) Keys() []*Key
- func (c *Class) MixIn(m *Class, mode MixMode) error
- func (c *Class) MixedInto() []*Class
- func (c *Class) Mixins() []*Class
- func (t *Class) Model() *Model
- func (t *Class) Name() Name
- func (c *Class) NewAttribute(name Name, typ Type, mult Multiplicity) (*Attribute, error)
- func (t *Class) NewKey(n Name, atts ...KeyElement) (*Key, error)
- func (c *Class) OwnAttributes() []*Attribute
- func (t *Class) Package() *Package
- func (c *Class) Properties() []Property
- func (c *Class) Property(name Name, inherited bool) (res Property)
- func (c *Class) PropertyString(name string, inherited bool) Property
- func (c *Class) SetAbstract(flag bool) *Class
- func (c *Class) SetEntity(flag bool) *Class
- func (c *Class) SetTag(key, tag any) error
- func (t *Class) String() string
- func (t *Class) Use() []Property
- type Collection
- type Comparability
- type DuplicateBaseError
- type EndIndex
- type Enum
- func (t *Enum) Compare(u Type) (bool, int)
- func (t *Enum) Compares() Comparability
- func (t *Enum) FQName() NamePath
- func (t *Enum) HasLiteral(l Name) bool
- func (t *Enum) Literals() []Name
- func (t *Enum) Model() *Model
- func (t *Enum) Name() Name
- func (t *Enum) Package() *Package
- func (t *Enum) SetTag(key, tag any) error
- func (t *Enum) String() string
- func (t *Enum) Use() []Property
- type IncomparableAtom
- type IncomparableClass
- type IncomparableEnum
- type Key
- func (k *Key) Add(p Property, key *Key) error
- func (k *Key) Compares() Comparability
- func (k *Key) Elem(i int) (Property, *Key)
- func (k *Key) FQName() NamePath
- func (k *Key) Global() bool
- func (k *Key) Name() Name
- func (k *Key) Owner() *Class
- func (k *Key) Part(a Property) (int, *Key)
- func (k *Key) SetGlobal(f bool) error
- func (k *Key) Size() int
- type KeyElement
- type MixMode
- type Model
- func (m *Model) AppendPackages(to []*Package) []*Package
- func (m *Model) Associations() []*Association
- func (m *Model) EachPackage(do func(*Package) error) error
- func (m *Model) Name() Name
- func (m *Model) NewPackage(name Name) (*Package, error)
- func (m *Model) Package(name Name) *Package
- func (m *Model) PackageString(name string) *Package
- func (m *Model) Packages() []*Package
- func (m *Model) SetTag(key, tag any) error
- func (m *Model) String() string
- func (t *Model) Tag(k any) any
- type ModelElement
- type Multiplicity
- type Name
- func (n Name) Camel(start int, keepAcronyms bool) Name
- func (n Name) Caps(keepAcronyms bool) Name
- func (n Name) Empty() bool
- func (n Name) Equal(m Name) bool
- func (n Name) Format(f fmt.State, verb rune)
- func (n Name) Join(sep string) string
- func (n Name) Lower(keepAcronyms bool) Name
- func (n Name) String() string
- func (n Name) Upper() Name
- func (n Name) Validate(acceptEmpty bool) error
- func (n Name) Word(i int) string
- type NamePath
- type Package
- func (p *Package) AddDependency(to *Package) []*Package
- func (p *Package) AppendAtoms(to []*Atom) []*Atom
- func (p *Package) AppendClasses(to []*Class) []*Class
- func (p *Package) AppendEnums(to []*Enum) []*Enum
- func (p *Package) AppendTypes(to []Type) []Type
- func (p *Package) Atoms() []*Atom
- func (p *Package) Classes() []*Class
- func (p *Package) Dependencies() []*Package
- func (p *Package) DependencyPath(to *Package) []*Package
- func (p *Package) DependsOn(q *Package) bool
- func (p *Package) EachType(do func(Type) error) error
- func (p *Package) Enums() []*Enum
- func (p *Package) FQName() NamePath
- func (p *Package) Model() *Model
- func (p *Package) Name() Name
- func (p *Package) NewAtom(name Name, cmpr Comparability) (*Atom, error)
- func (p *Package) NewClass(name Name, bases ...*Class) (*Class, error)
- func (p *Package) NewEntity(name Name, bases ...*Class) (*Class, error)
- func (p *Package) NewEnum(name Name, literals ...Name) (*Enum, error)
- func (p *Package) SetTag(key, tag any) error
- func (p *Package) String() string
- func (p *Package) Supported() []*Package
- func (p *Package) Supports(q *Package) bool
- func (t *Package) Tag(k any) any
- func (p *Package) Type(name Name) Type
- func (p *Package) TypeString(name string) Type
- func (p *Package) Types() []Type
- type Property
- type RestrictedTag
- type SpecificTag
- type Taggable
- type Type
Examples ¶
Constants ¶
const InvalidNameRunes = internal.NotInName
Variables ¶
This section is empty.
Functions ¶
func MultMaxCompare ¶
Types ¶
type AssocEnd ¶
type AssocEnd struct {
// contains filtered or unexported fields
}
func (*AssocEnd) Collection ¶ added in v0.10.0
func (p *AssocEnd) Collection() (Collection, *Key)
func (*AssocEnd) Counterpart ¶
func (*AssocEnd) Mult ¶
func (p *AssocEnd) Mult() Multiplicity
func (*AssocEnd) Owner ¶
func (e *AssocEnd) Owner() ModelElement
func (*AssocEnd) OwningAssoc ¶
func (e *AssocEnd) OwningAssoc() *Association
func (*AssocEnd) SetCollection ¶ added in v0.10.0
func (p *AssocEnd) SetCollection(coll Collection, key *Key) error
func (*AssocEnd) SetDerived ¶
type Association ¶
type Association struct {
// contains filtered or unexported fields
}
func Associate ¶
func Associate( class0 *Class, role0 Name, mult0 Multiplicity, class1 *Class, role1 Name, mult1 Multiplicity, bidi bool, name Name, ) (*Association, error)
func (*Association) BiDi ¶
func (a *Association) BiDi() bool
func (*Association) Ends ¶ added in v0.8.0
func (a *Association) Ends() (aEnd, bEnd *AssocEnd)
func (*Association) FQName ¶
func (a *Association) FQName() NamePath
func (*Association) IndexEnd ¶
func (a *Association) IndexEnd(i EndIndex) *AssocEnd
func (*Association) Model ¶
func (a *Association) Model() *Model
func (*Association) Name ¶
func (a *Association) Name() Name
func (*Association) SetTag ¶
func (a *Association) SetTag(key, tag any) error
func (*Association) Within ¶
func (a *Association) Within() *Package
type Atom ¶ added in v0.8.0
type Atom struct {
// contains filtered or unexported fields
}
- Can be defined to be non-comparable, comparable or ordered → Keys.
- Can be defined to be a restriction of another atom type → Check covariance when redefining attributes.
[mmb.AtomTypeLib] provides a collection of useful types.
func (*Atom) Compares ¶ added in v0.8.0
func (t *Atom) Compares() Comparability
type Attribute ¶
type Attribute struct {
// contains filtered or unexported fields
}
func (*Attribute) Collection ¶ added in v0.10.0
func (p *Attribute) Collection() (Collection, *Key)
func (*Attribute) Mult ¶
func (p *Attribute) Mult() Multiplicity
func (*Attribute) Owner ¶
func (a *Attribute) Owner() ModelElement
func (*Attribute) OwningClass ¶
func (*Attribute) SetCollection ¶ added in v0.10.0
func (p *Attribute) SetCollection(coll Collection, key *Key) error
func (*Attribute) SetDerived ¶
type Class ¶
type Class struct {
// contains filtered or unexported fields
}
Class represents concepts of your problem domain, not your programming language. Generators have to know how to make code from all this.
From [qb]MDD's perspective, classes do not have behavior – this is only about data's structure.
There is an edge case: Properties (Attributes or Association Ends) being derived/non-derived
func (*Class) AllAttributes ¶
AllAttributes returns a list of all attributes starting with class c and then going through the classes from c's BaseList. Redefined attributes are omitted.
func (*Class) AppendMixins ¶ added in v0.6.0
func (*Class) AppendOwnAttributes ¶ added in v0.5.0
func (*Class) AppendProperties ¶ added in v0.4.0
func (*Class) Associated ¶
func (*Class) AttCompares ¶ added in v0.10.0
func (c *Class) AttCompares() Comparability
AttCompares returns the comparability of a class which is derived from the comparability of all attributes of the class.
func (*Class) Attributes ¶
func (*Class) BaseList ¶
BaseList returns the linearized list of unique base class from the “closest” to the most “distant” ancestors.
func (*Class) Compares ¶
func (c *Class) Compares() Comparability
Compares returns the comparability the class's default key, if any.
func (*Class) HasMixedFrom ¶ added in v0.8.2
func (*Class) IsMixedInto ¶ added in v0.8.2
func (*Class) NewAttribute ¶ added in v0.2.0
func (*Class) NewKey ¶ added in v0.9.0
func (t *Class) NewKey(n Name, atts ...KeyElement) (*Key, error)
func (*Class) OwnAttributes ¶ added in v0.5.0
func (*Class) Properties ¶ added in v0.4.0
func (*Class) PropertyString ¶ added in v0.12.0
func (*Class) SetAbstract ¶ added in v0.2.0
type Collection ¶ added in v0.10.0
type Collection uint
const ( Ordered Collection = (1 << iota) Unique )
func (Collection) All ¶ added in v0.10.0
func (ct Collection) All(test Collection) bool
func (Collection) Any ¶ added in v0.10.0
func (ct Collection) Any(test Collection) bool
func (Collection) String ¶ added in v0.10.0
func (i Collection) String() string
type Comparability ¶
type Comparability uint
const ( // For each pair of values from a Equal type it is well defined if both // values are equal or not. Equal Comparability = (1 << iota) // For each pair of values from an Less type it is well defined if one // value is lesser than the other. That does not imply Equal: // x ≮ y ∧ y ≮ x ⇏ x = y Less // The type supports neither Equal or Less. NotComparable Comparability = 0 // The type supports Equal and Less. Orders = Equal | Less )
func (Comparability) All ¶ added in v0.10.0
func (c Comparability) All(set Comparability) bool
func (Comparability) Any ¶ added in v0.10.0
func (c Comparability) Any(set Comparability) bool
func (Comparability) String ¶
func (i Comparability) String() string
type DuplicateBaseError ¶ added in v0.9.0
type DuplicateBaseError struct {
// contains filtered or unexported fields
}
func (DuplicateBaseError) Error ¶ added in v0.9.0
func (e DuplicateBaseError) Error() string
type Enum ¶
type Enum struct { // In cases where the full set of values is not known until the runtime of // the target system, the enum type can be defined to be extensible. Often // such enums have an empty value set in the model. If your system relies on // some special, well-known enum values, those should be defined in the // model already. Extensible bool // If set to true, the enum is not only Equal comparable but it becomes // ordered. Values are then ordered by the order of definition in the model. Ordered bool // contains filtered or unexported fields }
An enumeration is a set of distinct values that are identified by a Name and can be used to enumerate things. By definition enum's Comparability is never NotComparable.
func (*Enum) Compares ¶
func (t *Enum) Compares() Comparability
func (*Enum) HasLiteral ¶
type IncomparableAtom ¶ added in v0.8.0
type IncomparableAtom int
const (
NoRestriction IncomparableAtom = 1
)
func (IncomparableAtom) String ¶ added in v0.8.0
func (i IncomparableAtom) String() string
type IncomparableClass ¶ added in v0.8.0
type IncomparableClass int
func (IncomparableClass) String ¶ added in v0.8.0
func (i IncomparableClass) String() string
type IncomparableEnum ¶ added in v0.8.0
type IncomparableEnum int
const ( DisjointLiteralSets IncomparableEnum = iota + 1 ExtExceedSuperset )
func (IncomparableEnum) String ¶ added in v0.8.0
func (i IncomparableEnum) String() string
type Key ¶
type Key struct {
// contains filtered or unexported fields
}
func (*Key) Add ¶
Add adds an new attribute from the key's owning class to the key. If the attribute's type is a class one can select an attribute key.
func (*Key) Compares ¶
func (k *Key) Compares() Comparability
type KeyElement ¶
type KeyElement struct {
// contains filtered or unexported fields
}
type MixMode ¶ added in v0.6.0
type MixMode int
MixMode describes what mixing in classes does when a mixin finds an existing mixed-in attribute with the same name.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
The Model captures all Types of the modelled problem domain. A Model consists of packages that group the types in reusable units. The dependencies between the packages are checked to be acyclic. Trying to create a cycle results in errors.
The core classes from the mdd package provide everything needed to create models. However crating models with the core API can be tedious because of extensive error checking and somewhat clunky Name handling. I recommend the API of the package mmb (MDD Model Builder) for your daily work when creating models from Go code.
func (*Model) AppendPackages ¶ added in v0.4.0
func (*Model) Associations ¶
func (m *Model) Associations() []*Association
func (*Model) PackageString ¶ added in v0.6.0
type ModelElement ¶
type Multiplicity ¶
type Multiplicity struct {
// contains filtered or unexported fields
}
func Many ¶
func Many(min uint) Multiplicity
func Mult ¶
func Mult(min, max uint) (Multiplicity, error)
func One ¶
func One() Multiplicity
func Opt ¶
func Opt() Multiplicity
func (Multiplicity) Collection ¶
func (m Multiplicity) Collection() bool
func (Multiplicity) Compare ¶
func (m Multiplicity) Compare(n Multiplicity) (bool, int)
func (*Multiplicity) Intersect ¶ added in v0.2.0
func (m *Multiplicity) Intersect(ms ...Multiplicity) bool
func (Multiplicity) Max ¶
func (m Multiplicity) Max() uint
func (Multiplicity) Min ¶
func (m Multiplicity) Min() uint
func (Multiplicity) String ¶
func (m Multiplicity) String() string
type Name ¶
type Name []string
Names in [qb]MDD are made from words. Words are strings that must not contain runes from InvalidNameRunes. A name can be mapped to a string according to some convention, e.g. camel-case string etc. Name also implements fmt.Formatter with its on verbs to allow simple mapping to such naming conventions when printing (see Name.Format).
func NewName ¶ added in v0.5.0
NewName splits n into whitespace separated words, creates a name from the words and validates the result using the acceptEmpty parameter. Consecutive spaces are treated as one separator.
func ParseName ¶
ParseName creates a name from the normalized string representation that is created by Name.String.
Example ¶
fmt.Println(ParseName("<Foo bar BAZ>"))
Output: [Foo bar BAZ] <nil>
func (Name) Format ¶ added in v0.3.0
Supported verbs:
'v' Format as []string 's' Format using Name.String() 'n' Concatenate the unchanged words of the Name 'l' Concatenate the lower case words of the Name 'u' Concatenate the upper case words of the Name 'c' Concatenate the capitalized words of the Name
Flags:
' ' Separate words with a space rune '-' Separate words with minus symbol (kebab case) '+' Separate words with underscore (snake case) '#' Keep acronyms unchanged
When a width value is used with the 'c' verb, all words with index lesser than width will be converted to lower case. All other words will be capitalized. With "%1c" one would produce camel case with first character in lower case.
Example ¶
n := Name{"Foo", "bar"} fmt.Println("Slice of words:", n) fmt.Printf("Delimited string representation: %s\n", n) fmt.Printf("Concatenated unchanged words: %n\n", n) fmt.Printf("Lower case words: %l\n", n) fmt.Printf("Lower case words separated with '-': %-l\n", n) fmt.Printf("Upper case words: %u\n", n) fmt.Printf("Upper case words separated with '_': %+u\n", n) fmt.Printf("Capitalized words (Camel starting at 0): %c\n", n) fmt.Printf("Capitalized separated by ' ': % c\n", n) fmt.Printf("Camel starting at 1: %1c\n", n) fmt.Printf("Camel starting at 1 separated by ' ': % 1c\n", n) fmt.Printf("Camel starting at 2 separated by '_': %+2c\n", Name{"foo", "Bar", "baz"}) fmt.Printf("With unchanged acronym: %#+c\n", Name{"JWT", "Token"}) fmt.Printf("Error: %x\n", n)
Output: Slice of words: [Foo bar] Delimited string representation: <Foo bar> Concatenated unchanged words: Foobar Lower case words: foobar Lower case words separated with '-': foo-bar Upper case words: FOOBAR Upper case words separated with '_': FOO_BAR Capitalized words (Camel starting at 0): FooBar Capitalized separated by ' ': Foo Bar Camel starting at 1: fooBar Camel starting at 1 separated by ' ': foo Bar Camel starting at 2 separated by '_': foo_bar_Baz With unchanged acronym: JWT_Token Error: %!x(invalid verb for mdd.Name <Foo bar>)
type Package ¶
type Package struct {
// contains filtered or unexported fields
}
func (*Package) AddDependency ¶
AddDependency lets package p depend on to given that this will not create cyclic dependency graph. A package is considered to depend on itself anyway but adding this dependency will have no effect.
func (*Package) AppendAtoms ¶ added in v0.8.0
func (*Package) AppendClasses ¶ added in v0.4.0
func (*Package) AppendEnums ¶ added in v0.4.0
func (*Package) AppendTypes ¶ added in v0.11.1
func (*Package) Dependencies ¶
Dependencies returns packages that p directly depends on.
func (*Package) DependencyPath ¶ added in v0.2.0
func (*Package) NewAtom ¶ added in v0.8.0
func (p *Package) NewAtom(name Name, cmpr Comparability) (*Atom, error)
func (*Package) Supported ¶ added in v0.5.0
Supported returns packages that are directly supported by p.
func (*Package) TypeString ¶ added in v0.5.0
type Property ¶
type Property interface { Owner() ModelElement Name() Name FQName() NamePath Type() Type Mult() Multiplicity Derived() bool SetDerived(bool) error Collection() (Collection, *Key) SetCollection(typ Collection, key *Key) error Taggable fmt.Stringer }
type RestrictedTag ¶ added in v0.5.0
A RestrictedTag will be checked to be valid before attached to a Taggable. Tag keys as well as tag values will be checked when implementing RestrictedTag.
type SpecificTag ¶ added in v0.9.1
type SpecificTag[T Taggable] struct{}
SpecificTag can be embedded to implement a RestrictedTag for T.
func (SpecificTag[T]) Tags ¶ added in v0.9.1
func (st SpecificTag[T]) Tags(e Taggable) bool
type Taggable ¶
type Taggable interface { Tag(k any) any SetTag(key, tag any) error // contains filtered or unexported methods }
Taggable is the interface for all model elements that can be tagged with arbitrary values. This is intended for use with generators - comparable to the stereotypes of UML as an extension mechanism.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package doc implements a [qb]MDD model for the mdd metamodel itself.
|
Package doc implements a [qb]MDD model for the mdd metamodel itself. |
examples
|
|
modular
Package modular imeplements a [qb]MDD model in a modular fashion.
|
Package modular imeplements a [qb]MDD model in a modular fashion. |
modular/complexpkg
Package complexpkg uses a rather complex way to define the package.
|
Package complexpkg uses a rather complex way to define the package. |
modular/model
Package model puts together the modular example model.
|
Package model puts together the modular example model. |
modular/simplepkg
Package simplepkg simply defines a package with a few elements.
|
Package simplepkg simply defines a package with a few elements. |
mymusic
Package mymusic implemets a model for a music database that makes use of many typical [qb]MDD features.
|
Package mymusic implemets a model for a music database that makes use of many typical [qb]MDD features. |
mymusic/puml
Generate PlantUML class diagram for the mymusic example model.
|
Generate PlantUML class diagram for the mymusic example model. |
mymusic/template
Generate AsciiDoc output with Go's text/template from the mymusic example model.
|
Generate AsciiDoc output with Go's text/template from the mymusic example model. |
Package mdg is the Model Driven Generator Toolbox for [qb]MDD.
|
Package mdg is the Model Driven Generator Toolbox for [qb]MDD. |
Package mmb – the [qb]MDD Model Builder – provides a wrapper around mdd to create models with a convenient syntax.
|
Package mmb – the [qb]MDD Model Builder – provides a wrapper around mdd to create models with a convenient syntax. |
Package puml provides generators for PlantUML files from [qb]MDD models.
|
Package puml provides generators for PlantUML files from [qb]MDD models. |