lutaml-uml 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 454f50ab7c670130123b6ce888ca7f9dbeae245a37a4c2e74e07529a47146f57
4
- data.tar.gz: 4d7ce781403a3c71733a13d02e81f82aa81c1650330ff14b924603bebf70d83d
3
+ metadata.gz: 79a4d0228330313679cd5545dd940cc978334821a8a8c3b37686cbba9e6b2bf0
4
+ data.tar.gz: 6c835a1f42bfa3b9d961c8924e020aaf0c41c8361c47032639db6dbc4349f1f8
5
5
  SHA512:
6
- metadata.gz: c4697e963d15d4a170d63f8ff8f4ac9e4589ee60178883fd48de1fa152912aafce6898fd264e12ce75bfc975fadcada13ed83c00ca5865b68b0f8e3cb2427834
7
- data.tar.gz: 33e09ace7d6f3a1f800ff0dc2e3d7977d20371166f9959e4f03f96737eb722540bec9ca2e2fa5f310bcc6a5989d3520f95441425e529325aa18a821ea00936fe
6
+ metadata.gz: f219cfc72ffb715c66ff37a2d5f4b565c959ecde36ed9c1d872ef02a80113c2b8b4d0eb6dc8891f886ab5dc48a0cccb1e4ba54a0b16b5a2eb33634e05814b7fa
7
+ data.tar.gz: 258fb342974bdbcbd9f212bdfe329c5710784d43c10531b171384ea510ebb84ac2b39a165d5b572023c9517402594d790d818102de96f07715cce7e00e0f8343
@@ -36,9 +36,16 @@ jobs:
36
36
  gem install bundler
37
37
  bundle config --local path vendor/bundle
38
38
  bundle install --jobs 4 --retry 3
39
- - name: Install Grpahviz Windows
39
+ - name: Install graphviz
40
+ uses: nick-invision/retry@v1
41
+ with:
42
+ polling_interval_seconds: 5
43
+ timeout_minutes: 5
44
+ max_attempts: 3
45
+ command: choco install --no-progress graphviz --version 2.38.0.20190211
46
+ - name: Check dot command
40
47
  run: |
41
- cinst -y graphviz
48
+ dot -?
42
49
  - name: Run specs
43
50
  run: |
44
51
  bundle exec rake
@@ -110,6 +110,20 @@ class Relationship {
110
110
  class Element {}
111
111
  ----
112
112
 
113
+ == Class' multiline "definition" property
114
+
115
+ === Definition
116
+
117
+ Full syntax:
118
+
119
+ [source,java]
120
+ ----
121
+ definition
122
+ inner text
123
+ end definition
124
+ ----
125
+
126
+
113
127
  == Attributes/entries
114
128
 
115
129
  === Definition
@@ -118,7 +132,7 @@ Full syntax:
118
132
 
119
133
  [source,java]
120
134
  ----
121
- [visibility][/][attribute] name [:type][multiplicity][=initial value][{property string}]
135
+ [visibility][/][attribute] name [:type][multiplicity][=initial value][{attribute body}]
122
136
  ----
123
137
 
124
138
  where:
@@ -128,11 +142,7 @@ where:
128
142
  * `/` - symbolizes a derived attribute.
129
143
  * `multiplicity` - Multiplicity is in square brackets (e.g. [1..*]).
130
144
  * `initial value` - Default value specifies the initial value of the attribute.
131
- * `property string` - Property string indicates a modifier that applies to the attribute:
132
- ** {readonly}: the property can be read but not changed.
133
- ** {union}: the property is a union of subsets.
134
- ** {subsets <property>}: the property is a subset of <property>.
135
- ** {redefines <property>}: the property is a new definition of <property> (overwritten by inheritance).
145
+ * `{attribute body}` - Body of attribute, additional properties for attribute
136
146
 
137
147
 
138
148
  One can use explicit or implicit syntax for attribute definition
@@ -186,6 +196,21 @@ class Figure {
186
196
  }
187
197
  ----
188
198
 
199
+ === Additional attribute' properties
200
+
201
+ example:
202
+
203
+ [source,java]
204
+ ----
205
+ class Figure {
206
+ + radius {
207
+ definition
208
+ Radius of the Figure
209
+ end definition
210
+ }
211
+ }
212
+ ----
213
+
189
214
  == Methods
190
215
 
191
216
  Syntax for defining methods:
@@ -6,7 +6,7 @@
6
6
  # Usage: bin/plantuml2lutaml /path/to/plantuml.wsd
7
7
 
8
8
  file_path = ARGV[0]
9
- FILE_NAME = File.basename(file_path, '.wsd')
9
+ FILE_NAME = File.basename(file_path, ".wsd")
10
10
  wsd_file = File.new(ARGV[0])
11
11
 
12
12
  def sync_puts(line, level = 0)
@@ -18,36 +18,36 @@ SKIPPED_LINES_REGEXP = /^(@startuml|'\*{7}|note|@enduml|\!|'\/)/
18
18
  COMMENT_START = /\/'/
19
19
  COMMENT_END = /'\//
20
20
  ASSOCIATION_MAPPINGS = {
21
- /-\|>/ => ',inheritance',
22
- /<\|-/ => 'inheritance,',
23
- /->/ => ',direct',
24
- /<-/ => 'direct,'
25
- }
21
+ /-\|>/ => ",inheritance",
22
+ /<\|-/ => "inheritance,",
23
+ /->/ => ",direct",
24
+ /<-/ => "direct,",
25
+ }.freeze
26
26
 
