rubabel 0.2.1 → 0.2.2
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.
- data/README.md +11 -1
- data/VERSION +1 -1
- data/bin/fragmenter.rb +40 -16
- data/lib/rubabel/atom.rb +14 -1
- data/lib/rubabel/bond.rb +25 -1
- data/lib/rubabel/molecule.rb +7 -1
- data/lib/rubabel/molecule/fragmentable.rb +60 -247
- data/spec/rubabel/molecule/fragmentable_spec.rb +174 -216
- data/spec/rubabel/molecule_spec.rb +12 -0
- metadata +2 -2
data/README.md
CHANGED
@@ -120,7 +120,7 @@ Have some bonds to break?, split makes new molecules split from that bond(s)
|
|
120
120
|
bonds = mol.matches("CO").map {|c, o| c.get_bond(o) }
|
121
121
|
mol.split(*bonds) # splits between every carbon single bonded to oxygen
|
122
122
|
|
123
|
-
### Add
|
123
|
+
### Add, delete, modify atoms/bonds
|
124
124
|
|
125
125
|
#### Adding
|
126
126
|
|
@@ -147,6 +147,16 @@ Have some bonds to break?, split makes new molecules split from that bond(s)
|
|
147
147
|
bond = mol[0].get_bond(mol[1])
|
148
148
|
mol.delete(bond) # -> #<Mol C.O>
|
149
149
|
|
150
|
+
#### Modifying
|
151
|
+
|
152
|
+
Can add or subtract from bonds to change bond order:
|
153
|
+
|
154
|
+
mol = Rubabel["CC"]
|
155
|
+
mol[0].get_bond(mol[1]) + 1 # now it is a double bond
|
156
|
+
bond = mol[0].bonds.first
|
157
|
+
bond - 1
|
158
|
+
bond.bond_order # => 1
|
159
|
+
|
150
160
|
## Installing
|
151
161
|
|
152
162
|
First, many thanks to Andreas Maunz for packaging openbabel as a gem which makes this install quite painless.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
data/bin/fragmenter.rb
CHANGED
@@ -4,40 +4,64 @@ require 'trollop'
|
|
4
4
|
require 'rubabel'
|
5
5
|
require 'rubabel/molecule/fragmentable'
|
6
6
|
|
7
|
+
default_ph = 2.5
|
8
|
+
|
9
|
+
Fragment = Struct.new(:frag, :id, :title, :mz, :mass, :charge, :smiles, :pairing)
|
7
10
|
|
8
11
|
parser = Trollop::Parser.new do
|
9
12
|
banner "usage: #{File.basename($0)} [OPTIONS|RULES] <SMARTS> ..."
|
10
13
|
text "\noptions:"
|
11
|
-
opt :ph, "the pH to use (experimental option)", :default =>
|
14
|
+
opt :ph, "the pH to use (experimental option)", :default => default_ph
|
15
|
+
opt :images, "print out svg images of fragments"
|
16
|
+
opt :format, "format of the molecules", :default => 'smiles'
|
12
17
|
#opt :uniq, "no repeated fragments", :default => false
|
13
18
|
text "\nrules:"
|
14
19
|
Rubabel::Molecule::Fragmentable::RULES.each do |rule|
|
15
20
|
opt rule, rule.to_s.gsub("_",' ')
|
16
21
|
end
|
17
22
|
text "\nexample:"
|
18
|
-
text "fragmenter.rb -
|
23
|
+
text "fragmenter.rb -xeh 'CCC(=O)OCCC' 'CCC(=O)OCCC(=O)O'"
|
19
24
|
end
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
rules.
|
26
|
-
|
27
|
-
end
|
26
|
+
options = parser.parse(ARGV)
|
27
|
+
opts = {rules: []}
|
28
|
+
opts[:uniq] = options.delete(:uniq)
|
29
|
+
ph = options.delete(:ph)
|
30
|
+
opts[:rules] = Rubabel::Molecule::Fragmentable::RULES.map do |rule|
|
31
|
+
rule if options["#{rule}_given".to_sym]
|
32
|
+
end.compact
|
28
33
|
|
29
34
|
if ARGV.size == 0
|
30
35
|
parser.educate && exit
|
31
36
|
end
|
32
37
|
|
33
|
-
ARGV.each do |
|
34
|
-
mol = Rubabel[
|
38
|
+
ARGV.each do |smiles|
|
39
|
+
mol = Rubabel[smiles, options[:format].to_sym]
|
35
40
|
puts "\nmolecule: #{mol.csmiles}"
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
mol.correct_for_ph!(ph)
|
42
|
+
puts "at ph #{ph}: #{mol.csmiles}"
|
43
|
+
fragment_sets = mol.fragment(opts)
|
44
|
+
puts %w(mz mass charge title smiles pairing).join("\t")
|
45
|
+
frags = []
|
46
|
+
fragment_sets.each_with_index do |frag_set,i|
|
47
|
+
frag_set.each_with_index do |frag,j|
|
48
|
+
unless frag.charge == 0
|
49
|
+
mz = (frag.mass / frag.charge).round(5)
|
50
|
+
end
|
51
|
+
|
52
|
+
frag.title = "#{i}-#{j}pair_" + (mz ? "#{mz}_mz" : "#{frag.mass.round(3)}_Mass")
|
53
|
+
frag_obj = Fragment.new(frag, frag.title, frag.title, mz, frag.exact_mass, frag.charge, frag.csmiles, i)
|
54
|
+
frags << frag_obj
|
41
55
|
end
|
42
56
|
end
|
57
|
+
frags = frags.sort_by {|frag| [-frag.charge, frag.mz] }
|
58
|
+
if options[:images]
|
59
|
+
frags.each do |frag|
|
60
|
+
fn = "#{frag.title}.png"
|
61
|
+
frag.frag.write(fn)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
frags.each do |frag|
|
65
|
+
puts [:mz, :mass, :charge, :title, :smiles, :pairing].map {|cat| frag.send(cat) }.join("\t")
|
66
|
+
end
|
43
67
|
end
|
data/lib/rubabel/atom.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
1
3
|
require 'matrix'
|
2
4
|
require 'andand'
|
3
5
|
|
@@ -184,7 +186,7 @@ module Rubabel
|
|
184
186
|
end
|
185
187
|
@ob.set_spin_multiplicity(new_spin)
|
186
188
|
atoms.each do |atom|
|
187
|
-
if atom.
|
189
|
+
if atom.hydrogen?
|
188
190
|
self.mol.delete_atom(atom)
|
189
191
|
break
|
190
192
|
end
|
@@ -246,6 +248,10 @@ module Rubabel
|
|
246
248
|
@ob.get_spin_multiplicity
|
247
249
|
end
|
248
250
|
|
251
|
+
def spin=(val)
|
252
|
+
@ob.set_spin_multiplicity(val)
|
253
|
+
end
|
254
|
+
|
249
255
|
def type
|
250
256
|
@ob.get_type
|
251
257
|
end
|
@@ -292,6 +298,13 @@ module Rubabel
|
|
292
298
|
def hbond_donor?() @ob.is_hbond_donor end
|
293
299
|
def hbond_donor_h?() @ob.is_hbond_donor_h end
|
294
300
|
|
301
|
+
# the total number of hydrogens bonded to the atom (implicit + explicit)
|
302
|
+
def hydrogen_count
|
303
|
+
@ob.implicit_hydrogen_count + @ob.explicit_hydrogen_count
|
304
|
+
end
|
305
|
+
|
306
|
+
alias_method :num_h, :hydrogen_count
|
307
|
+
|
295
308
|
def double_bond?
|
296
309
|
each_bond.any? {|bond| bond.bond_order == 2 }
|
297
310
|
end
|
data/lib/rubabel/bond.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
1
3
|
require 'rubabel/atom'
|
2
4
|
|
3
5
|
class OpenBabel::OBBond
|
@@ -88,7 +90,29 @@ module Rubabel
|
|
88
90
|
end
|
89
91
|
|
90
92
|
def inspect
|
91
|
-
|
93
|
+
bond_symbol = case bond_order
|
94
|
+
when 2 then '='
|
95
|
+
when 3 then '≡'
|
96
|
+
else
|
97
|
+
'-'
|
98
|
+
end
|
99
|
+
"#{atoms.map(&:inspect).join(bond_symbol)}"
|
100
|
+
end
|
101
|
+
|
102
|
+
# returns self
|
103
|
+
def +(val)
|
104
|
+
# do we need to check the bounds here?
|
105
|
+
newval = @ob.get_bond_order + val
|
106
|
+
@ob.set_bond_order(newval)
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
# won't decrease below zero. returns self
|
111
|
+
def -(val)
|
112
|
+
newval = @ob.get_bond_order - val
|
113
|
+
newval = 0 if newval < 0
|
114
|
+
@ob.set_bond_order(newval)
|
115
|
+
self
|
92
116
|
end
|
93
117
|
|
94
118
|
end
|
data/lib/rubabel/molecule.rb
CHANGED
@@ -503,7 +503,13 @@ module Rubabel
|
|
503
503
|
end
|
504
504
|
|
505
505
|
# sensitive to add_h!
|
506
|
-
def num_atoms()
|
506
|
+
def num_atoms(count_implied_hydrogens=false)
|
507
|
+
if !count_implied_hydrogens
|
508
|
+
@ob.num_atoms
|
509
|
+
else
|
510
|
+
@ob.num_atoms + reduce(0) {|cnt, atom| cnt + atom.ob.implicit_hydrogen_count }
|
511
|
+
end
|
512
|
+
end
|
507
513
|
def num_bonds() @ob.num_bonds end
|
508
514
|
def num_hvy_atoms() @ob.num_hvy_atoms end
|
509
515
|
def num_residues() @ob.num_residues end
|
@@ -6,21 +6,12 @@ module Rubabel
|
|
6
6
|
class Molecule
|
7
7
|
module Fragmentable
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
# :sp3c_oxygen_double_bond_far_side_sp3, :sp3c_oxygen_double_bond_far_side_sp2, :sp3c_oxygen_double_bond_water_loss, :sp3c_nitrogen_double_bond,
|
12
|
-
#]
|
13
|
-
#ADDUCTS = [:lioh, :nh4cl, :nh4oh]
|
14
|
-
#CO_RULES = Set[:alcohol_to_aldehyde, :peroxy_to_carboxy, :co2_loss,
|
15
|
-
# :sp3c_oxygen_double_bond_water_loss, :sp3c_oxygen_double_bond_far_side_sp2, :sp3c_oxygen_double_bond_far_side_sp3, :sp3c_oxygen_asymmetric_far_sp3
|
16
|
-
#]
|
17
|
-
|
18
|
-
RULES = Set[:cad_o, :cad_oo, :oxed_ether]
|
9
|
+
#RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh]
|
10
|
+
RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh, :oxhpd]
|
19
11
|
|
20
12
|
DEFAULT_OPTIONS = {
|
21
13
|
rules: RULES,
|
22
|
-
|
23
|
-
#ph: 7.4,
|
14
|
+
errors: :remove,
|
24
15
|
# return only the set of unique fragments
|
25
16
|
uniq: false,
|
26
17
|
}
|
@@ -31,117 +22,8 @@ module Rubabel
|
|
31
22
|
# For instance, water loss with double bond formation is not allowable
|
32
23
|
# for NCC(O)CC => CCC=C[NH2+], presumably because of the lone pair and
|
33
24
|
# double bond resonance.
|
34
|
-
#
|
35
25
|
def allowable_fragmentation?(frags)
|
36
|
-
self.num_atoms == frags.
|
37
|
-
end
|
38
|
-
|
39
|
-
# add_h! to self, then selects allowable fragments
|
40
|
-
def allowable_fragment_sets!(fragment_sets)
|
41
|
-
self.add_h!
|
42
|
-
fragment_sets.select do |_frags|
|
43
|
-
putsv "ExMAIN:"
|
44
|
-
putsv _frags.inspect
|
45
|
-
putsv self.allowable_fragmentation?(_frags)
|
46
|
-
self.allowable_fragmentation?(_frags)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# will turn bond into a double bond, yield the changed molecule, then
|
51
|
-
# return the bond to the original state when the block is closed
|
52
|
-
# returns whatever the block returned
|
53
|
-
def feint_double_bond(bond, give_e_pair=nil, get_e_pair=nil, &block)
|
54
|
-
orig = bond.bond_order
|
55
|
-
bond.bond_order = 2
|
56
|
-
reply =
|
57
|
-
if give_e_pair || get_e_pair
|
58
|
-
feint_e_transfer(give_e_pair, get_e_pair, &block)
|
59
|
-
else
|
60
|
-
block.call(self)
|
61
|
-
end
|
62
|
-
bond.bond_order = orig
|
63
|
-
reply
|
64
|
-
end
|
65
|
-
|
66
|
-
# warning, this method adds_h! to the calling molecule
|
67
|
-
def electrophile_snatches_electrons(carbon, electrophile)
|
68
|
-
self.add_h!
|
69
|
-
frags = self.split(carbon.get_bond(electrophile))
|
70
|
-
raise NotImplementedError
|
71
|
-
# don't check for allowable fragments because it
|
72
|
-
#allowable_fragment_sets!([frag_set])
|
73
|
-
end
|
74
|
-
|
75
|
-
def feint_e_transfer(give_e_pair=nil, get_e_pair=nil, &block)
|
76
|
-
if give_e_pair
|
77
|
-
gc_orig = give_e_pair.charge
|
78
|
-
give_e_pair.charge = gc_orig + 1
|
79
|
-
end
|
80
|
-
if get_e_pair
|
81
|
-
rc_orig = get_e_pair.charge
|
82
|
-
get_e_pair.charge = rc_orig - 1
|
83
|
-
end
|
84
|
-
|
85
|
-
reply = block.call(self)
|
86
|
-
|
87
|
-
give_e_pair.charge = gc_orig if give_e_pair
|
88
|
-
get_e_pair.charge = rc_orig if get_e_pair
|
89
|
-
|
90
|
-
reply
|
91
|
-
end
|
92
|
-
|
93
|
-
def near_side_double_bond_break(carbon, electrophile)
|
94
|
-
frag_sets = carbon.atoms.select {|atom| atom.type == "C3" }.map do |near_c3|
|
95
|
-
frags = feint_double_bond(carbon.get_bond(near_c3)) do |_mol|
|
96
|
-
frags = _mol.split(electrophile.get_bond(carbon))
|
97
|
-
frags.map(&:add_h!)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
allowable_fragment_sets!(frag_sets)
|
101
|
-
end
|
102
|
-
|
103
|
-
def alcohol_to_aldehyde(carbon, oxygen, carbon_nbrs)
|
104
|
-
# alcohol becomes a ketone and one R group is released
|
105
|
-
frag_sets = carbon_nbrs.select {|atom| atom.type == 'C3' }.map do |_atom|
|
106
|
-
frags = feint_double_bond(carbon.get_bond(oxygen)) do |_mol|
|
107
|
-
frags = _mol.split(carbon.get_bond(_atom))
|
108
|
-
frags.map(&:add_h!)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
allowable_fragment_sets!(frag_sets)
|
112
|
-
end
|
113
|
-
|
114
|
-
def co2_loss(carbon, oxygen, c3_nbr)
|
115
|
-
# carboxyl rules ...
|
116
|
-
# neutral carbon dioxide loss with anion gain on attaching group
|
117
|
-
# (if carbon)
|
118
|
-
frags = feint_double_bond(carbon.get_bond(oxygen), oxygen, c3_nbr) do |_mol|
|
119
|
-
frags = _mol.split(c3_nbr.get_bond(carbon))
|
120
|
-
frags.map(&:add_h!)
|
121
|
-
end
|
122
|
-
allowable_fragment_sets!([frags])
|
123
|
-
end
|
124
|
-
|
125
|
-
def peroxy_to_carboxy(carbon, oxygen, carbon_nbrs, oxygen_nbr)
|
126
|
-
if oxygen_nbr.el == :o # has a neighbor oxygen
|
127
|
-
distal_o = oxygen_nbr
|
128
|
-
if distal_o.bonds.size == 1 # this is a peroxy
|
129
|
-
frag_sets = carbon_nbrs.select {|atom| atom.type == 'C3' }.map do |_atom|
|
130
|
-
self.swap!(carbon, _atom, oxygen, distal_o)
|
131
|
-
frags = feint_double_bond(carbon.get_bond(oxygen)) do |_mol|
|
132
|
-
|
133
|
-
# we swapped the atoms so the bond to split off is now
|
134
|
-
# attached to the oxygen
|
135
|
-
frags = _mol.split(oxygen.get_bond(_atom))
|
136
|
-
frags.map(&:add_h!)
|
137
|
-
end
|
138
|
-
self.swap!(carbon, distal_o, oxygen, _atom)
|
139
|
-
frags
|
140
|
-
end
|
141
|
-
allowable_fragment_sets!(frag_sets)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
26
|
+
self.num_atoms(true) == frags.reduce(0) {|cnt,fr| cnt + fr.num_atoms(true) }
|
145
27
|
end
|
146
28
|
|
147
29
|
# splits the molecule between the carbon and carbon_nbr, adds a double
|
@@ -174,29 +56,30 @@ module Rubabel
|
|
174
56
|
# breaks the bond and gives the electrons to the oxygen
|
175
57
|
def carbon_oxygen_esteal(carbon, oxygen)
|
176
58
|
nmol = self.dup
|
177
|
-
nmol.ob.add_hydrogens
|
178
59
|
ncarbon = nmol.atom(carbon.id)
|
179
60
|
noxygen = nmol.atom(oxygen.id)
|
180
61
|
nmol.delete_bond(ncarbon, noxygen)
|
181
|
-
ncarbon.charge += 1
|
182
|
-
noxygen.charge -= 1
|
183
62
|
ncarbon.remove_an_h!
|
184
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
63
|
+
#noxygen.ob.set_spin_multiplicity 1
|
64
|
+
noxygen.spin = 1
|
65
|
+
noxygen.charge = -1
|
66
|
+
nmol.split
|
67
|
+
end
|
68
|
+
|
69
|
+
# returns the duplicated molecule and the equivalent atoms
|
70
|
+
def dup_molecule(atoms=[])
|
71
|
+
nmol = self.dup
|
72
|
+
[nmol, atoms.map {|old_atom| nmol.atom(old_atom.id) }]
|
73
|
+
end
|
190
74
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
puts "HIAY"
|
75
|
+
# returns molecules created from splitting between the electrophile and
|
76
|
+
# the center and where the bond order is increased between the center
|
77
|
+
# and center_nbr
|
78
|
+
def break_with_double_bond(electrophile, center, center_nbr)
|
79
|
+
(nmol, (nele, ncarb, ncarb_nbr)) = self.dup_molecule([electrophile, center, center_nbr])
|
80
|
+
nmol.delete_bond(nele, ncarb)
|
81
|
+
ncarb_nbr.get_bond(ncarb) + 1
|
82
|
+
nmol.split
|
200
83
|
end
|
201
84
|
|
202
85
|
# an empty array is returned if there are no fragments generated.
|
@@ -205,6 +88,7 @@ module Rubabel
|
|
205
88
|
#
|
206
89
|
# :rules => queryable by :include? set of rules
|
207
90
|
# :uniq => false
|
91
|
+
# :errors => :remove | :fix | :ignore (default is :remove)
|
208
92
|
def fragment(opts={})
|
209
93
|
only_uniqs = true
|
210
94
|
opts = DEFAULT_OPTIONS.merge(opts)
|
@@ -218,131 +102,60 @@ module Rubabel
|
|
218
102
|
|
219
103
|
fragment_sets = []
|
220
104
|
|
221
|
-
if opts[:rules].any? {|r| [:
|
105
|
+
if opts[:rules].any? {|r| [:cod, :codoo].include?(r) }
|
222
106
|
self.each_match("C[O;h1,O]", only_uniqs) do |carbon, oxygen|
|
223
107
|
carbon.atoms.select {|a| a.el == :c }.each do |carbon_nbr|
|
224
108
|
fragment_sets << carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
|
225
109
|
end
|
226
110
|
end
|
227
111
|
end
|
228
|
-
if opts[:rules].any? {|r| [:
|
229
|
-
self.each_match("C
|
112
|
+
if opts[:rules].any? {|r| [:oxe].include?(r) }
|
113
|
+
self.each_match("C-O", only_uniqs) do |carbon, oxygen|
|
230
114
|
fragment_sets << carbon_oxygen_esteal(carbon, oxygen)
|
231
115
|
end
|
232
116
|
end
|
117
|
+
# right now implemented so that a beta hydrogen has to be availabe for
|
118
|
+
# extraction
|
119
|
+
if opts[:rules].any? {|r| [:oxh].include?(r) }
|
120
|
+
self.each_match("C[C,O]-O", only_uniqs) do |beta_c, center, oxygen|
|
121
|
+
next unless beta_c.hydrogen_count > 0
|
122
|
+
fragment_sets << break_with_double_bond(oxygen, center, beta_c)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
if opts[:rules].any? {|r| [:oxhpd].include?(r) }
|
126
|
+
self.each_match("C-O-P-O", only_uniqs) do |carbon, alc_oxy, phosphate, beta_carb_oxy|
|
127
|
+
next unless beta_carb_oxy.hydrogen_count > 0
|
128
|
+
frag_set = break_with_double_bond(alc_oxy, phosphate, beta_carb_oxy)
|
129
|
+
frag_set.map! &:convert_dative_bonds!
|
130
|
+
fragment_sets << frag_set
|
131
|
+
end
|
132
|
+
end
|
133
|
+
if opts[:rules].any? {|r| [:oxepd].include?(r) }
|
134
|
+
self.each_match("P-O-C", only_uniqs) do |phosphate, oxygen, carbon|
|
135
|
+
frag_set = carbon_oxygen_esteal(phosphate, oxygen)
|
136
|
+
frag_set.map! &:convert_dative_bonds!
|
137
|
+
fragment_sets << frag_set
|
138
|
+
end
|
139
|
+
end
|
233
140
|
|
234
|
-
|
235
|
-
|
236
|
-
|
141
|
+
case opts[:errors]
|
142
|
+
when :remove
|
143
|
+
fragment_sets.select! {|set| allowable_fragmentation?(set) }
|
144
|
+
when :fix
|
145
|
+
raise NotImplementedError
|
146
|
+
when :ignore # do nothing
|
237
147
|
end
|
148
|
+
|
149
|
+
self.remove_h!
|
238
150
|
if opts[:uniq]
|
239
151
|
# TODO: impelent properly
|
240
152
|
raise NotImplementedError
|
241
|
-
#fragment_sets = fragment_sets.uniq_by(&:csmiles)
|
153
|
+
#fragment_sets = fragment_sets.uniq_by(&:csmiles)
|
242
154
|
end
|
243
155
|
|
244
156
|
fragment_sets
|
245
157
|
end
|
246
|
-
|
247
|
-
|
248
|
-
# had_hydrogens = self.h_added?
|
249
|
-
|
250
|
-
#self.correct_for_ph!(opts[:ph])
|
251
|
-
#self.remove_h!
|
252
|
-
|
253
|
-
#rules = opts[:rules]
|
254
|
-
#fragment_sets = []
|
255
|
-
#if rules.any? {|rule| CO_RULES.include?(rule) }
|
256
|
-
#putsv "matching C-O"
|
257
|
-
#self.each_match("CO").each do |_atoms|
|
258
|
-
## note: this will *not* match C=O
|
259
|
-
#(carbon, oxygen) = _atoms
|
260
|
-
#carbon_nbrs = carbon.atoms.reject {|atom| atom == oxygen }
|
261
|
-
#c3_nbrs = carbon_nbrs.select {|atm| atm.type == 'C3' }
|
262
|
-
## pulling this out here causes it to work incorrectly internally
|
263
|
-
## (not sure why)
|
264
|
-
##co_bond = carbon.get_bond(oxygen)
|
265
|
-
|
266
|
-
#case oxygen.bonds.size # non-hydrogen bonds
|
267
|
-
#when 1 # *must* be an alcohol or a carboxylic acid
|
268
|
-
#putsv "#{csmiles} oxygen has no other bonds besides C-O (alcohol or carboxylic acid)"
|
269
|
-
#if carbon.type == 'C3'
|
270
|
-
#if rules.include?(:sp3c_oxygen_double_bond_water_loss)
|
271
|
-
#putsv "rule :sp3c_oxygen_double_bond_water_loss"
|
272
|
-
#fragment_sets.push *near_side_double_bond_break(carbon, oxygen)
|
273
|
-
#end
|
274
|
-
#if rules.include?(:alcohol_to_aldehyde)
|
275
|
-
#putsv "rule :alcohol_to_aldehyde"
|
276
|
-
#fragment_sets.push *alcohol_to_aldehyde(carbon, oxygen, carbon_nbrs)
|
277
|
-
#end
|
278
|
-
#elsif carbon.carboxyl_carbon?
|
279
|
-
#if rules.include?(:co2_loss)
|
280
|
-
#putsv "rule :co2_loss"
|
281
|
-
#if c3_nbr = c3_nbrs.first
|
282
|
-
#fragment_sets.push *co2_loss(carbon, oxygen, c3_nbr)
|
283
|
-
#end
|
284
|
-
#end
|
285
|
-
#end
|
286
|
-
#when 2
|
287
|
-
#putsv "#{csmiles} c-o & oxygen has 2 non-hydrogen bonds"
|
288
|
-
#oxygen_nbr = oxygen.atoms.reject {|atom| atom.idx == carbon.idx }.first
|
289
|
-
#if carbon.type == 'C3'
|
290
|
-
#if rules.include?(:peroxy_to_carboxy)
|
291
|
-
#fragment_sets.push *peroxy_to_carboxy(carbon, oxygen, carbon_nbrs, oxygen_nbr)
|
292
|
-
#end
|
293
|
-
## ester and ethers (look *only* on close side for places to make
|
294
|
-
## double bond)
|
295
|
-
|
296
|
-
#if oxygen_nbr.type == 'C3'
|
297
|
-
#putsv "oxygen nbr is C3"
|
298
|
-
#if rules.include?(:sp3c_oxygen_double_bond_far_side_sp3)
|
299
|
-
#putsv "rule :sp3c_oxygen_double_bond_far_side_sp3"
|
300
|
-
#fragment_sets.push *near_side_double_bond_break(carbon, oxygen)
|
301
|
-
#end
|
302
|
-
#if rules.include?(:sp3c_oxygen_asymmetric_far_sp3)
|
303
|
-
#putsv "rule :sp3c_oxygen_asymmetric_far_sp3"
|
304
|
-
## only returns a single frag set
|
305
|
-
#fragment_sets.push electrophile_snatches_electrons(carbon, oxygen)
|
306
|
-
#end
|
307
|
-
#end
|
308
|
-
#if oxygen_nbr.type == 'C2'
|
309
|
-
#if rules.include?(:sp3c_oxygen_double_bond_far_side_sp2)
|
310
|
-
#putsv "rule :sp3c_oxygen_double_bond_far_side_sp2"
|
311
|
-
#fragment_sets.push *near_side_double_bond_break(carbon, oxygen)
|
312
|
-
#end
|
313
|
-
#end
|
314
|
-
## note: the case of a carboxy is found with CO search
|
315
|
-
#end
|
316
|
-
#end
|
317
|
-
#end
|
318
|
-
#end
|
319
|
-
#if rules.include?(:sp3c_nitrogen_double_bond)
|
320
|
-
#self.each_match("CN") do |_atoms|
|
321
|
-
#(carbon, nitrogen) = _atoms
|
322
|
-
#num_nitrogen_bonds = nitrogen.bonds.size
|
323
|
-
#case num_nitrogen_bonds
|
324
|
-
#when 2
|
325
|
-
#if carbon.type == 'C3'
|
326
|
-
#fragment_sets.push *near_side_double_bond_break(carbon, nitrogen)
|
327
|
-
#end
|
328
|
-
#end
|
329
|
-
#end
|
330
|
-
#end
|
331
|
-
|
332
|
-
#unless had_hydrogens
|
333
|
-
#fragment_sets.each {|set| set.each(&:remove_h!) }
|
334
|
-
#self.remove_h!
|
335
|
-
#end
|
336
|
-
#if opts[:uniq]
|
337
|
-
## TODO: impelent properly
|
338
|
-
##fragment_sets = fragment_sets.uniq_by(&:csmiles)
|
339
|
-
#raise NotImplementedError
|
340
|
-
#end
|
341
|
-
#fragment_sets
|
342
|
-
#end
|
343
|
-
|
344
158
|
end
|
345
159
|
include Fragmentable
|
346
160
|
end
|
347
|
-
end
|
348
|
-
|
161
|
+
end # Rubabel
|
@@ -4,226 +4,184 @@ require 'rubabel'
|
|
4
4
|
|
5
5
|
$VERBOSE = nil
|
6
6
|
|
7
|
-
|
7
|
+
describe Rubabel::Molecule::Fragmentable do
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# :peroxy_to_carboxy
|
10
|
+
# :oxygen_asymmetric_sp3, :nitrogen_asymmetric_sp3,
|
11
|
+
# :internal_phosphoester
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
describe 'fragmentation rules' do
|
14
|
+
# coenzyme: CC1=CC(=O)C=CC1=O
|
15
|
+
# 2-methylcyclohexa-2,5-diene-1,4-dione
|
16
16
|
|
17
17
|
#let(:test_mol) { "COP(=O)(O)OCNCOCC(OO)C(=O)O" }
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
it 'raises an error for a bad rule' do
|
20
|
+
mol = Rubabel["CCNC"]
|
21
|
+
expect { mol.fragment(rules: [:wackiness]) }.to raise_error
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
describe 'cod: carbonyl appendage dump' do
|
25
|
+
# a primary oxygen or peroxide => C=O appendage dump
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
##mol = Rubabel["NC(O)CC"]
|
190
|
-
##fragments = mol.fragment( rules: [:sp3c_oxygen_double_bond_water_loss] )
|
191
|
-
##fragments.flatten(1).map(&:csmiles).sort.should == []
|
192
|
-
##end
|
193
|
-
##end
|
194
|
-
|
195
|
-
##describe 'sp3c_oxygen_double_bond_far_side_sp2' do
|
196
|
-
|
197
|
-
##it 'does not cleave esters without sp3 carbons available for double bond' do
|
198
|
-
##mol = Rubabel["NCCC(=O)OC"]
|
199
|
-
##pieces = mol.fragment( rules: [:sp3c_oxygen_double_bond_far_side_sp2] )
|
200
|
-
##pieces.should be_empty
|
201
|
-
##end
|
202
|
-
|
203
|
-
##it 'cleaves esters on far side of singly bonded oxygen' do
|
204
|
-
##mol = Rubabel["NCCC(=O)OCC"]
|
205
|
-
##pieces = mol.fragment( rules: [:sp3c_oxygen_double_bond_far_side_sp2] )
|
206
|
-
##pieces.size.should == 1 # one set
|
207
|
-
##the_pair = pieces.first
|
208
|
-
##csmiles = the_pair.map(&:csmiles)
|
209
|
-
##csmiles.should include("OC(=O)CC[NH3+]")
|
210
|
-
##csmiles.should include("C=C")
|
211
|
-
##end
|
212
|
-
|
213
|
-
##end
|
214
|
-
|
215
|
-
##describe ':alcohol_to_aldehyde' do
|
216
|
-
##it 'cleaves beside alcohols to generate an aldehyde' do
|
217
|
-
##mol = Rubabel["NCCC(O)CC"]
|
218
|
-
##mol.correct_for_ph!
|
219
|
-
##total_mass = mol.add_h!.mass
|
220
|
-
|
221
|
-
##pieces = mol.fragment(rules: [:alcohol_to_aldehyde])
|
222
|
-
##pieces.size.should == 2
|
223
|
-
##pieces.map(&:size).should == [2,2]
|
224
|
-
##pieces.flatten(1).map(&:csmiles).should == ["CC[NH3+]", "CCC=O", "C(C=O)C[NH3+]", "CC"]
|
225
|
-
##pieces.each do |pair|
|
226
|
-
##pair.map(&:mass).reduce(:+).should == total_mass
|
227
|
-
##end
|
228
|
-
##end
|
229
|
-
##end
|
27
|
+
specify 'cod: primary alcohol' do
|
28
|
+
mol = Rubabel["NCC(O)CC"]
|
29
|
+
frags = mol.fragment(rules: [:cod])
|
30
|
+
frags.flatten(1).map(&:csmiles).should == ["C[NH3+]", "CCC=O", "C([NH3+])C=O", "CC"]
|
31
|
+
end
|
32
|
+
|
33
|
+
specify 'peroxide' do
|
34
|
+
mol = Rubabel["NCC(OO)CC"]
|
35
|
+
frags = mol.fragment(rules: [:codoo])
|
36
|
+
frags.flatten(1).map(&:csmiles).should == ["OC[NH3+]", "CCC=O", "C([NH3+])C=O", "CCO"]
|
37
|
+
end
|
38
|
+
|
39
|
+
specify 'cod: carboxylate' do
|
40
|
+
mol = Rubabel["CCC(=O)O"]
|
41
|
+
pieces = mol.fragment(rules: [:cod])
|
42
|
+
pieces.flatten(1).map(&:csmiles).should == ["[CH2-]C", "O=C=O"]
|
43
|
+
end
|
44
|
+
|
45
|
+
specify 'cod: carboxylic acid' do
|
46
|
+
mol = Rubabel["CCC(=O)O"]
|
47
|
+
mol.add_h!(1.5)
|
48
|
+
pieces = mol.fragment(rules: [:cod])
|
49
|
+
pieces.flatten(1).map(&:csmiles).should == ["CC", "O=C=O"]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'oxe: oxygen electron stealing' do
|
54
|
+
# oxygen just steals the electron pair it is attached to. This
|
55
|
+
# typically results in a negatively charged oxygen and a positively
|
56
|
+
# charged carbo-cation.
|
57
|
+
specify 'ether to ions (same for esters)' do
|
58
|
+
mol = Rubabel["CCOCCN"]
|
59
|
+
frag_set = mol.fragment(rules: [:oxe])
|
60
|
+
frags = frag_set.first
|
61
|
+
frags.first.csmiles.should == "C[CH2+]"
|
62
|
+
frags.last.csmiles.should == '[O-]CC[NH3+]'
|
63
|
+
frags.first.formula.should == 'C2H5'
|
64
|
+
frags.last.formula.should == 'C2H7NO'
|
65
|
+
frags.first.exact_mass.should be_within(1e-6).of(29.03912516)
|
66
|
+
frags.last.exact_mass.should be_within(1e-6).of(61.052763849)
|
67
|
+
|
68
|
+
mol = Rubabel["CCOC(=O)CCN"]
|
69
|
+
frag_set = mol.fragment(rules: [:oxe])
|
70
|
+
ff = frag_set.first
|
71
|
+
ff.first.csmiles.should == 'C[CH2+]'
|
72
|
+
ff.last.csmiles.should == '[O-]C(=O)CC[NH3+]'
|
73
|
+
ff.first.formula.should == "C2H5"
|
74
|
+
ff.last.formula.should == "C3H7NO2"
|
75
|
+
ff.first.exact_mass.should be_within(1e-6).of(29.03912516035)
|
76
|
+
ff.last.exact_mass.should be_within(1e-6).of(89.04767846841)
|
77
|
+
end
|
78
|
+
|
79
|
+
specify 'carboxyl group' do
|
80
|
+
mol = Rubabel["CCC(=O)O"]
|
81
|
+
frag_set = mol.fragment(rules: [:oxe])
|
82
|
+
ff = frag_set.first
|
83
|
+
ff.first.csmiles.should == 'CC[C+]=O'
|
84
|
+
ff.last.csmiles.should == '[O-]'
|
85
|
+
ff.first.formula.should == "C3H5O"
|
86
|
+
ff.first.exact_mass.should be_within(1e-6).of(57.034039779909996)
|
87
|
+
ff.last.formula.should == "O"
|
88
|
+
end
|
89
|
+
|
90
|
+
specify 'phosphodiester' do
|
91
|
+
mol = Rubabel["CC(COP(=O)([O-])OCCN"]
|
92
|
+
frag_set = mol.fragment(rules: [:oxepd])
|
93
|
+
ff = frag_set.first
|
94
|
+
ff.first.csmiles.should == '[O-]CCC'
|
95
|
+
ff.last.csmiles.should == '[NH3+]CCO[P](=O)=O'
|
96
|
+
ff.first.formula.should == 'C3H7O'
|
97
|
+
ff.first.exact_mass.should be_within(1e-6).of(59.049689844)
|
98
|
+
ff.last.formula.should == 'C2H7NO3P'
|
99
|
+
ff.last.exact_mass.should be_within(1e-6).of(124.016354719)
|
100
|
+
|
101
|
+
mol = Rubabel["CCCOP(=O)(OCC[N+](C)(C)C)[O-]"]
|
102
|
+
frag_set = mol.fragment(rules: [:oxepd, :oxe])
|
103
|
+
# some of these don't like right on first inspection, but that is
|
104
|
+
# because we 'converted dative bonds' meaning + and - next to each
|
105
|
+
# other are allowed to cancel one another out!
|
106
|
+
frag_set.size.should == 4
|
107
|
+
mols = frag_set.flatten
|
108
|
+
mols.map(&:csmiles).should == ["CC[CH2+]", "[O-]P(=O)(OCC[N+](C)(C)C)[O-]", "CCCOP(=O)([O-])[O-]", "[CH2+]C[N+](C)(C)C", "[O-]CCC", "O=[P](=O)OCC[N+](C)(C)C", "CCCO[P](=O)=O", "[O-]CC[N+](C)(C)C"]
|
109
|
+
mols.map(&:formula).should == ["C3H7", "C5H13NO4P", "C3H7O4P", "C5H13N", "C3H7O", "C5H13NO3P", "C3H7O3P", "C5H13NO"]
|
110
|
+
mols.map(&:exact_mass).zip([43.05477522449, 182.05821952995, 138.00819533273, 87.10479942171, 59.04968984405, 166.06330491039, 122.01328071317, 103.09971404127]) do |act, exp|
|
111
|
+
act.should be_within(1e-6).of(exp)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# this is really a subset of oxygen bond stealing: if the negatively
|
118
|
+
# charged oxygen can rip off a nearby proton, it will.
|
119
|
+
describe 'oxh: oxygen alpha/beta/gamma hydrogen stealing' do
|
120
|
+
specify 'primary alcohol giving water loss' do
|
121
|
+
mol = Rubabel["CC(O)CCN"]
|
122
|
+
frags = mol.fragment(rules: [:oxh])
|
123
|
+
ff = frags.first
|
124
|
+
ff.first.csmiles.should == 'C=CCC[NH3+]'
|
125
|
+
ff.last.csmiles.should == 'O'
|
126
|
+
ll = frags.last
|
127
|
+
ll.first.csmiles.should == 'CC=CC[NH3+]'
|
128
|
+
ll.last.csmiles.should == 'O'
|
129
|
+
ff.first.formula.should == 'C4H10N'
|
130
|
+
ff.first.exact_mass.should be_within(1e-6).of(72.0813243255)
|
131
|
+
end
|
132
|
+
|
133
|
+
specify 'peroxide carbonyl formation (or peroxide formation [that what we want??])' do
|
134
|
+
# do we really see peroxide formation? Tamil didn't include this in
|
135
|
+
# the rules but it follows from the broad way for creating these
|
136
|
+
# rules. Can prohibit peroxide formation in future if necessary...
|
137
|
+
mol = Rubabel["CC(OO)CCN"]
|
138
|
+
frags = mol.fragment(rules: [:oxh])
|
139
|
+
mols = frags.flatten
|
140
|
+
mols.map(&:csmiles).should == ["C=CCC[NH3+]", "OO", "CC(=O)CC[NH3+]", "O", "CC=CC[NH3+]", "OO"]
|
141
|
+
mols.map(&:formula).should == ["C4H10N", "H2O2", "C4H10NO", "H2O", "C4H10N", "H2O2"]
|
142
|
+
mols.map(&:exact_mass).zip([72.081324325, 34.005479304, 88.076238945, 18.010564684, 72.081324325, 34.005479304]) do |act, exp|
|
143
|
+
act.should be_within(1e-6).of(exp)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
specify 'ether to alcohol, ignoring errors' do
|
148
|
+
# this is a good example of a 'disallowed structure' where the
|
149
|
+
# formula's do not match up to the original formulas
|
150
|
+
mol = Rubabel["CCOCCN"]
|
151
|
+
frags = mol.fragment(rules: [:oxh], errors: :ignore)
|
152
|
+
mols = frags.flatten
|
153
|
+
mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]", "CCO", "C=C[NH2+]"]
|
154
|
+
end
|
155
|
+
|
156
|
+
specify 'ether to alcohol, removing errors' do
|
157
|
+
mol = Rubabel["CCOCCN"]
|
158
|
+
frags = mol.fragment(rules: [:oxh])
|
159
|
+
mols = frags.flatten
|
160
|
+
mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]"]
|
161
|
+
end
|
162
|
+
|
163
|
+
specify 'ester to alcohol' do
|
164
|
+
mol = Rubabel["CC(=O)OCCCN"]
|
165
|
+
frags = mol.fragment(rules: [:oxh])
|
166
|
+
mols = frags.flatten
|
167
|
+
mols.map(&:csmiles).should == ["C=C=O", "OCCC[NH3+]", "CC(=O)O", "C=CC[NH3+]"]
|
168
|
+
mols.map(&:formula).should == ["C2H2O", "C3H10NO", "C2H4O2", "C3H8N"]
|
169
|
+
mols.map(&:exact_mass).zip([42.010564684, 76.076238945, 60.021129368000004, 58.065674261]) do |act,exp|
|
170
|
+
act.should be_within(1e-6).of(exp)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
specify 'phosphodiester (right now needs very low pH and NOT SURE WORKING PROPERLY)' do
|
175
|
+
mol = Rubabel["CC(COP(=O)(O)OCCCN"]
|
176
|
+
mol.add_h!(1.0)
|
177
|
+
frags = mol.fragment(rules: [:oxhpd])
|
178
|
+
frags = frags.flatten
|
179
|
+
frags.map(&:csmiles).should == ["CCCO", "[NH3+]CCCOP(=O)=O", "CCCOP(=O)=O", "OCCC[NH3+]"]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
|
@@ -88,6 +88,18 @@ describe Rubabel::Molecule do
|
|
88
88
|
ar.size.should == 2
|
89
89
|
end
|
90
90
|
|
91
|
+
specify 'num_atoms gives the number of atoms which can vary with hydrogens added' do
|
92
|
+
mol = Rubabel["CCC"]
|
93
|
+
mol.num_atoms.should == 3
|
94
|
+
mol.add_h!
|
95
|
+
mol.num_atoms.should == 11
|
96
|
+
end
|
97
|
+
|
98
|
+
specify 'num_atoms(true) gives the number including implied hydrogens' do
|
99
|
+
mol = Rubabel["CCC"]
|
100
|
+
mol.num_atoms(true).should == 11
|
101
|
+
end
|
102
|
+
|
91
103
|
describe 'adding an atom' do
|
92
104
|
it 'can be added but not attached' do
|
93
105
|
mol = Rubabel["CCO"]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubabel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: openbabel
|