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
@@ -1,28 +1,27 @@
1
1
  # Lutaml::Uml
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/lutaml/uml`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Lutaml is a language for specifying UML class diagrams and a tool for converting it into various different formats.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ ## Install
6
6
 
7
- ## Installation
7
+ ### Bundler: `gem "lutaml-uml"`
8
8
 
9
- Add this line to your application's Gemfile:
9
+ ### RubyGems: `gem install lutaml-uml`
10
10
 
11
- ```ruby
12
- gem 'lutaml-uml'
13
- ```
11
+ ## Executable
14
12
 
15
- And then execute:
13
+ [source,sh]
14
+ --
15
+ # Convert example.lutaml to example.png
16
+ $ lutaml-uml --type png --output . example.lutaml
16
17
 
17
- $ bundle install
18
+ # Display detailed help message
19
+ $ lutaml-uml --help
20
+ --
18
21
 
19
- Or install it yourself as:
22
+ ## Language
20
23
 
21
- $ gem install lutaml-uml
22
-
23
- ## Usage
24
-
25
- TODO: Write usage instructions here
24
+ See link:LUTAML.adoc[LUTAML.adoc]
26
25
 
27
26
  ## Development
28
27
 
@@ -37,4 +36,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERN
37
36
 
38
37
  ## Code of Conduct
39
38
 
40
- Everyone interacting in the Lutaml::Uml project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/lutaml-uml/blob/master/CODE_OF_CONDUCT.md).
39
+ Everyone interacting in the Lutaml::Uml project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/lutaml-uml/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "bundler/setup"
4
5
  require "lutaml/uml"
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # Script to convert lutaml files into dot and png files
6
+ # Usage: bin/lutaml2dotpng /path/to/lutaml/folder/
7
+ require "bundler/setup"
8
+ require "lutaml/uml"
9
+
10
+ basedir = ARGV[0]
11
+ Dir["#{basedir}/*.lutaml"].each do |filename|
12
+ puts(filename)
13
+ base_filename = File.basename(filename, '.lutaml')
14
+ File.open("#{basedir}/#{base_filename}.dot", 'w') do |file|
15
+ file
16
+ .puts(Lutaml::Uml::Formatter::Graphviz
17
+ .new
18
+ .format_document(
19
+ Lutaml::Uml::Parsers::Dsl
20
+ .parse(File.read("#{basedir}/#{base_filename}.lutaml"))))
21
+ end
22
+ `dot -T png #{"#{basedir}/#{base_filename}.dot"} > "#{basedir}/#{base_filename}.png"`
23
+ end
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # Script to convert datamodel yaml files into LutaML syntax
6
+ # Usage: bin/yaml2lutaml /path/to/datamodel/view/file.yml
7
+
8
+ require "yaml"
9
+
10
+ view_yaml = YAML.safe_load(File.read(ARGV[0]))
11
+ models_path = File.expand_path("../../models", ARGV[0])
12
+
13
+ def sync_puts(line, level = 0)
14
+ $stdout.puts("#{''.rjust(level)}#{line}")
15
+ $stdout.flush
16
+ end
17
+
18
+ encountered_relations = Hash.new { |h, key| h[key] = [] }
19
+ # relations:
20
+ # - target: AttributeProfile
21
+ # relationship:
22
+ # source:
23
+ # type: aggregation
24
+ # attribute:
25
+ # addressClassProfile:
26
+ # target:
27
+ # type: direct
28
+ # attribute:
29
+ # attributeProfile:
30
+ # cardinality:
31
+ # min: 0
32
+ # max: '*'
33
+ def process_association(owner, values, encountered_relations)
34
+ target_name = values["target"]
35
+ return if encountered_relations[owner].include?(target_name)
36
+
37
+ encountered_relations[owner].push(target_name)
38
+ sync_puts("association {", 2)
39
+
40
+ relationship_block = values["relationship"] || {}
41
+
42
+ if relationship_block["source"] && relationship_block["source"]["type"]
43
+ source = relationship_block["source"]
44
+ sync_puts("owner_type #{source['type']}", 4)
45
+ if source["attribute"]
46
+ source_attribute_name = source["attribute"].keys.first
47
+ owner += "##{source_attribute_name}"
48
+ if source["attribute"][source_attribute_name]["cardinality"]
49
+ cardinality = source["attribute"][source_attribute_name]["cardinality"]
50
+ owner += " [#{cardinality['min']}..#{cardinality['max']}]"
51
+ end
52
+ end
53
+ end
54
+ sync_puts("owner #{owner}", 4)
55
+
56
+ member = target_name
57
+ if relationship_block["target"]
58
+ target = relationship_block["target"]
59
+ type = target["type"] || "direct"
60
+ sync_puts("member_type #{type}", 4)
61
+ if target["attribute"]
62
+ target_attribute_name = target["attribute"].keys.first
63
+ member += "##{target_attribute_name}"
64
+ if target["attribute"][target_attribute_name]["cardinality"]
65
+ cardinality = target["attribute"][target_attribute_name]["cardinality"]
66
+ member += " [#{cardinality['min']}..#{cardinality['max']}]"
67
+ end
68
+ end
69
+ else
70
+ sync_puts("member_type direct", 4)
71
+ end
72
+ sync_puts("member #{member}", 4)
73
+
74
+ sync_puts("}", 2)
75
+ end
76
+ sync_puts("diagram #{File.basename(ARGV[0], 'yml')[0..-2]} {")
77
+ sync_puts("title '#{view_yaml['title']}'", 2)
78
+
79
+ # Class associations notations
80
+ view_yaml["relations"]&.each do |values|
81
+ process_association(values["source"], values, encountered_relations)
82
+ end
83
+
84
+ view_yaml["imports"].keys.each do |entry|
85
+ import = YAML.safe_load(File.read(File.join(models_path, "#{entry}.yml")))
86
+ import_name = import["name"]
87
+ # Class notation
88
+ sync_puts("#{import['modelType']} #{import['name']} {", 2)
89
+ import["values"]&.each_pair do |key, values|
90
+ sync_puts("#{key}", 4)
91
+ end
92
+ import["attributes"]&.each_pair do |key, values|
93
+ cardinality = if values["cardinality"]
94
+ cardinality_val = values["cardinality"]
95
+ "[#{cardinality_val['min']}..#{cardinality_val['max']}]"
96
+ else
97
+ ""
98
+ end
99
+ sync_puts("+#{key}: #{values['type']} #{cardinality}", 4)
100
+ end
101
+ sync_puts("}", 2)
102
+
103
+ # Associations notations
104
+ import["relations"]&.each do |values|
105
+ process_association(import_name, values, encountered_relations)
106
+ end
107
+ end
108
+ sync_puts("}")
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: UTF-8
3
+ # frozen_string_literal: true
3
4
 