27
27
  in_comment_block = false
28
28
 
29
29
  def transform_line(line)
30
30
  return sync_puts(line, 2) if ASSOCIATION_MAPPINGS.keys.none? { |key| line =~ key }
31
31
 
32
- owner_type, member_type = ASSOCIATION_MAPPINGS.find { |(key,value)| line =~ key }.last.split(',')
33
- blocks = line.split(' ')
32
+ owner_type, member_type = ASSOCIATION_MAPPINGS.detect { |(key, _value)| line =~ key }.last.split(",")
33
+ blocks = line.split(" ")
34
34
  owner = blocks.first
35
35
  member = blocks.last
36
36
  sync_puts("association {", 2)
37
37
  sync_puts("owner #{owner}", 4)
38
38
  sync_puts("member #{member}", 4)
39
- sync_puts("owner_type #{owner_type}", 4) if owner_type.to_s.length > 0
40
- sync_puts("member_type #{member_type}", 4) if member_type.to_s.length > 0
39
+ sync_puts("owner_type #{owner_type}", 4) if !owner_type.to_s.empty?
40
+ sync_puts("member_type #{member_type}", 4) if !member_type.to_s.empty?
41
41
  sync_puts("}", 2)
42
42
  end
43
43
 
44
44
  sync_puts("diagram #{FILE_NAME} {")
45
45
  wsd_file.readlines.each do |line|
46
- if line =~ COMMENT_START
46
+ if line.match?(COMMENT_START)
47
47
  in_comment_block = true
48
48
  end
49
49
 
50
- if line =~ COMMENT_END
50
+ if line.match?(COMMENT_END)
51
51
  in_comment_block = false
52
52
  end
53
53
 
@@ -55,4 +55,4 @@ wsd_file.readlines.each do |line|
55
55
 
56
56
  transform_line(line)
57
57
  end
58
- sync_puts("}")
58
+ sync_puts("}")
@@ -75,6 +75,7 @@ def process_association(owner, values, encountered_relations)
75
75
  end
76
76
  sync_puts("diagram #{File.basename(ARGV[0], 'yml')[0..-2]} {")
77
77
  sync_puts("title '#{view_yaml['title']}'", 2)
78
+ sync_puts("caption '#{view_yaml['caption']}'", 2)
78
79
 
79
80
  # Class associations notations
80
81
  view_yaml["relations"]&.each do |values|
@@ -83,20 +84,55 @@ end
83
84
 
84
85
  view_yaml["imports"].keys.each do |entry|
85
86
  import = YAML.safe_load(File.read(File.join(models_path, "#{entry}.yml")))
86
- import_name = import["name"] || File.basename(entry)
87
+ import_name = import["name"] || File.basename(entry)
87
88
  # Class notation
88
89
  sync_puts("#{import['modelType']} #{import_name} {", 2)
