asciichem 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f9929cd67fc49ac37896dce9ebc173306615fb08b704fd96ddfa14c09189afd
4
- data.tar.gz: dc7bc12b0914610807bdd168f18b2e4b1e281519bbd5698a5c7e08d660b49d83
3
+ metadata.gz: f025579767518b2551359a0817e2019c19bec299f0a7c77c16264dd98342df25
4
+ data.tar.gz: c092bfffa44620c0bb2ef20abdba849732eaaaa01ae2f0039bf8c22a4d57baad
5
5
  SHA512:
6
- metadata.gz: 13f7ec97ce27c022cfac8e9df9944ae9860c949d8bb8569995b113f846a4fb5a0052bf0d6def2374fcaa11b140187d5c38c73e8afb66b0ca77ff3f558f1a994a
7
- data.tar.gz: 161b22b36e6eaeb599b7bbae7666c45574d2a17b4abf5127cdbc4fe9e3c8a558b8e8de00d0149c45a58bf4c062368fb79526ef70cdd9f10ad50a6d6cdd169982
6
+ metadata.gz: 63957c098bb2df1785ce770d6e375c1f54c771e847f01f7de5b03cfd88a4321cf9c6abd6d93c5a5b6f43b1239887f1da80ec48d46d62351071ab25632bfd766f
7
+ data.tar.gz: 82f5b7dda4a1f9461e5fe68dfc8566328ab2a4541101b33605582620be59651b61f358a7053e3361b5022587d3dc83be4ad1039615673076a492167025321fa0
data/asciichem.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ["lib"]
32
32
 
33
- spec.add_dependency "chemicalml", "0.2.0"
33
+ spec.add_dependency "chemicalml", "~> 0.2.1"
34
34
  spec.add_dependency "elkrb", "~> 1.0"
35
35
  spec.add_dependency "nokogiri", "~> 1.16"
36
36
  spec.add_dependency "parslet", "~> 2.0"
@@ -158,7 +158,7 @@ module AsciiChem
158
158
  # then reaction reactants+products, then cascade reactions.
159
159
  def self.flatten_canonical_atoms(canonical_doc)
160
160
  atoms = []
161
- canonical_doc.molecules.each { |m| atoms.concat(m.atoms) }
161
+ canonical_doc.molecules.each { |m| atoms.concat((m.atom_array&.atoms || [])) }
162
162
  canonical_doc.reactions.each do |reaction|
163
163
  atoms.concat(flatten_reaction_atoms(reaction))
164
164
  end
@@ -172,8 +172,8 @@ module AsciiChem
172
172
  atoms = []
173
173
  reactants = reaction.reactant_list
174
174
  products = reaction.product_list
175
- reactants&.reactants&.each { |r| atoms.concat(r.substance.molecule.atoms) }
176
- products&.products&.each { |p| atoms.concat(p.substance.molecule.atoms) }
175
+ reactants&.reactants&.each { |r| atoms.concat(r.substance.molecule.atom_array&.atoms || []) }
176
+ products&.products&.each { |p| atoms.concat(p.substance.molecule.atom_array&.atoms || []) }
177
177
  atoms
178
178
  end
179
179
  private_class_method :flatten_reaction_atoms
@@ -4,62 +4,74 @@ require "chemicalml"
4
4
 
5
5
  module AsciiChem
6
6
  module Cml
7
- # Thin composition of the AsciiChem <-> canonical adapter
8
- # (`AsciiChem::ModelAdapter`) and the canonical <-> CML adapter
9
- # (`Chemicalml::Cml::Translator`). Owns no chemistry logic just
10
- # wiring, the schema-registration dance that chemicalml requires
11
- # on first use, and the aci: extension namespace side-channel
12
- # that carries AsciiChem-specific fields through CML round-trip.
7
+ # Thin adapter between AsciiChem::Model and Chemicalml::Cml wire
8
+ # classes. chemicalml 0.2.1+ merged the canonical Model into the
9
+ # wire classes Schema3::Atom, Schema3::Molecule, etc. handle both
10
+ # serialization and semantics. This class:
11
+ #
12
+ # 1. Builds a Chemicalml::Cml::Document from AsciiChem::Model::Formula
13
+ # 2. Serializes to XML (optionally enriching with aci: extensions)
14
+ # 3. Parses CML XML back into AsciiChem::Model::Formula
15
+ #
16
+ # The aci: extension namespace (oxidation state, Lewis markers, ring
17
+ # closures, groups, electron config, math, text, metadata) is handled
18
+ # by post-processing the XML via Extensions and GroupExtensions.
13
19
  class Translator