4
5
  # resolve bin path, ignoring symlinks
5
6
  require "pathname"
@@ -15,6 +16,6 @@ class Gem::Specification
15
16
  def this; self; end
16
17
  end
17
18
 
18
- # start up the CLI
19
- require "reeper"
20
- Reeper::Cli.start(ARGV)
19
+ require "lutaml/uml/interface/command_line"
20
+
21
+ Lutaml::Uml::Interface::CommandLine.run
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ class Engine
5
+ attr_accessor :input
6
+
7
+ def initialize(input:)
8
+ @input = input
9
+ end
10
+
11
+ def render(_type)
12
+ raise ArgumentError, "Implement render method"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-graphviz"
4
+ require "lutaml/layout/engine"
5
+
6
+ module Lutaml
7
+ module Layout
8
+ class GraphVizEngine < Engine
9
+ def render(type)
10
+ GraphViz
11
+ .parse_string(input)
12
+ .output(type => String)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "lutaml/uml/version"
4
+ require "lutaml/uml/interface/command_line"
2
5
 
3
6
  module Lutaml
4
7
  module Uml
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  ## Behaviour metamodel
3
5
  ##
4
- module Lutaml::Uml
5
-
6
- class Abstraction < Dependency
7
- end
8
-
6
+ module Lutaml
7
+ module Uml
8
+ class Abstraction < Dependency
9
+ end
10
+ end
9
11
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  ## Behaviour metamodel
3
5
  ##
4
- module Lutaml::Uml
5
-
6
- class Activity < Behavior
6
+ module Lutaml
7
+ module Uml
8
+ class Activity < Behavior
9
+ end
10
+ end
7
11
  end
8
-
9
- end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  ## Behaviour metamodel
3
5
  ##
4
6
 
