rubabel 0.4.0 → 0.4.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
  SHA1:
3
- metadata.gz: 6e50e4f083ed06992600b2b86767d0d3a2b00fcf
4
- data.tar.gz: e2b4f65a73450c8336b31d650c3c4bfff6981942
3
+ metadata.gz: 8c407acb50267d5d801e3b17c7ca6c9090f09935
4
+ data.tar.gz: dc4f917d5688fd3be0b593bb34d3f25edce5b362
5
5
  SHA512:
6
- metadata.gz: a1e131cbc6b178f52ea340acc11ca1b48b606846cdfe3f21609e9578c7b7ecbd9f5590655c988a1098bc7356e9089a930c5570dc359df09f6384f4349d69c65f
7
- data.tar.gz: e626626e6f236810a4e46e41bdcf63da8927e8bfe0bc2d8b271c915ba2fc48dc898012eccf0c535f2b5c95dd1281e3be2c1d99c27c53f9779811613da191629b
6
+ metadata.gz: 618fb4a2d529cdbf7c3ec1ae1fc85088a92cd4b554d43f95bfa527bb15c1cae946a45474c1553db0a4ab456cf70a7cd5c6566a47856a0a4f4656c251378ff067
7
+ data.tar.gz: eeb366cb6d73da968fd54dae44e6f64d3edc485a0913742713846ed7b28dabdb89708533d145dfc6ad6bf6b164a6584f8288120e45dc19e82c7af9e9410fa8a2
@@ -2,7 +2,6 @@ require 'openbabel'
2
2
  require 'rubabel'
3
3
  require 'rubabel/atom'
4
4
  require 'rubabel/bond'
5
- require 'rubabel/molecule/fragmentable'
6
5
  require 'stringio'
7
6
  require 'mini_magick'
8
7
 
@@ -1,3 +1,3 @@
1
1
  module Rubabel
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubabel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John T. Prince
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-07 00:00:00.000000000 Z
11
+ date: 2013-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: openbabel
@@ -139,8 +139,7 @@ dependencies:
139
139
  description: Ruby interface to the OpenBabel ruby bindings similar to pybel
140
140
  email:
141
141
  - jtprince@gmail.com
142
- executables:
143
- - fragmenter.rb
142
+ executables: []
144
143
  extensions: []
145
144
  extra_rdoc_files: []
146
145
  files:
@@ -152,7 +151,6 @@ files:
152
151
  - README.md
153
152
  - Rakefile
154
153
  - VERSION
155
- - bin/fragmenter.rb
156
154
  - lib/rubabel.rb
157
155
  - lib/rubabel/atom.rb
158
156
  - lib/rubabel/bond.rb
@@ -160,7 +158,6 @@ files:
160
158
  - lib/rubabel/core_ext/putsv.rb
161
159
  - lib/rubabel/fingerprint.rb
162
160
  - lib/rubabel/molecule.rb
163
- - lib/rubabel/molecule/fragmentable.rb
164
161
  - lib/rubabel/molecule_data.rb
165
162
  - lib/rubabel/pm.rb
166
163
  - lib/rubabel/smarts.rb
@@ -186,7 +183,6 @@ files:
186
183
  - spec/chemistry_toolkit_rosetta/tpsa.tab
187
184
  - spec/rubabel/atom_spec.rb
188
185
  - spec/rubabel/bond_spec.rb
189
- - spec/rubabel/molecule/fragmentable_spec.rb
190
186
  - spec/rubabel/molecule_data_spec.rb
191
187
  - spec/rubabel/molecule_spec.rb
192
188
  - spec/rubabel_spec.rb
@@ -236,7 +232,6 @@ test_files:
236
232
  - spec/chemistry_toolkit_rosetta/tpsa.tab
237
233
  - spec/rubabel/atom_spec.rb
238
234
  - spec/rubabel/bond_spec.rb
239
- - spec/rubabel/molecule/fragmentable_spec.rb
240
235
  - spec/rubabel/molecule_data_spec.rb
241
236
  - spec/rubabel/molecule_spec.rb
242
237
  - spec/rubabel_spec.rb
