lutaml-uml 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +36 -0
  3. data/.github/workflows/ubuntu.yml +38 -0
  4. data/.github/workflows/windows.yml +41 -0
  5. data/.gitignore +1 -0
  6. data/Gemfile +2 -1
  7. data/LUTAML.adoc +314 -0
  8. data/{README.md → README.adoc} +15 -16
  9. data/Rakefile +3 -1
  10. data/bin/console +1 -0
  11. data/bin/lutaml2dotpng +23 -0
  12. data/bin/yaml2lutaml +108 -0
  13. data/exe/lutaml-uml +4 -3
  14. data/lib/lutaml/layout/engine.rb +15 -0
  15. data/lib/lutaml/layout/graph_viz_engine.rb +16 -0
  16. data/lib/lutaml/uml.rb +3 -0
  17. data/lib/lutaml/uml/abstraction.rb +7 -5
  18. data/lib/lutaml/uml/activity.rb +7 -5
  19. data/lib/lutaml/uml/actor.rb +14 -12
  20. data/lib/lutaml/uml/association.rb +40 -14
  21. data/lib/lutaml/uml/behavior.rb +7 -5
  22. data/lib/lutaml/uml/class.rb +56 -16
  23. data/lib/lutaml/uml/classifier.rb +9 -6
  24. data/lib/lutaml/uml/connector.rb +16 -12
  25. data/lib/lutaml/uml/constraint.rb +8 -7
  26. data/lib/lutaml/uml/constructor_end.rb +11 -8
  27. data/lib/lutaml/uml/data_type.rb +9 -4
  28. data/lib/lutaml/uml/dependency.rb +16 -13
  29. data/lib/lutaml/uml/document.rb +71 -0
  30. data/lib/lutaml/uml/enum.rb +33 -0
  31. data/lib/lutaml/uml/event.rb +7 -5
  32. data/lib/lutaml/uml/final_state.rb +7 -5
  33. data/lib/lutaml/uml/formatter.rb +21 -0
  34. data/lib/lutaml/uml/formatter/base.rb +67 -0
  35. data/lib/lutaml/uml/formatter/graphviz.rb +335 -0
  36. data/lib/lutaml/uml/has_attributes.rb +14 -0
  37. data/lib/lutaml/uml/has_members.rb +30 -0
  38. data/lib/lutaml/uml/instance.rb +15 -10
  39. data/lib/lutaml/uml/interface/base.rb +28 -0
  40. data/lib/lutaml/uml/interface/command_line.rb +265 -0
  41. data/lib/lutaml/uml/model.rb +11 -8
  42. data/lib/lutaml/uml/node/base.rb +21 -0
  43. data/lib/lutaml/uml/node/class_node.rb +57 -0
  44. data/lib/lutaml/uml/node/class_relationship.rb +14 -0
  45. data/lib/lutaml/uml/node/document.rb +18 -0
  46. data/lib/lutaml/uml/node/field.rb +34 -0
  47. data/lib/lutaml/uml/node/has_name.rb +15 -0
  48. data/lib/lutaml/uml/node/has_type.rb +15 -0
  49. data/lib/lutaml/uml/node/method.rb +29 -0
  50. data/lib/lutaml/uml/node/method_argument.rb +16 -0
  51. data/lib/lutaml/uml/node/relationship.rb +28 -0
  52. data/lib/lutaml/uml/opaque_behavior.rb +7 -6
  53. data/lib/lutaml/uml/package.rb +16 -13
  54. data/lib/lutaml/uml/parsers/attribute.rb +70 -0
  55. data/lib/lutaml/uml/parsers/dsl.rb +375 -0
  56. data/lib/lutaml/uml/parsers/dsl_preprocessor.rb +44 -0
  57. data/lib/lutaml/uml/parsers/dsl_transform.rb +27 -0
  58. data/lib/lutaml/uml/parsers/yaml.rb +46 -0
  59. data/lib/lutaml/uml/port.rb +6 -4
  60. data/lib/lutaml/uml/primitive_type.rb +9 -4
  61. data/lib/lutaml/uml/property.rb +25 -15
  62. data/lib/lutaml/uml/pseudostate.rb +7 -6
  63. data/lib/lutaml/uml/realization.rb +7 -5
  64. data/lib/lutaml/uml/region.rb +7 -6
  65. data/lib/lutaml/uml/serializers/association.rb +58 -0
  66. data/lib/lutaml/uml/serializers/base.rb +16 -0
  67. data/lib/lutaml/uml/serializers/class.rb +29 -0
  68. data/lib/lutaml/uml/serializers/top_element_attribute.rb +14 -0
  69. data/lib/lutaml/uml/serializers/yaml_view.rb +18 -0
  70. data/lib/lutaml/uml/state.rb +8 -6
  71. data/lib/lutaml/uml/state_machine.rb +7 -5
  72. data/lib/lutaml/uml/top_element.rb +45 -35
  73. data/lib/lutaml/uml/top_element_attribute.rb +25 -0
  74. data/lib/lutaml/uml/transition.rb +8 -6
  75. data/lib/lutaml/uml/trigger.rb +8 -6
  76. data/lib/lutaml/uml/version.rb +3 -1
  77. data/lib/lutaml/uml/vertex.rb +7 -5
  78. data/lutaml-uml.gemspec +9 -2
  79. data/spec/fixtures/datamodel/models/AddressClassProfile.yml +90 -0
  80. data/spec/fixtures/datamodel/models/AddressComponentProfile.yml +63 -0
  81. data/spec/fixtures/datamodel/models/AddressComponentSpecification.yml +15 -0
  82. data/spec/fixtures/datamodel/models/AddressProfile.yml +36 -0
  83. data/spec/fixtures/datamodel/models/AttributeProfile.yml +32 -0
  84. data/spec/fixtures/datamodel/models/InterchangeAddressClassProfile.yml +79 -0
  85. data/spec/fixtures/datamodel/models/Localization copy.yml +23 -0
  86. data/spec/fixtures/datamodel/models/Localization.yml +23 -0
  87. data/spec/fixtures/datamodel/models/ProfileCompliantAddress.yml +36 -0
  88. data/spec/fixtures/datamodel/models/ProfileCompliantAddressComponent.yml +15 -0
  89. data/spec/fixtures/datamodel/models/Signature.yml +20 -0
  90. data/spec/fixtures/datamodel/models/SignatureBlankDefinition.yml +20 -0
  91. data/spec/fixtures/datamodel/models/TextDirectionCode copy.yml +16 -0
  92. data/spec/fixtures/datamodel/models/TextDirectionCode.yml +16 -0
  93. data/spec/fixtures/datamodel/models/Validity.yml +14 -0
  94. data/spec/fixtures/datamodel/models/iso19160-1/Address.yml +22 -0
  95. data/spec/fixtures/datamodel/models/iso19160-1/AddressComponent.yml +2 -0
  96. data/spec/fixtures/datamodel/style.uml.inc +37 -0
  97. data/spec/fixtures/datamodel/views/AddressClassProfile.yml +12 -0
  98. data/spec/fixtures/datamodel/views/AddressProfile.yml +3 -0
  99. data/spec/fixtures/datamodel/views/CommonModels.yml +9 -0
  100. data/spec/fixtures/datamodel/views/TopDown.yml +62 -0
  101. data/spec/fixtures/dsl/diagram.lutaml +3 -0
  102. data/spec/fixtures/dsl/diagram_attributes.lutaml +5 -0
  103. data/spec/fixtures/dsl/diagram_class_assocation.lutaml +29 -0
  104. data/spec/fixtures/dsl/diagram_class_fields.lutaml +19 -0
  105. data/spec/fixtures/dsl/diagram_comments.lutaml +28 -0
  106. data/spec/fixtures/dsl/diagram_concept_model.lutaml +132 -0
  107. data/spec/fixtures/dsl/diagram_data_types.lutaml +24 -0
  108. data/spec/fixtures/dsl/diagram_includes.lutaml +6 -0
  109. data/spec/fixtures/dsl/diagram_multiply_classes.lutaml +7 -0
  110. data/spec/fixtures/dsl/shared.lutaml +3 -0
  111. data/spec/fixtures/dsl/shared1.lutaml +4 -0
  112. data/spec/fixtures/generated_dot/AddressClassProfile.dot +170 -0
  113. data/spec/fixtures/generated_dot/AddressProfile.dot +34 -0
  114. data/spec/lutaml/uml/formatter/graphviz_spec.rb +41 -0
  115. data/spec/lutaml/uml/parsers/dsl_spec.rb +252 -0
  116. data/spec/lutaml/uml/parsers/yaml_spec.rb +18 -0
  117. data/spec/lutaml/uml/serializers/yaml_view_spec.rb +20 -0
  118. data/spec/lutaml/uml_spec.rb +2 -4
  119. data/spec/spec_helper.rb +11 -0
  120. metadata +161 -13
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/uml/node/relationship"
4
+ require "lutaml/uml/node/has_name"
5
+
6
+ module Lutaml
7
+ module Uml
8
+ module Node
9
+ class ClassRelationship < Relationship
10
+ include HasName
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/uml/node/base"
4
+ require "lutaml/uml/node/class_node"
5
+
6
+ module Lutaml
7
+ module Uml
8
+ module Node
9
+ class Document < Base
10
+ attr_reader :classes
11
+
12
+ def classes=(value)
13
+ @classes = value.to_a.map { |attributes| ClassNode.new(attributes) }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/uml/node/base"
4
+ require "lutaml/uml/node/has_name"
5
+ require "lutaml/uml/node/has_type"
6
+
7
+ module Lutaml
8
+ module Uml
9
+ module Node
10
+ class Field < Base
11
+ include HasName
12
+ include HasType
13
+
14
+ def initialize(attributes = {})
15
+ @access = "public"
16
+
17
+ super
18
+ end
19
+
20
+ attr_reader :static
21
+
22
+ def static=(value)
23
+ @static = !!value
24
+ end
25
+
26
+ attr_reader :access
27
+
28
+ def access=(value)
29
+ @access = value.to_s # TODO: Validate?
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Uml
5
+ module Node
6
+ module HasName
7
+ attr_reader :name
8
+
9
+ def name=(value)
10
+ @name = value.to_s
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Uml
5
+ module Node
6
+ module HasType
7
+ attr_reader :type
8
+
9
+ def type=(value)
10
+ @type = value.to_s
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/uml/node/field"
4
+ require "lutaml/uml/node/method_argument"
5
+ require "lutaml/uml/node/has_name"
6
+
7
+ module Lutaml
8
+ module Uml
9
+ module Node
10
+ class Method < Field
11
+ include HasName
12
+
13
+ attr_reader :abstract
14
+
15
+ def abstract=(value)
16
+ @abstract = !!value
17
+ end
18
+
19
+ attr_reader :arguments
20
+
21
+ def arguments=(value)
22
+ @arguments = value.to_a.map do |attributes|
23
+ MethodArgument.new(attributes)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/uml/node/base"
4
+ require "lutaml/uml/node/has_name"
5
+ require "lutaml/uml/node/has_type"
6
+
7
+ module Lutaml
8
+ module Uml
9
+ module Node
10
+ class MethodArgument < Base
11
+ include HasName
12
+ include HasType
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/uml/node/base"
4
+ require "lutaml/uml/node/has_name"
5
+ require "lutaml/uml/node/has_type"
6
+
7
+ module Lutaml
8
+ module Uml
9
+ module Node
10
+ class Relationship < Base
11
+ include HasName
12
+ include HasType
13
+
14
+ attr_reader :from
15
+
16
+ def from=(value)
17
+ @from = value.to_s
18
+ end
19
+
20
+ attr_reader :to
21
+
22
+ def to=(value)
23
+ @to = value.to_s
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  ## Behaviour metamodel
3
5
  ##