90
+ if import["definition"]
91
+ definition = <<~TEXT
92
+ definition
93
+ #{import['definition']}
94
+ end definition
95
+ TEXT
96
+ sync_puts(definition, 4)
97
+ end
89
98
  import["values"]&.each_pair do |key, values|
90
- sync_puts("#{key}", 4)
99
+ result_string = key
100
+ if values["definition"]
101
+ result_string += <<~TEXT
102
+ {
103
+ definition
104
+ #{values['definition']}
105
+ end definition
106
+ }
107
+ TEXT
108
+ end
109
+ sync_puts(result_string, 4)
91
110
  end
92
111
  import["attributes"]&.each_pair do |key, values|
112
+ definition = values["definition"]
93
113
  cardinality = if values["cardinality"]
94
114
  cardinality_val = values["cardinality"]
95
115
  "[#{cardinality_val['min']}..#{cardinality_val['max']}]"
96
116
  else
97
117
  ""
98
118
  end
99
- sync_puts("+#{key}: #{values['type']} #{cardinality}", 4)
119
+ result_string = "+#{key}"
120
+ if values["type"]
121
+ result_string += ": #{values['type']}"
122
+ end
123
+ if cardinality
124
+ result_string += " #{cardinality}"
125
+ end
126
+ if definition
127
+ result_string += <<~TEXT
128
+ {
129
+ definition
130
+ #{definition}
131
+ end definition
132
+ }
133
+ TEXT
134
+ end
135
+ sync_puts(result_string, 4)
100
136
  end
101
137
  sync_puts("}", 2)
102
138
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "lutaml/uml/version"
4
4
  require "lutaml/uml/interface/command_line"
5
+ require "lutaml/uml/lutaml_path/document_wrapper"
5
6
 
6
7
  module Lutaml
7
8
  module Uml
@@ -16,6 +16,7 @@ module Lutaml
16
16
 
17
17
  attr_reader :associations,
18
18
  :attributes,
19
+ :definition,
19
20
  :members,
20
21
  :modifier
21
22
 
@@ -31,6 +32,10 @@ module Lutaml
31
32
  @modifier = value.to_s # TODO: Validate?
32
33
  end
33
34
 
35
+ def definition=(value)
36
+ @definition = value.to_s
37
+ end
38
+
34
39
  def attributes=(value)
35
40
  @attributes = value.to_a.map do |attr|
36
41
  TopElementAttribute.new(attr)
@@ -3,8 +3,11 @@
3
3
  module Lutaml
4
4
  module Uml
5
5
  class DataType < Class
6
- def keyword
7
- "dataType"
6
+ attr_reader :keyword
7
+
8
+ def initialize(attributes = {})
9
+ super
10
+ @keyword = "dataType"
8
11
  end
9
12
  end
10
13
  end
@@ -12,7 +12,14 @@ module Lutaml
12
12
 
13
13
  attr_reader :attributes,
14
14
  :members,
15
- :modifier
15
+ :modifier,
16
+ :definition,
17
+ :keyword
18
+
19
+ def initialize(attributes = {})
20
+ super
21
+ @keyword = "enumeration"
22
+ end
16
23
 
17
24
  def attributes=(value)
18
25
  @attributes = value.to_a.map do |attr|
@@ -20,14 +27,14 @@ module Lutaml
20
27
  end
21
28
  end
22
29
 
30
+ def definition=(value)
31
+ @definition = value.to_s
32
+ end
33
+
23
34
  # TODO: reserved name, change
24
35
  def methods
25
36
  []
26
37
  end
27
-
28
- def keyword
29
- "enumeration"
30
- end
31
38
  end
32
39
  end
33
40
  end
@@ -0,0 +1,15 @@
1
+ require "lutaml/lutaml_path/document_wrapper"
2
+
3
+ module Lutaml
4
+ module Uml
5
+ module LutamlPath
6
+ class DocumentWrapper < ::Lutaml::LutamlPath::DocumentWrapper
7
+ protected
8
+
9
+ def serialize_document(document)
10
+ serialize_to_hash(document)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -53,6 +53,7 @@ module Lutaml
53
53
  realizes
54
54
  static
55
55
  title
56
+ caption
56
57
  ].freeze
57
58
 
58
59
  KEYWORDS.each do |keyword|
@@ -132,7 +133,8 @@ module Lutaml
132
133
  attribute_name >>