14
20
  class << self
15
- # AsciiChem::Model::Formula -> CML XML string.
16
21
  def from_asciichem(formula)
17
22
  ensure_schema_registered!
18
23
  translation = AsciiChem::ModelAdapter.to_canonical_with_mapping(formula)
19
- wire_doc = Chemicalml::Cml::Translator.from_canonical(translation.document)
20
- xml = wire_doc.to_xml
24
+ xml = translation.document.to_xml
21
25
  xml = inject_atom_extensions(xml, translation.atom_mapping)
22
- xml = inject_group_extensions(xml, translation.groups)
23
- inject_top_level_extensions(xml, formula)
26
+ inject_molecule_extensions(xml, formula, translation)
24
27
  end
25
28
 
26
- # CML XML string -> AsciiChem::Model::Formula.
27
29
  def to_asciichem(xml)
28
30
  ensure_schema_registered!
29
31
  top_level = Extensions.extract_top_level(xml)
30
32
  atom_extensions = Extensions.extract(xml)
31
33
  group_extensions = GroupExtensions.extract(xml)
32
34
  wire_doc = Chemicalml::Cml::Document.from_xml(xml)
33
- canonical = Chemicalml::Cml::Translator.to_canonical(wire_doc)
34
- formula = AsciiChem::ModelAdapter.from_canonical(canonical)
35
- Extensions.restore(formula, canonical, atom_extensions)
36
- GroupExtensions.restore(formula, canonical, group_extensions)
35
+ formula = AsciiChem::ModelAdapter.from_canonical(wire_doc)
36
+ Extensions.restore(formula, wire_doc, atom_extensions)
37
+ GroupExtensions.restore(formula, wire_doc, group_extensions)
37
38
  Extensions.restore_top_level(formula, top_level)
38
39
  formula
39
40
  end
40
41
 
41
42
  private
42
43
 
44
+ def build_wire_document(document)
45
+ molecules = document.molecules.map { |m| m }
46
+ reactions = document.reactions.map { |r| r }
47
+ reaction_lists = document.reaction_lists.map { |l| l }
48
+ Chemicalml::Cml::Document.new(
49
+ molecules: molecules,
50
+ reactions: reactions,
51
+ reaction_lists: reaction_lists
52
+ )
53
+ end
54
+
43
55
  def inject_atom_extensions(xml, atom_mapping)
44
56
  extensions = Extensions.collect(atom_mapping)
45
57
  Extensions.inject(xml, extensions)
46
58
  end
47
59
 
48
- def inject_group_extensions(xml, groups_by_molecule)
49
- collected = GroupExtensions.collect(groups_by_molecule)
50
- GroupExtensions.inject(xml, collected)
60
+ def inject_molecule_extensions(xml, formula, translation)
61
+ xml = inject_groups(xml, formula, translation)
62
+ inject_top_level(xml, formula)
63
+ end
64
+
65
+ def inject_groups(xml, formula, translation)
66
+ groups = translation.respond_to?(:groups) ? translation.groups : {}
67
+ GroupExtensions.inject(xml, GroupExtensions.collect(groups))
51
68
  end
52
69
 
53
- def inject_top_level_extensions(xml, formula)
70
+ def inject_top_level(xml, formula)
54
71
  top_level = Extensions.collect_top_level(formula)
55
72
  Extensions.inject_top_level(xml, top_level)
56
73
  end
57
74
 