4
- module Lutaml::Uml
5
-
6
- class OpaqueBehavior < Behavior
7
- end
8
-
9
-
6
+ module Lutaml
7
+ module Uml
8
+ class OpaqueBehavior < Behavior
9
+ end
10
+ end
10
11
  end
@@ -1,16 +1,19 @@
1
- module Lutaml::Uml
1
+ # frozen_string_literal: true
2
2
 
3
- class Package < TopElement
4
- attr_accessor :imports, :contents
5
- def initialize
6
- @imports = []
7
- @contents = []
8
- @name = nil
9
- @xmi_id = nil
10
- @xmi_uuid = nil
11
- @namespace = nil
12
- @href = nil
13
- end
14
- end
3
+ module Lutaml
4
+ module Uml
5
+ class Package < TopElement
6
+ attr_accessor :imports, :contents
15
7
 
8
+ def initialize
9
+ @imports = []
10
+ @contents = []
11
+ @name = nil
12
+ @xmi_id = nil
13
+ @xmi_uuid = nil
14
+ @namespace = nil
15
+ @href = nil
16
+ end
17
+ end
18
+ end
16
19
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Lutaml
6
+ module Uml
7
+ module Parsers
8
+ class Attribute < Parslet::Parser
9
+ class Transform < Parslet::Transform
10
+ rule(integer: simple(:x)) { Integer(x) }
11
+ rule(float: simple(:x)) { Float(x) }
12
+ rule(string: simple(:x)) { String(x) }
13
+ end
14
+
15
+ def self.parse(io, options = {})
16
+ new.parse(io, options)
17
+ end
18
+
19
+ def parse(io, options = {})
20
+ tree = Transform.new.apply(super)
21
+ tree = tree[:assignments].each_with_object({}) do |assignment, memo|
22
+ memo[assignment[:name].to_s] = assignment[:value]
23
+ end
24
+
25
+ tree
26
+ end
27
+
28
+ rule(:spaces) { match("\s").repeat(1) }
29
+ rule(:spaces?) { spaces.maybe }
30
+
31
+ rule(:digits) { match["0-9"].repeat(1) }
32
+
33
+ rule(:integer) do
34
+ (str("-").maybe >> digits >> str(".").absent?).as(:integer)
35
+ end
36
+ rule(:float) do
37
+ (str("-").maybe >> digits >> str(".") >> digits).as(:float)
38
+ end
39
+
40
+ rule(:string_single_quoted) do
41
+ str("'") >>
42
+ (str("'").absent? >> any).repeat.as(:string) >>
43
+ str("'")
44
+ end
45
+ rule(:string_double_quoted) do
46
+ str('"') >>
47
+ (str('"').absent? >> any).repeat.as(:string) >>
48
+ str('"')
49
+ end
50
+
51
+ rule(:string) { string_single_quoted | string_double_quoted }
52
+
53
+ rule(:assignment_name) do
54
+ (match["=\s"].absent? >> any).repeat.as(:name)
55
+ end
56
+ rule(:assignment_value) { (integer | float | string).as(:value) }
57
+ rule(:assignment) do
58
+ assignment_name >> spaces? >> str("=") >> spaces? >> assignment_value
59
+ end
60
+
61
+ rule(:attribute) { spaces? >> assignment >> spaces? }
62
+ rule(:attributes) do
63
+ (attribute >> (str(",") >> attribute).repeat).repeat.as(:assignments)
64
+ end
65
+
66
+ root(:attributes)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,375 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+ require "lutaml/uml/parsers/dsl_preprocessor"
5
+ require "lutaml/uml/parsers/dsl_transform"
6
+ require "lutaml/uml/node/document"
7
+
8
+ module Lutaml
9
+ module Uml
10
+ module Parsers
11
+ # Class for parsing LutaML dsl into Lutaml::Uml::Document
12
+ class Dsl < Parslet::Parser
13
+ # @param [String] io - LutaML string representation
14
+ # [Hash] options - options for parsing
15
+ #
16
+ # @return [Lutaml::Uml::Document]
17
+ def self.parse(io, options = {})
18
+ new.parse(io, options)
19
+ end
20
+
21
+ def parse(input_file, _options = {})
22
+ data = Lutaml::Uml::Parsers::DslPreprocessor.call(input_file)
23
+ ::Lutaml::Uml::Document.new(DslTransform.new.apply(super(data)))
24
+ end
25
+
26
+ KEYWORDS = %w[
27
+ abstract
28
+ aggregation
29
+ association
30
+ association
31
+ attribute
32
+ bidirectional
33
+ class
34
+ composition
35
+ data_type
36
+ dependency
37
+ diagram
38
+ directional
39
+ enum
40
+ fontname
41
+ generalizes
42
+ include
43
+ interface
44
+ member
45
+ member_type
46
+ method
47
+ owner
48
+ owner_type
49
+ primitive
50
+ private
51
+ protected
52
+ public
53
+ realizes
54
+ static
55
+ title
56
+ ].freeze
57
+
58
+ KEYWORDS.each do |keyword|
59
+ rule("kw_#{keyword}") { str(keyword) }
60
+ end
61
+
62
+ rule(:spaces) { match("\s").repeat(1) }
63
+ rule(:spaces?) { spaces.maybe }
64
+ rule(:whitespace) { (match("\s") | match("\n") | str(";")).repeat(1) }
65
+ rule(:whitespace?) { whitespace.maybe }
66
+ rule(:name) { match["a-zA-Z0-9 _-"].repeat(1) }
67
+ rule(:newline) { str("\n") >> str("\r").maybe }
68
+ rule(:comment_definition) do
69
+ spaces? >> str("**") >> (newline.absent? >> any).repeat.as(:comments)
70
+ end
71
+ rule(:comment_multiline_definition) do
72
+ spaces? >> str("*|") >> (str("|*").absent? >> any).repeat.as(:comments) >> whitespace? >> str("|*")
73
+ end
74
+ rule(:class_name_chars) { match('(?:[a-zA-Z0-9 _-]|\:|\.)').repeat(1) }
75
+ rule(:class_name) do
76
+ class_name_chars >>
77
+ (str("(") >>
78
+ class_name_chars >>
79
+ str(")")).maybe
80
+ end
81
+ rule(:cardinality_body_definition) do
82
+ match['0-9\*'].as(:min) >>
83
+ str("..").maybe >>
84
+ match['0-9\*'].as(:max).maybe
85
+ end
86
+ rule(:cardinality) do
87
+ str("[") >>
88
+ cardinality_body_definition.as(:cardinality) >>
89
+ str("]")
90
+ end
91
+ rule(:cardinality?) { cardinality.maybe }
92
+
93
+ # -- attribute/Method
94
+ rule(:kw_visibility_modifier) do
95
+ str("+") | str("-") | str("#") | str("~")
96
+ end
97
+
98
+ rule(:member_static) { (kw_static.as(:static) >> spaces).maybe }
99
+ rule(:visibility) do
100
+ kw_visibility_modifier.as(:visibility_modifier)
101
+ end
102
+ rule(:visibility?) { visibility.maybe }
103
+
104
+ rule(:method_abstract) { (kw_abstract.as(:abstract) >> spaces).maybe }
105
+ rule(:attribute_keyword) do
106
+ str("<<") >>
107
+ match['a-zA-Z0-9_\-'].repeat(1).as(:keyword) >>
108
+ str(">>")
109
+ end
110
+ rule(:attribute_keyword?) { attribute_keyword.maybe }
111
+ rule(:attribute_type) do
112
+ (str(":") >>
113
+ spaces? >>
114
+ attribute_keyword? >>
115
+ spaces? >>
116
+ match['"\''].maybe >>
117
+ match['a-zA-Z0-9_\- '].repeat(1).as(:type) >>
118
+ match['"\''].maybe >>
119
+ spaces?
120
+ )
121
+ end
122
+ rule(:attribute_type?) do
123
+ attribute_type.maybe
124
+ end
125
+
126
+ rule(:attribute_name) { name.as(:name) }
127
+ rule(:attribute_definition) do
128
+ (visibility?.as(:visibility) >>
129
+ match['"\''].maybe >>
130
+ attribute_name >>
131
+ match['"\''].maybe >>
132
+ attribute_type? >>
133
+ cardinality?)
134
+ .as(:attributes)
135
+ end
136
+
137
+ rule(:title_keyword) { kw_title >> spaces }
138
+ rule(:title_text) do
139
+ match['"\''].maybe >>
140
+ match['a-zA-Z0-9_\- '].repeat(1).as(:title) >>
141
+ match['"\''].maybe
142
+ end
143
+ rule(:title_definition) { title_keyword >> title_text }
144
+
145
+ rule(:fontname_keyword) { kw_fontname >> spaces }
146
+ rule(:fontname_text) do
147
+ match['"\''].maybe >>
148
+ match['a-zA-Z0-9_\- '].repeat(1).as(:fontname) >>
149
+ match['"\''].maybe
150
+ end
151
+ rule(:fontname_definition) { fontname_keyword >> fontname_text }
152
+
153
+ # Method
154
+ # rule(:method_keyword) { kw_method >> spaces }
155
+ # rule(:method_argument) { name.as(:name) >> member_type }
156
+ # rule(:method_arguments_inner) do
157
+ # (method_argument >>
158
+ # (spaces? >> str(",") >> spaces? >> method_argument).repeat)
159
+ # .repeat.as(:arguments)
160
+ # end
161
+ # rule(:method_arguments) do
162
+ # (str("(") >>
163
+ # spaces? >>
164
+ # method_arguments_inner >>
165
+ # spaces? >>
166
+ # str(")"))
167
+ # .maybe
168
+ # end
169
+
170
+ # rule(:method_name) { name.as(:name) }
171
+ # rule(:method_return_type) { member_type.maybe }
172
+ # rule(:method_definition) do
173
+ # (method_abstract >>
174
+ # member_static >>
175
+ # visibility >>
176
+ # method_keyword >>
177
+ # method_name >>
178
+ # method_arguments >>
179
+ # method_return_type)
180
+ # .as(:method)
181
+ # end
182
+
183
+ # -- Association
184
+
185
+ rule(:association_keyword) { kw_association >> spaces }
186
+
187
+ %w[owner member].each do |association_end_type|
188
+ rule("#{association_end_type}_cardinality") do
189
+ spaces? >>
190
+ str("[") >>
191
+ cardinality_body_definition
192
+ .as("#{association_end_type}_end_cardinality") >>
193
+ str("]")
194
+ end
195
+ rule("#{association_end_type}_cardinality?") do
196
+ send("#{association_end_type}_cardinality").maybe
197
+ end
198
+ rule("#{association_end_type}_attribute_name") do
199
+ str("#") >>
200
+ visibility? >>
201
+ name.as("#{association_end_type}_end_attribute_name")
202
+ end
203
+ rule("#{association_end_type}_attribute_name?") do
204
+ send("#{association_end_type}_attribute_name").maybe
205
+ end
206
+ rule("#{association_end_type}_definition") do
207
+ send("kw_#{association_end_type}") >>
208
+ spaces >>
209
+ name.as("#{association_end_type}_end") >>
210
+ send("#{association_end_type}_attribute_name?") >>
211
+ send("#{association_end_type}_cardinality?")
212
+ end
213
+ rule("#{association_end_type}_type") do
214
+ send("kw_#{association_end_type}_type") >>
215
+ spaces >>
216
+ name.as("#{association_end_type}_end_type")
217
+ end
218
+ end
219
+
220
+ rule(:association_inner_definitions) do
221
+ owner_type |
222
+ member_type |
223
+ owner_definition |
224
+ member_definition |
225
+ comment_definition |
226
+ comment_multiline_definition
227
+ end
228
+ rule(:association_inner_definition) do
229
+ association_inner_definitions >> whitespace?
230
+ end
231
+ rule(:association_body) do
232
+ spaces? >>
233
+ str("{") >>
234
+ whitespace? >>
235
+ association_inner_definition.repeat.as(:members) >>
236
+ str("}")
237
+ end
238
+ rule(:association_definition) do
239
+ association_keyword >>
240
+ name.as(:name).maybe >>
241
+ association_body
242
+ end
243
+
244
+ # -- Class
245
+
246
+ rule(:kw_class_modifier) { kw_abstract | kw_interface }
247
+
248
+ rule(:class_modifier) do
249
+ (kw_class_modifier.as(:modifier) >> spaces).maybe
250
+ end
251
+ rule(:class_keyword) { kw_class >> spaces }
252
+ rule(:class_inner_definitions) do
253
+ attribute_definition |
254
+ comment_definition |
255
+ comment_multiline_definition
256
+ end
257
+ rule(:class_inner_definition) do
258
+ class_inner_definitions >> whitespace?
259
+ end
260
+ rule(:class_body) do
261
+ spaces? >>
262
+ str("{") >>
263
+ whitespace? >>
264
+ class_inner_definition.repeat.as(:members) >>
265
+ str("}")
266
+ end
267
+ rule(:class_body?) { class_body.maybe }
268
+ rule(:class_definition) do
269
+ class_modifier >>
270
+ class_keyword >>
271
+ class_name.as(:name) >>
272
+ spaces? >>
273
+ attribute_keyword? >>
274
+ class_body?
275
+ end
276
+
277
+ # -- Enum
278
+ rule(:enum_keyword) { kw_enum >> spaces }
279
+ rule(:enum_inner_definitions) do
280
+ attribute_definition |
281
+ comment_definition |
282
+ comment_multiline_definition
283
+ end
284
+ rule(:enum_inner_definition) do
285
+ enum_inner_definitions >> whitespace?
286
+ end
287
+ rule(:enum_body) do
288
+ spaces? >>
289
+ str("{") >>
290
+ whitespace? >>
291
+ enum_inner_definition.repeat.as(:members) >>
292
+ str("}")
293
+ end
294
+ rule(:enum_body?) { enum_body.maybe }
295
+ rule(:enum_definition) do
296
+ enum_keyword >>
297
+ match['"\''].maybe >>
298
+ class_name.as(:name) >>
299
+ match['"\''].maybe >>
300
+ enum_body?
301
+ end
302
+
303
+ # -- data_type
304
+ rule(:data_type_keyword) { kw_data_type >> spaces }
305
+ rule(:data_type_inner_definitions) do
306
+ attribute_definition
307
+ end
308
+ rule(:data_type_inner_definition) do
309
+ data_type_inner_definitions >> whitespace?
310
+ end
311
+ rule(:data_type_body) do
312
+ spaces? >>
313
+ str("{") >>
314
+ whitespace? >>
315
+ data_type_inner_definition.repeat.as(:members) >>
316
+ str("}")
317
+ end
318
+ rule(:data_type_body?) { data_type_body.maybe }
319
+ rule(:data_type_definition) do
320
+ data_type_keyword >>
321
+ match['"\''].maybe >>
322
+ class_name.as(:name) >>
323
+ match['"\''].maybe >>
324
+ data_type_body?
325
+ end
326
+
327
+ # -- primitive
328
+ rule(:primitive_keyword) { kw_primitive >> spaces }
329
+ rule(:primitive_definition) do
330
+ primitive_keyword >>
331
+ match['"\''].maybe >>
332
+ class_name.as(:name) >>
333
+ match['"\''].maybe
334
+ end
335
+
336
+ # -- Diagram
337
+ rule(:diagram_keyword) { kw_diagram >> spaces? }
338
+ rule(:diagram_inner_definitions) do
339
+ title_definition |
340
+ fontname_definition |
341
+ class_definition.as(:classes) |
342
+ enum_definition.as(:enums) |
343
+ primitive_definition.as(:primitives) |
344
+ data_type_definition.as(:data_types) |
345
+ association_definition.as(:associations) |
346
+ comment_definition |
347
+ comment_multiline_definition
348
+ end
349
+ rule(:diagram_inner_definition) do
350
+ diagram_inner_definitions >> whitespace?
351
+ end
352
+ rule(:diagram_body) do
353
+ spaces? >>
354
+ str("{") >>
355
+ whitespace? >>
356
+ diagram_inner_definition.repeat.as(:members) >>
357
+ str("}")
358
+ end
359
+ rule(:diagram_body?) { diagram_body.maybe }
360
+ rule(:diagram_definition) do
361
+ diagram_keyword >>
362
+ spaces? >>
363
+ class_name.as(:name) >>
364
+ diagram_body? >>
365
+ whitespace?
366
+ end
367
+ rule(:diagram_definitions) { diagram_definition >> whitespace? }
368
+ rule(:diagram) { whitespace? >> diagram_definition }
369
+ # -- Root
370
+
371
+ root(:diagram)
372
+ end
373
+ end
374
+ end
375
+ end