133
134
  match['"\''].maybe >>
134
135
  attribute_type? >>
135
- cardinality?)
136
+ cardinality? >>
137
+ class_body?)
136
138
  .as(:attributes)
137
139
  end
138
140
 
@@ -143,6 +145,13 @@ module Lutaml
143
145
  match['"\''].maybe
144
146
  end
145
147
  rule(:title_definition) { title_keyword >> title_text }
148
+ rule(:caption_keyword) { kw_caption >> spaces }
149
+ rule(:caption_text) do
150
+ match['"\''].maybe >>
151
+ match['a-zA-Z0-9_\- '].repeat(1).as(:caption) >>
152
+ match['"\''].maybe
153
+ end
154
+ rule(:caption_definition) { caption_keyword >> caption_text }
146
155
 
147
156
  rule(:fontname_keyword) { kw_fontname >> spaces }
148
157
  rule(:fontname_text) do
@@ -252,7 +261,8 @@ module Lutaml
252
261
  end
253
262
  rule(:class_keyword) { kw_class >> spaces }
254
263
  rule(:class_inner_definitions) do
255
- attribute_definition |
264
+ definition_body |
265
+ attribute_definition |
256
266
  comment_definition |
257
267
  comment_multiline_definition
258
268
  end
@@ -276,10 +286,21 @@ module Lutaml
276
286
  class_body?
277
287
  end
278
288
 
289
+ # -- Definition
290
+ rule(:definition_body) do
291
+ spaces? >>
292
+ str("definition") >>
293
+ whitespace? >>
294
+ (str("end definition").absent? >> any).repeat.as(:definition) >>
295
+ whitespace? >>
296
+ str("end definition")
297
+ end
298
+
279
299
  # -- Enum
280
300
  rule(:enum_keyword) { kw_enum >> spaces }
281
301
  rule(:enum_inner_definitions) do
282
- attribute_definition |
302
+ definition_body |
303
+ attribute_definition |
283
304
  comment_definition |
284
305
  comment_multiline_definition
285
306
  end
@@ -339,6 +360,7 @@ module Lutaml
339
360
  rule(:diagram_keyword) { kw_diagram >> spaces? }
340
361
  rule(:diagram_inner_definitions) do
341
362
  title_definition |
363
+ caption_definition |
342
364
  fontname_definition |
343
365
  class_definition.as(:classes) |
344
366
  enum_definition.as(:enums) |
@@ -27,7 +27,7 @@ module Lutaml
27
27
  end
28
28
 
29
29
  def process_include_line(include_root, line)
30
- include_path_match = line.match(/\s*include\s+(.+)/)
30
+ include_path_match = line.match(/^\s*include\s+(.+)/)
31
31
  return line if include_path_match.nil?
32
32
 
33
33
  path_to_file = include_path_match[1].strip
@@ -3,8 +3,11 @@
3
3
  module Lutaml
4
4
  module Uml
5
5
  class PrimitiveType < DataType
6
- def keyword
7
- "primitive"
6
+ attr_reader :keyword
7
+
8
+ def initialize(attributes = {})
9
+ super
10
+ @keyword = "primitive"
8
11
  end
9
12
  end
10
13
  end
@@ -4,6 +4,7 @@ module Lutaml
4
4
  module Uml
5
5
  class TopElementAttribute
6
6
  include HasAttributes
7
+ include HasMembers
7
8
 
8
9
  attr_accessor :name,
9
10
  :visibility,
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Uml
5
- VERSION = "0.2.3"
5
+ VERSION = "0.2.4"
6
6
  end
7
7
  end
@@ -26,15 +26,16 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.add_runtime_dependency "activesupport", "~> 5.0"
28
28
  spec.add_runtime_dependency "hashie", "~> 4.1.0"
29
+ spec.add_runtime_dependency "lutaml", "~> 0.3.0"
29
30
  spec.add_runtime_dependency "parslet", "~> 1.7.1"
30
31
  spec.add_runtime_dependency "ruby-graphviz", "~> 1.2"
31
32
  spec.add_runtime_dependency "thor", "~> 1.0"
32
33
 
34
+ spec.add_development_dependency "bundler", "~> 2.0"
33
35
  spec.add_development_dependency "byebug"