5
- module Lutaml::Uml
6
-
7
- class Actor < Classifier
8
- def initialize
9
- @name = nil
10
- @xmi_id = nil
11
- @stereotype = []
12
- @generalization = []
13
- @namespace = nil
14
- end
7
+ module Lutaml
8
+ module Uml
9
+ class Actor < Classifier
10
+ def initialize
11
+ @name = nil
12
+ @xmi_id = nil
13
+ @stereotype = []
14
+ @generalization = []
15
+ @namespace = nil
16
+ end
17
+ end
18
+ end
15
19
  end
16
-
17
- end
@@ -1,15 +1,41 @@
1
- module Lutaml::Uml
2
-
3
- class Association < TopElement
4
- attr_accessor :owned_end, :member_end
5
- def initialize
6
- @name = nil
7
- @xmi_id = nil
8
- @xmi_uuid = nil
9
- @owned_end = []
10
- @member_end = []
11
- @namespace = nil
12
- end
13
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Uml
5
+ class Association < TopElement
6
+ include HasMembers
7
+
8
+ attr_accessor :owner_end,
9
+ :owner_end_attribute_name,
10
+ :owner_end_cardinality,
11
+ :owner_end_type,
12
+ :member_end,
13
+ :member_end_attribute_name,
14
+ :member_end_cardinality,
15
+ :member_end_type,
16
+ :static,
17
+ :action
14
18
 
15
- end
19
+ # TODO: move to Parslet::Transform
20
+ def members=(value)
21
+ value.group_by { |member| member.keys.first }
22
+ .each do |(type, group)|
23
+ if %w[owner_end member_end].include?(type)
24
+ group.each do |member|
25
+ member.each_pair do |key, member_value|
26
+ public_send("#{associtaion_type(key)}=", member_value)
27
+ end
28
+ end
29
+ next
30
+ end
31
+ attribute_value = group.map(&:values).flatten
32
+ if attribute_value.length == 1 && !attribute_value.first.is_a?(Hash)
33
+ next public_send("#{associtaion_type(type)}=", attribute_value.first)
34
+ end
35
+
36
+ public_send("#{associtaion_type(type)}=", attribute_value)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  ## Behaviour metamodel
3
5
  ##
4
- module Lutaml::Uml
5
-
6
- class Behavior < Class
6
+ module Lutaml
7
+ module Uml
8
+ class Behavior < Class
9
+ end
10
+ end
7
11
  end
8
-
9
- end
@@ -1,17 +1,57 @@
1
- module Lutaml::Uml
2
-
3
- class Class < Classifier
4
- attr_accessor :nested_classifier, :is_abstract
5
- def initialize
6
- @name = nil
7
- @xmi_id = nil
8
- @xmi_uuid = nil
9
- @nested_classifier = []
10
- @stereotype = []
11
- @generalization = []
12
- @namespace = nil
13
- @is_abstract = false
14
- end
15
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/uml/has_members"
4
+ require "lutaml/uml/classifier"
5
+ require "lutaml/uml/association"
6
+ require "lutaml/uml/top_element_attribute"
7
+
8
+ module Lutaml
9
+ module Uml
10
+ class Class < Classifier
11
+ include HasMembers
12
+
13
+ attr_accessor :nested_classifier,
14
+ :is_abstract,
15
+ :type
16
+
17
+ attr_reader :associations,
18
+ :attributes,
19
+ :members,
20
+ :modifier
21
+
22
+ def initialize(attributes = {})
23
+ @nested_classifier = []
24
+ @stereotype = []
25
+ @generalization = []
26
+ @is_abstract = false
27
+ super
28
+ end
16
29
 
17
- end
30
+ def modifier=(value)
31
+ @modifier = value.to_s # TODO: Validate?
32
+ end
33
+
34
+ def attributes=(value)
35
+ @attributes = value.to_a.map do |attr|
36
+ TopElementAttribute.new(attr)
37
+ end
38
+ end
39
+
40
+ def associations=(value)
41
+ @associations = value.to_a.map do |attr|
42
+ Association.new(attr.to_h.merge(owner_end: name))
43
+ end
44
+ end
45
+
46
+ def methods
47
+ # @members&.select { |member| member.class == Method }
48
+ []
49
+ end
50
+
51
+ def relationships
52
+ # @members&.select { |member| member.class == ClassRelationship }
53
+ []
54
+ end
55
+ end
56
+ end
57
+ end