58
- # chemicalml registers wire classes into a lutaml-model
59
- # TypeRegistry on first use. The registry call is idempotent
60
- # (guarded by `@models_registered`) but must run before any
61
- # `from_xml` so element types like `molecule` and `atom` are
62
- # resolvable.
63
75
  def ensure_schema_registered!
64
76
  Chemicalml::Cml::Schema3.ensure_registered!
65
77
  end
@@ -10,18 +10,18 @@ module AsciiChem
10
10
  #
11
11
  # Mapping rules:
12
12
  #
13
- # - `Chemicalml::Model::Document` -> `Formula`.
14
- # - `Chemicalml::Model::Molecule` -> `Molecule`. Atoms become
13
+ # - `Chemicalml::Cml::Document` -> `Formula`.
14
+ # - `Chemicalml::Cml::Molecule` -> `Molecule`. Atoms become
15
15
  # AsciiChem atoms with
16
16
  # subscript=count. Bonds
17
17
  # re-insert between their
18
18
  # endpoint positions.
19
- # - `Chemicalml::Model::Atom` -> `Atom` (element, isotope,
19
+ # - `Chemicalml::Cml::Atom` -> `Atom` (element, isotope,
20
20
  # charge, lone pairs,
21
21
  # radical electrons).
22
- # - `Chemicalml::Model::Bond` -> `Bond` (kind enum).
23
- # - `Chemicalml::Model::Reaction` -> `Reaction`.
24
- # - `Chemicalml::Model::ReactionList` -> `ReactionCascade`.
22
+ # - `Chemicalml::Cml::Bond` -> `Bond` (kind enum).
23
+ # - `Chemicalml::Cml::Reaction` -> `Reaction`.
24
+ # - `Chemicalml::Cml::ReactionList` -> `ReactionCascade`.
25
25
  #
26
26
  # Round-trip note: the canonical model is richer than AsciiChem's
27
27
  # (3D coordinates, metadata, etc.). Those fields are dropped on the
@@ -113,7 +113,7 @@ module AsciiChem
113
113
 
114
114
  def extract_scalar_value(value)
115
115
  return nil if value.nil?
116
- return value.value if value.is_a?(Chemicalml::Model::Scalar)
116
+ return value.value if value.is_a?(Chemicalml::Cml::Scalar)
117
117
 
118
118
  value.to_s
119
119
  end
@@ -136,11 +136,21 @@ module AsciiChem
136
136
  AsciiChem::Model::Reaction.new(
137
137
  reactants: reactants_from_canonical(reaction.reactant_list),
138
138
  products: products_from_canonical(reaction.product_list),
139
- arrow: reaction.arrow,
139
+ arrow: arrow_from_wire(reaction),
140
140
  conditions: conditions_from_canonical(reaction)
141
141
  )
142
142
  end
143
143
 
144
+ def arrow_from_wire(reaction)
145
+ type = reaction.type || reaction.title
146
+ case type.to_s
147
+ when 'reverse' then :reverse
148
+ when 'equilibrium' then :equilibrium
149
+ when 'resonance' then :resonance
150
+ else :forward
151
+ end
152
+ end
153
+
144
154
  def reaction_list_from_canonical(list)