34
36
  spec.add_development_dependency "nokogiri", "~> 1.10"
35
- spec.add_development_dependency "rubocop", "~> 0.54.0"
36
- spec.add_development_dependency "bundler", "~> 2.0"
37
37
  spec.add_development_dependency "pry", "~> 0.12.2"
38
38
  spec.add_development_dependency "rake", "~> 10.0"
39
39
  spec.add_development_dependency "rspec", "~> 3.0"
40
+ spec.add_development_dependency "rubocop", "~> 0.54.0"
40
41
  end
@@ -0,0 +1,20 @@
1
+ diagram MyView {
2
+ title "my diagram"
3
+
4
+ class AddressClassProfile {
5
+ definition
6
+ this is multiline with `ascidoc`
7
+ comments
8
+ and list
9
+ end definition
10
+ +addressClassProfile: CharacterString [0..1]
11
+ }
12
+
13
+ class AttributeProfile {
14
+ imlicistAttributeProfile: CharacterString [0..1] {
15
+ definition this is attribute definition
16
+ with multiply lines
17
+ end definition
18
+ }
19
+ }
20
+ }
@@ -248,5 +248,29 @@ RSpec.describe Lutaml::Uml::Parsers::Dsl do
248
248
 
249
249
  it_behaves_like "the correct graphviz formatting"
250
250
  end
251
+
252
+ context "when defninition directives included" do
253
+ let(:content) do
254
+ File.new(fixtures_path("dsl/diagram_definitions.lutaml"))
255
+ end
256
+ let(:class_definition) do
257
+ "this is multiline with `ascidoc`\n comments\n and list"
258
+ end
259
+ let(:attribute_definition) do
260
+ "this is attribute definition\n with multiply lines"
261
+ end
262
+
263
+ it "create comments for document and classes" do
264
+ expect(by_name(parse.classes, "AddressClassProfile").definition)
265
+ .to(eq(class_definition))
266
+ expect(by_name(parse.classes, "AttributeProfile")
267
+ .attributes
268
+ .first
269
+ .definition)
270
+ .to(eq(attribute_definition))
271
+ end
272
+
273
+ it_behaves_like "the correct graphviz formatting"
274
+ end
251
275
  end
252
276
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-uml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-21 00:00:00.000000000 Z
11
+ date: 2020-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 4.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: lutaml
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.3.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.3.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: parslet
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -81,61 +95,47 @@ dependencies:
81
95
  - !ruby/object:Gem::Version
82
96
  version: '1.0'
83
97
  - !ruby/object:Gem::Dependency
84
- name: byebug
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: nokogiri
98
+ name: bundler
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.10'
103
+ version: '2.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '1.10'
110
+ version: '2.0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rubocop
112
+ name: byebug
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: 0.54.0
117
+ version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 0.54.0
124
+ version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: bundler
126
+ name: nokogiri
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '2.0'
131
+ version: '1.10'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '2.0'
138
+ version: '1.10'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: pry
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
180
  version: '3.0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rubocop
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 0.54.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 0.54.0
181
195
  description: UML model module for LutaML.
182
196
  email:
183
197
  - open.source@ribose.com'
@@ -230,6 +244,7 @@ files:
230
244
  - lib/lutaml/uml/instance.rb
231
245
  - lib/lutaml/uml/interface/base.rb
232
246
  - lib/lutaml/uml/interface/command_line.rb
247
+ - lib/lutaml/uml/lutaml_path/document_wrapper.rb
233
248
  - lib/lutaml/uml/model.rb
234
249
  - lib/lutaml/uml/node/base.rb
235
250
  - lib/lutaml/uml/node/class_node.rb
@@ -297,6 +312,7 @@ files:
297
312
  - spec/fixtures/dsl/diagram_comments.lutaml
298
313
  - spec/fixtures/dsl/diagram_concept_model.lutaml
299
314
  - spec/fixtures/dsl/diagram_data_types.lutaml
315
+ - spec/fixtures/dsl/diagram_definitions.lutaml
300
316
  - spec/fixtures/dsl/diagram_includes.lutaml
301
317
  - spec/fixtures/dsl/diagram_multiply_classes.lutaml
302
318
  - spec/fixtures/dsl/shared.lutaml