@@ -1,67 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'trollop'
4
- require 'rubabel'
5
- require 'rubabel/molecule/fragmentable'
6
-
7
- default_ph = 2.5
8
-
9
- Fragment = Struct.new(:frag, :id, :title, :mz, :mass, :charge, :smiles, :pairing)
10
-
11
- parser = Trollop::Parser.new do
12
- banner "usage: #{File.basename($0)} [OPTIONS|RULES] <SMARTS> ..."
13
- text "\noptions:"
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'
17
- #opt :uniq, "no repeated fragments", :default => false
18
- text "\nrules:"
19
- Rubabel::Molecule::Fragmentable::RULES.each do |rule|
20
- opt rule, rule.to_s.gsub("_",' ')
21
- end
22
- text "\nexample:"
23
- text "fragmenter.rb -xeh 'CCC(=O)OCCC' 'CCC(=O)OCCC(=O)O'"
24
- end
25
-
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
33
-
34
- if ARGV.size == 0
35
- parser.educate && exit
36
- end
37
-
38
- ARGV.each do |smiles|
39
- mol = Rubabel[smiles, options[:format].to_sym]
40
- puts "\nmolecule: #{mol.csmiles}"
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
55
- end
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
67
- end
@@ -1,162 +0,0 @@
1
- require 'set'
2
- require 'rubabel/core_ext/putsv'
3
- require 'rubabel/core_ext/enumerable'
4
-
5
- module Rubabel
6
- class Molecule
7
- module Fragmentable
8
-
9
- #RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh]
10
- RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh, :oxhpd]
11
-
12
- DEFAULT_OPTIONS = {
13
- rules: RULES,
14
- errors: :remove,
15
- # return only the set of unique fragments
16
- uniq: false,
17
- }
18
-
19
- # molecules and fragments should all have hydrogens added (add_h!)
20
- # before calling this method
21
- #
22
- # For instance, water loss with double bond formation is not allowable
23
- # for NCC(O)CC => CCC=C[NH2+], presumably because of the lone pair and
24
- # double bond resonance.
25
- def allowable_fragmentation?(frags)
26
- self.num_atoms(true) == frags.reduce(0) {|cnt,fr| cnt + fr.num_atoms(true) }
27
- end
28
-
29
- # splits the molecule between the carbon and carbon_nbr, adds a double
30
- # bond between the carbon and oxygen, and moves whatever was on the
31
- # oxygen (e.g., an OH or a charge) to the carbon_nbr. Returns two new
32
- # molecules.
33
- def carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
34
- appendage = oxygen.atoms.find {|a| a.el != :C }
35
- if oxygen.charge != 0
36
- ocharge = oxygen.charge
37
- end
38
- nmol = self.dup
39
- new_oxygen = nmol.atom(oxygen.id)
40
- new_carbon = nmol.atom(carbon.id)
41
- new_carbon_nbr = nmol.atom(carbon_nbr.id)
42
- new_appendage = nmol.atom(appendage.id) if appendage
43
- nmol.delete_bond(new_carbon.get_bond(new_carbon_nbr))
44
- if new_appendage
45
- nmol.delete_bond(new_oxygen.get_bond(new_appendage))
46
- nmol.add_bond!(new_carbon_nbr, new_appendage)
47
- end
48
- if ocharge
49
- new_carbon_nbr.charge += ocharge
50
- new_oxygen.charge -= ocharge
51
- end
52
- new_carbon.get_bond(new_oxygen).bond_order = 2
53
- nmol.split
54
- end
55
-
56
- # breaks the bond and gives the electrons to the oxygen
57
- def carbon_oxygen_esteal(carbon, oxygen)
58
- nmol = self.dup
59
- ncarbon = nmol.atom(carbon.id)
60
- noxygen = nmol.atom(oxygen.id)
61
-
62
- is_carboxyl = noxygen.carboxyl_oxygen?
63
-
64
- nmol.delete_bond(ncarbon, noxygen)
65
- ncarbon.remove_a_hydride!
66
- noxygen.remove_a_proton!
67
- nmol.split
68
- end
69
-
70
- # returns the duplicated molecule and the equivalent atoms
71
- def dup_molecule(atoms=[])
72
- nmol = self.dup
73
- [nmol, atoms.map {|old_atom| nmol.atom(old_atom.id) }]
74
- end
75
-
76
- # returns molecules created from splitting between the electrophile and
77
- # the center and where the bond order is increased between the center
78
- # and center_nbr
79
- def break_with_double_bond(electrophile, center, center_nbr)
80
- (nmol, (nele, ncarb, ncarb_nbr)) = self.dup_molecule([electrophile, center, center_nbr])
81
- nmol.delete_bond(nele, ncarb)
82
- ncarb_nbr.get_bond(ncarb) + 1
83
- nmol.split
84
- end
85
-
86
- # an empty array is returned if there are no fragments generated.
87
- # Hydrogens are added at a pH of 7.4, unless they have already been
88
- # added.
89
- #
90
- # :rules => queryable by :include? set of rules
91
- # :uniq => false
92
- # :errors => :remove | :fix | :ignore (default is :remove)
93
- def fragment(opts={})
94
- only_uniqs = true
95
- opts = DEFAULT_OPTIONS.merge(opts)
96
- opts[:rules].each do |rule|
97
- raise ArgumentError, "bad rule: #{rule}" unless RULES.include?(rule)
98
- end
99
-
100
- had_hydrogens = self.h_added?
101
- self.correct_for_ph!(7.4) unless had_hydrogens
102
- self.remove_h!
103
-
104
- fragment_sets = []
105
-
106
- if opts[:rules].any? {|r| [:cod, :codoo].include?(r) }
107
- self.each_match("C[O;h1,O]", only_uniqs) do |carbon, oxygen|
108
- carbon.atoms.select {|a| a.el == :C }.each do |carbon_nbr|
109
- fragment_sets << carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
110
- end
111
- end
112
- end
113
- if opts[:rules].any? {|r| [:oxe].include?(r) }
114
- self.each_match("C-O", only_uniqs) do |carbon, oxygen|
115
- fragment_sets << carbon_oxygen_esteal(carbon, oxygen)
116
- end
117
- end
118
- # right now implemented so that a beta hydrogen has to be availabe for
119
- # extraction
120
- if opts[:rules].any? {|r| [:oxh].include?(r) }
121
- self.each_match("C[C,O]-O", only_uniqs) do |beta_c, center, oxygen|
122
- next unless beta_c.hydrogen_count > 0
123
- fragment_sets << break_with_double_bond(oxygen, center, beta_c)
124
- end
125
- end
126
- if opts[:rules].any? {|r| [:oxhpd].include?(r) }
127
- self.each_match("C-O-P-O", only_uniqs) do |carbon, alc_oxy, phosphate, beta_carb_oxy|
128
- next unless beta_carb_oxy.hydrogen_count > 0
129
- frag_set = break_with_double_bond(alc_oxy, phosphate, beta_carb_oxy)
130
- frag_set.map! &:convert_dative_bonds!
131
- fragment_sets << frag_set
132
- end
133
- end
134
- if opts[:rules].any? {|r| [:oxepd].include?(r) }
135
- self.each_match("P-O-C", only_uniqs) do |phosphate, oxygen, carbon|
136
- frag_set = carbon_oxygen_esteal(phosphate, oxygen)
137
- frag_set.map! &:convert_dative_bonds!
138
- fragment_sets << frag_set
139
- end
140
- end
141
-
142
- case opts[:errors]
143
- when :remove
144
- fragment_sets.select! {|set| allowable_fragmentation?(set) }
145
- when :fix
146
- raise NotImplementedError
147
- when :ignore # do nothing
148
- end
149
-
150
- self.remove_h!
151
- if opts[:uniq]
152
- # TODO: impelent properly
153
- raise NotImplementedError
154
- #fragment_sets = fragment_sets.uniq_by(&:csmiles)
155
- end
156
-
157
- fragment_sets
158
- end
159
- end
160
- include Fragmentable
161
- end
162
- end # Rubabel
@@ -1,199 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'rubabel'
4
-
5
- $VERBOSE = nil
6
-
7
- describe Rubabel::Molecule::Fragmentable do
8
-
9
- # :peroxy_to_carboxy
10
- # :oxygen_asymmetric_sp3, :nitrogen_asymmetric_sp3,
11
- # :internal_phosphoester
12
-
13
- describe 'fragmentation rules' do
14
- # coenzyme: CC1=CC(=O)C=CC1=O
15
- # 2-methylcyclohexa-2,5-diene-1,4-dione
16
-
17
- #let(:test_mol) { "COP(=O)(O)OCNCOCC(OO)C(=O)O" }
18
-
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
-
24
- describe 'cod: carbonyl appendage dump' do
25
- # a primary oxygen or peroxide => C=O appendage dump
26
-
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' 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
- end
68
-
69
- specify 'ester to ions' do
70
- mol = Rubabel["CCOC(=O)CCN"]
71
- frag_set = mol.fragment(rules: [:oxe])
72
- ff = frag_set.first
73
- ff.first.csmiles.should == 'C[CH2+]'
74
- ff.last.csmiles.should == '[O-]C(=O)CC[NH3+]'
75
- ff.first.formula.should == "C2H5+"
76
-
77
- ff.last.formula.should == "C3H7NO2"
78
- ff.first.exact_mass.should be_within(1e-6).of(29.03912516035)
79
- ff.last.exact_mass.should be_within(1e-6).of(89.04767846841)
80
- end
81
-
82
- specify 'carboxyl group' do
83
- mol = Rubabel["CCC(=O)O"]
84
- frag_set = mol.fragment(rules: [:oxe])
85
- ff = frag_set.first
86
- ff.first.csmiles.should == 'CC[C+]=O'
87
- # this is a carboxylate oxygen that falls off
88
- ff.last.csmiles.should == '[O-2]'
89
- #ff.first.formula.should == "C3H5O"
90
- ff.first.formula.should == "C3H5O+"
91
- ff.first.exact_mass.should be_within(1e-6).of(57.034039779909996)
92
- #ff.last.formula.should == "O"
93
- ff.last.formula.should == "O--"
94
- end
95
-
96
- specify 'phosphodiester' do
97
- mol = Rubabel["CC(COP(=O)([O-])OCCN"]
98
- frag_set = mol.fragment(rules: [:oxepd])
99
- ff = frag_set.first
100
- ff.first.csmiles.should == '[O-]CCC'
101
- #ff.last.csmiles.should == '[NH3+]CCO[P](=O)=O'
102
- ff.last.csmiles.should == "[NH3+]CCOP(=O)=O"
103
- #ff.first.formula.should == 'C3H7O'
104
- ff.first.formula.should == 'C3H7O-'
105
- ff.first.exact_mass.should be_within(1e-6).of(59.049689844)
106
- #ff.last.formula.should == 'C2H7NO3P'
107
- ff.last.formula.should == 'C2H7NO3P+'
108
- ff.last.exact_mass.should be_within(1e-6).of(124.016354719)
109
-
110
- mol = Rubabel["CCCOP(=O)(OCC[N+](C)(C)C)[O-]"]
111
- frag_set = mol.fragment(rules: [:oxepd, :oxe])
112
- # some of these don't like right on first inspection, but that is
113
- # because we 'converted dative bonds' meaning + and - next to each
114
- # other are allowed to cancel one another out!
115
- frag_set.size.should == 4
116
- mols = frag_set.flatten
117
- 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", "CCCOP(=O)=O", "[O-]CC[N+](C)(C)C"]
118
- mols.map(&:formula).should == ["C3H7+", "C5H13NO4P-", "C3H7O4P--", "C5H13N++", "C3H7O-", "C5H13NO3P+", "C3H7O3P", "C5H13NO"]
119
- mols.map(&:exact_mass).zip([43.05477522449, 182.05821952995, 138.00819533273, 87.10479942171, 59.04968984405, 166.06330491039, 122.01328071317, 103.09971404127]) do |act, exp|
120
- act.should be_within(1e-6).of(exp)
121
- end
122
-
123
- end
124
- end
125
-
126
- # this is really a subset of oxygen bond stealing: if the negatively
127
- # charged oxygen can rip off a nearby proton, it will.
128
- describe 'oxh: oxygen alpha/beta/gamma hydrogen stealing' do
129
- specify 'primary alcohol giving water loss' do
130
- mol = Rubabel["CC(O)CCN"]
131
- frags = mol.fragment(rules: [:oxh])
132
- ff = frags.first
133
- ff.first.csmiles.should == 'C=CCC[NH3+]'
134
- ff.last.csmiles.should == 'O'
135
- ll = frags.last
136
- ll.first.csmiles.should == 'CC=CC[NH3+]'
137
- ll.last.csmiles.should == 'O'
138
- #ff.first.formula.should == 'C4H10N'
139
- ff.first.formula.should == 'C4H10N+'
140
- ff.first.exact_mass.should be_within(1e-6).of(72.0813243255)
141
- end
142
-
143
- specify 'peroxide carbonyl formation (or peroxide formation [that what we want??])' do
144
- # do we really see peroxide formation? Tamil didn't include this in
145
- # the rules but it follows from the broad way for creating these
146
- # rules. Can prohibit peroxide formation in future if necessary...
147
- mol = Rubabel["CC(OO)CCN"]
148
- frags = mol.fragment(rules: [:oxh])
149
- mols = frags.flatten
150
- mols.map(&:csmiles).should == ["C=CCC[NH3+]", "OO", "CC(=O)CC[NH3+]", "O", "CC=CC[NH3+]", "OO"]
151
- mols.map(&:formula).should == ["C4H10N+", "H2O2", "C4H10NO+", "H2O", "C4H10N+", "H2O2"]
152
- #mols.map(&:formula).should == ["C4H10N", "H2O2", "C4H10NO", "H2O", "C4H10N", "H2O2"]
153
- mols.map(&:exact_mass).zip([72.081324325, 34.005479304, 88.076238945, 18.010564684, 72.081324325, 34.005479304]) do |act, exp|
154
- act.should be_within(1e-6).of(exp)
155
- end
156
- end
157
-
158
- specify 'ether to alcohol, ignoring errors' do
159
- # this is a good example of a 'disallowed structure' where the
160
- # formula's do not match up to the original formulas
161
- mol = Rubabel["CCOCCN"]
162
- frags = mol.fragment(rules: [:oxh], errors: :ignore)
163
- mols = frags.flatten
164
- mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]", "CCO", "C=C[NH2+]"]
165
- end
166
-
167
- specify 'ether to alcohol, removing errors' do
168
- mol = Rubabel["CCOCCN"]
169
- frags = mol.fragment(rules: [:oxh])
170
- mols = frags.flatten
171
- mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]"]
172
- end
173
-
174
- specify 'ester to alcohol' do
175
- mol = Rubabel["CC(=O)OCCCN"]
176
- frags = mol.fragment(rules: [:oxh])
177
- mols = frags.flatten
178
- mols.map(&:csmiles).should == ["C=C=O", "OCCC[NH3+]", "CC(=O)O", "C=CC[NH3+]"]
179
- #mols.map(&:formula).should == ["C2H2O", "C3H10NO", "C2H4O2", "C3H8N"]
180
- mols.map(&:formula).should == ["C2H2O", "C3H10NO+", "C2H4O2", "C3H8N+"]
181
- mols.map(&:exact_mass).zip([42.010564684, 76.076238945, 60.021129368000004, 58.065674261]) do |act,exp|
182
- act.should be_within(1e-6).of(exp)
183
- end
184
- end
185
-
186
- specify 'phosphodiester (right now needs very low pH and NOT SURE WORKING PROPERLY)' do
187
- mol = Rubabel["CC(COP(=O)(O)OCCCN"]
188
- mol.add_h!(1.0)
189
- frags = mol.fragment(rules: [:oxhpd])
190
- frags = frags.flatten
191
- frags.map(&:csmiles).should == ["CCCO", "[NH3+]CCCOP(=O)=O", "CCCOP(=O)=O", "OCCC[NH3+]"]
192
- end
193
- end
194
-
195
- end
196
- end
197
-
198
-
199
-