145
155
  AsciiChem::Model::ReactionCascade.new(
146
156
  steps: list.reactions.map { |r| reaction_from_canonical(r) }
@@ -159,12 +169,8 @@ module AsciiChem
159
169
  list.products.map { |p| molecule_from_canonical(p.substance.molecule) }
160
170
  end
161
171
 
162
- def conditions_from_canonical(reaction)
163
- above = reaction.conditions_above
164
- below = reaction.conditions_below
165
- return nil unless above || below
166
-
167
- AsciiChem::Model::Reaction::Conditions.new(above: above, below: below)
172
+ def conditions_from_canonical(_reaction)
173
+ nil
168
174
  end
169
175
 
170
176
  # Rebuilds an AsciiChem::Model::Molecule's node list from a
@@ -180,7 +186,7 @@ module AsciiChem
180
186
  def initialize(molecule)
181
187
  @molecule = molecule
182
188
  @position_by_atom_id = {}
183
- molecule.atoms.each_with_index do |atom, idx|
189
+ wire_atoms(molecule).each_with_index do |atom, idx|
184
190
  @position_by_atom_id[atom.id] = idx
185
191
  end
186
192
  @nodes = build_nodes
@@ -189,20 +195,26 @@ module AsciiChem
189
195
  private
190
196
 
191
197
  def build_nodes
192
- atoms = @molecule.atoms.map { |a| atom_from_canonical(a) }
193
- return atoms if @molecule.bonds.empty?
198
+ atoms = wire_atoms(@molecule).map { |a| atom_from_canonical(a) }
199
+ return atoms if wire_bonds(@molecule).empty?
194
200
 
195
201
  insert_bonds(atoms)
196
202
  end
197
203
 
204
+ def wire_atoms(molecule)
205
+ molecule.atom_array&.atoms || []
206
+ end
207
+
208
+ def wire_bonds(molecule)
209
+ molecule.bond_array&.bonds || []
210
+ end
211
+
198
212
  def atom_from_canonical(atom)
199
213
  AsciiChem::Model::Atom.new(
200
- element: atom.element,
214
+ element: atom.element_type,
201
215
  isotope: atom.isotope,
202
216
  subscript: subscript_from_count(atom.count),
203
217
  charge: atom.formal_charge,
204
- lone_pairs: atom.lone_pairs,
205
- radical_electrons: atom.radical_electrons,
206
218
  **extract_coordinates(atom)
207
219
  )
208
220
  end
@@ -230,14 +242,14 @@ module AsciiChem
230
242
  result = atoms.dup
231
243
  # Insert in descending position order so earlier insertions
232
244
  # don't shift the indices of pending ones.
233
- bonds_with_pos = @molecule.bonds.map { |b| [b, later_position(b)] }
245
+ bonds_with_pos = wire_bonds(@molecule).map { |b| [b, later_position(b)] }
234
246
  bonds_with_pos.sort_by { |(_, pos)| -pos }.each do |bond, pos|
235
247
  # Ring bonds connect non-adjacent atoms. They're represented
236
248
  # by the ring_closures digit carried via aci: extension on
237
249
  # the atoms, not as a positional bond in the node list.
238
250
  next if ring_bond?(bond)
239
251
 
240
- result.insert(pos, AsciiChem::Model::Bond.new(kind: bond.kind))
252
+ result.insert(pos, AsciiChem::Model::Bond.new(kind: bond_kind_from_order(bond.order)))
241
253
  end
242
254
  result
243
255
  end
@@ -245,7 +257,7 @@ module AsciiChem
245
257
  # Position of the later endpoint of the bond — i.e. where the
246
258
  # bond marker should sit in the rebuilt linear sequence.
247
259
  def later_position(bond)
248
- positions = bond.atom_refs.map { |id| @position_by_atom_id[id] }.compact
260
+ positions = bond.atom_refs2.to_s.split.map { |id| @position_by_atom_id[id] }.compact
249
261
  return 0 if positions.empty?
250
262
 
251
263
  positions.max
@@ -255,16 +267,26 @@ module AsciiChem
255
267
  # adjacent — its endpoints span a gap. Such bonds are
256
268
  # represented by ring_closures digits, not positional markers.
257
269
  def ring_bond?(bond)
258
- positions = bond.atom_refs.map { |id| @position_by_atom_id[id] }.compact
270
+ positions = bond.atom_refs2.to_s.split.map { |id| @position_by_atom_id[id] }.compact
259
271
  return false if positions.length < 2
260
272
 
261
273
  positions.max - positions.min > 1
262
274
  end
263
275
 
264
276
  def first_position(bond)
265
- positions = bond.atom_refs.map { |id| @position_by_atom_id[id] }.compact
277
+ positions = bond.atom_refs2.to_s.split.map { |id| @position_by_atom_id[id] }.compact
266
278
  positions.min || 0
267
279
  end
280
+
281
+ ORDER_TO_KIND = {
282
+ 'S' => :single, 'D' => :double, 'T' => :triple,
283
+ 'Q' => :quadruple, 'W' => :wedge, 'H' => :hash,
284
+ 'A' => :dative, 'V' => :wavy
285
+ }.freeze
286
+
287
+ def bond_kind_from_order(order)
288
+ ORDER_TO_KIND.fetch(order.to_s, :single)
289
+ end
268
290
  end
269
291
  private_constant :MoleculeRebuilder
270
292
  end
@@ -9,17 +9,17 @@ module AsciiChem
9
9
  #
10
10
  # Mapping rules:
11
11
  #
12
- # - `Formula` -> `Chemicalml::Model::Document`.
13
- # - `Molecule` -> `Chemicalml::Model::Molecule`. Inner atoms
12
+ # - `Formula` -> `Chemicalml::Cml::Document`.
13
+ # - `Molecule` -> `Chemicalml::Cml::Molecule`. Inner atoms
14
14
  # collect IDs; bonds reference consecutive
15
15
  # IDs. Groups flatten with their multiplicity
16
16
  # applied to each contained atom's count.
17
- # - `Atom` -> `Chemicalml::Model::Atom` (element,
17
+ # - `Atom` -> `Chemicalml::Cml::Atom` (element,
18
18
  # isotope, charge, count, lone pairs,
19
19
  # radical electrons).
20
- # - `Bond` -> `Chemicalml::Model::Bond` (kind, refs).
21
- # - `Reaction` -> `Chemicalml::Model::Reaction`.
22
- # - `ReactionCascade` -> `Chemicalml::Model::ReactionList`.
20
+ # - `Bond` -> `Chemicalml::Cml::Bond` (kind, refs).
21
+ # - `Reaction` -> `Chemicalml::Cml::Reaction`.
22
+ # - `ReactionCascade` -> `Chemicalml::Cml::ReactionList`.
23
23
  # - `ElectronConfiguration`, `EmbeddedMath`, `Text` -> skipped
24
24
  # (no canonical representation yet; a future extension can carry
25
25
  # them as namespaced metadata).
@@ -52,7 +52,7 @@ module AsciiChem
52
52
  reaction_lists << reaction_cascade_to_canonical(node)
53
53
  end
54
54
  end
55
- Chemicalml::Model::Document.new(
55
+ Chemicalml::Cml::Document.new(
56
56
  molecules: molecules,
57
57
  reactions: reactions,
58
58
  reaction_lists: reaction_lists
@@ -67,10 +67,10 @@ module AsciiChem
67
67
  walker = MoleculeWalker.new(@ids)
68
68
  atoms, bonds = walker.walk(molecule)
69
69
  @atom_mapping.merge!(walker.atom_mapping)
70
- canonical_molecule = Chemicalml::Model::Molecule.new(
70
+ canonical_molecule = Chemicalml::Cml::Molecule.new(
71
71
  id: @ids.next(:molecule),
72
- atoms: atoms,
73
- bonds: bonds,
72
+ atom_array: atoms.empty? ? nil : Chemicalml::Cml::AtomArray.new(atoms: atoms),
73
+ bond_array: bonds.empty? ? nil : Chemicalml::Cml::BondArray.new(bonds: bonds),
74
74
  count: molecule.coefficient,
75
75
  formal_charge: total_formal_charge(atoms),
76
76
  names: map_names(molecule.names),
@@ -88,7 +88,7 @@ module AsciiChem
88
88
  return [] if names.nil? || names.empty?
89
89
 
90
90
  names.map do |n|
91
- Chemicalml::Model::Name.new(
91
+ Chemicalml::Cml::Name.new(
92
92
  content: n.content,
93
93
  convention: n.convention,
94
94
  dict_ref: n.dict_ref
@@ -100,7 +100,7 @@ module AsciiChem
100
100
  return [] if identifiers.nil? || identifiers.empty?
101
101
 
102
102
  identifiers.map do |i|
103
- Chemicalml::Model::Identifier.new(
103
+ Chemicalml::Cml::Identifier.new(
104
104
  value: i.value,
105
105
  convention: i.convention,
106
106
  dict_ref: i.dict_ref
@@ -112,7 +112,7 @@ module AsciiChem
112
112
  return [] if formulas.nil? || formulas.empty?
113
113
 
114
114
  formulas.map do |f|
115
- Chemicalml::Model::Formula.new(
115
+ Chemicalml::Cml::Formula.new(
116
116
  concise: f[:concise],
117
117
  inline: f[:inline],
118
118
  formal_charge: f[:formal_charge],
@@ -128,7 +128,7 @@ module AsciiChem
128
128
  return [] if properties.nil? || properties.empty?
129
129
 
130
130
  properties.map do |p|
131
- Chemicalml::Model::Property.new(
131
+ Chemicalml::Cml::Property.new(
132
132
  title: p[:title],
133
133
  value: build_scalar(p[:value]),
134
134
  dict_ref: p[:dict_ref],
@@ -140,7 +140,7 @@ module AsciiChem
140
140
  def build_scalar(value)
141
141
  return nil if value.nil?
142
142
 
143
- Chemicalml::Model::Scalar.new(
143
+ Chemicalml::Cml::Scalar.new(
144
144
  value: value.to_s,
145
145
  dict_ref: nil
146
146
  )
@@ -150,7 +150,7 @@ module AsciiChem
150
150
  return [] if labels.nil? || labels.empty?
151
151
 
152
152
  labels.map do |l|
153
- Chemicalml::Model::Label.new(
153
+ Chemicalml::Cml::Label.new(
154
154
  value: l[:value],
155
155
  dict_ref: l[:dict_ref],
156
156
  convention: l[:convention]
@@ -180,7 +180,7 @@ module AsciiChem
180
180
  # -- Reactions --------------------------------------------------
181
181
 
182
182
  def reaction_to_canonical(reaction)
183
- Chemicalml::Model::Reaction.new(
183
+ Chemicalml::Cml::Reaction.new(
184
184
  id: @ids.next(:reaction),
185
185
  reactant_list: reactant_list_to_canonical(reaction.reactants),
186
186
  product_list: product_list_to_canonical(reaction.products),
@@ -193,26 +193,26 @@ module AsciiChem
193
193
  end
194
194
 
195
195
  def reaction_cascade_to_canonical(cascade)
196
- Chemicalml::Model::ReactionList.new(
196
+ Chemicalml::Cml::ReactionList.new(
197
197
  reactions: cascade.steps.map { |s| reaction_to_canonical(s) }
198
198
  )
199
199
  end
200
200
 
201
201
  def reactant_list_to_canonical(reactants)
202
- Chemicalml::Model::ReactantList.new(
202
+ Chemicalml::Cml::ReactantList.new(
203
203
  reactants: reactants.map { |m| participant_to_canonical(m, :reactant) }
204
204
  )
205
205
  end
206
206
 
207
207
  def product_list_to_canonical(products)
208
- Chemicalml::Model::ProductList.new(
208
+ Chemicalml::Cml::ProductList.new(
209
209
  products: products.map { |m| participant_to_canonical(m, :product) }
210
210
  )
211
211
  end
212
212
 
213
213
  def participant_to_canonical(molecule, role)
214
- Chemicalml::Model::Reactant.new(
215
- substance: Chemicalml::Model::Substance.new(
214
+ Chemicalml::Cml::Reactant.new(
215
+ substance: Chemicalml::Cml::Substance.new(
216
216
  molecule: molecule_to_canonical(molecule),
217
217
  role: role
218
218
  )
@@ -264,7 +264,7 @@ module AsciiChem
264
264
  # into canonical atom IDs. Skips pairs that already have a
265
265
  # positional bond between them (degenerate case like `C1-C1`).
266
266
  def emit_ring_bonds(molecule)
267
- existing_pair_keys = @bonds.map { |b| pair_key(b.atom_refs) }.to_set
267
+ existing_pair_keys = @bonds.map { |b| pair_key(b.atom_refs2.to_s.split) }.to_set
268
268
  AsciiChem::RingBonds.each_in(molecule) do |ring_bond|
269
269
  from_id = @atom_id_by_object_id[ring_bond.from_atom.object_id]
270
270
  to_id = @atom_id_by_object_id[ring_bond.to_atom.object_id]
@@ -273,10 +273,10 @@ module AsciiChem
273
273
  key = pair_key([from_id, to_id])
274
274
  next if existing_pair_keys.include?(key)
275
275
 
276
- @bonds << Chemicalml::Model::Bond.new(
276
+ @bonds << Chemicalml::Cml::Bond.new(
277
277
  id: @ids.next(:bond),
278
- atom_refs: [from_id, to_id],
279
- kind: :single
278
+ atom_refs2: "#{from_id} #{to_id}",
279
+ order: "S"
280
280
  )
281
281
  existing_pair_keys << key
282
282
  end
@@ -325,7 +325,7 @@ module AsciiChem
325
325
  @group_stack.each { |record| record.atom_ids << id }
326
326
  attrs = {
327
327
  id: id,
328
- element: atom.element,
328
+ element_type: atom.element,
329
329
  isotope: atom.isotope,
330
330
  formal_charge: atom.charge,
331
331
  count: effective_count(atom, multiplier),
@@ -333,17 +333,17 @@ module AsciiChem
333
333
  radical_electrons: atom.radical_electrons
334
334
  }
335
335
  merge_coordinates(attrs, atom)
336
- @atoms << Chemicalml::Model::Atom.new(**attrs)
336
+ @atoms << Chemicalml::Cml::Atom.new(**attrs)
337
337
  emit_pending_bond(id) if @pending_bond_kind && @last_atom_id
338
338
  @last_atom_id = id
339
339
  @pending_bond_kind = nil
340
340
  end
341
341
 
342
342
  def emit_pending_bond(next_atom_id)
343
- @bonds << Chemicalml::Model::Bond.new(
343
+ @bonds << Chemicalml::Cml::Bond.new(
344
344
  id: @ids.next(:bond),
345
- atom_refs: [@last_atom_id, next_atom_id],
346
- kind: @pending_bond_kind,
345
+ atom_refs2: "#{@last_atom_id} #{next_atom_id}",
346
+ order: BOND_ORDER_CODES.fetch(@pending_bond_kind, "S"),
347
347
  bond_stereo: bond_stereo_for(@pending_bond_kind)
348
348
  )
349
349
  end
@@ -351,13 +351,16 @@ module AsciiChem
351
351
  # CML bondStereo codes for stereo bonds. Wedge (coming out of
352
352
  # page) → "W"; hash (going into page) → "H". Other bond kinds
353
353
  # have no stereo meaning.
354
+ BOND_ORDER_CODES = { single: "S", double: "D", triple: "T",
355
+ quadruple: "Q", wedge: "W", hash: "H",
356
+ dative: "A", wavy: "V" }.freeze
354
357
  BOND_STEREO_CODES = { wedge: "W", hash: "H" }.freeze
355
358
 
356
359
  def bond_stereo_for(kind)
357
360
  code = BOND_STEREO_CODES[kind]
358
361
  return nil unless code
359
362
 
360
- Chemicalml::Model::BondStereo.new(value: code)
363
+ Chemicalml::Cml::BondStereo.new(value: code)
361
364
  end
362
365
 
363
366
  def effective_count(atom, multiplier)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AsciiChem
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciichem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -13,16 +13,16 @@ dependencies:
13
13
  name: chemicalml
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - '='
16
+ - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.2.0
18
+ version: 0.2.1
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - '='
23
+ - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 0.2.0
25
+ version: 0.2.1
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: elkrb
28
28
  requirement: !ruby/object:Gem::Requirement