msplinter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 549e4f5c83a9065e97cc542ee98a6c69c54d0443
4
+ data.tar.gz: a93e6a4567344e57b8a6d3bdfc86bb766200118d
5
+ SHA512:
6
+ metadata.gz: 4b705b21e3db91c1f5b9862b4b02a01d09140b1b827244c98cf86e89bd1ce6558a169c6a8b3f702b553aa2f7d4094ffa81952cef83c138cb519183bc4e431dc9
7
+ data.tar.gz: 38695117916f6328b555d78338d114a8994ae859b0bbb604fba059ed08eb9498f8eadddc530a220ea6e6a56d3cca905f60ff9389737c518dc1fe09f16e2b1754
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ coverage
2
+ .coveralls.yml
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in msplinter.gemspec
4
+ gemspec
5
+
6
+ gem 'coveralls', require: false
data/LICENSE.txt ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2013 Brigham Young University
2
+ Authored by: John T. Prince
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # msplinter
2
+
3
+ [![Gem Version][GV img]][Gem Version]
4
+ [![Dependency Status][DS img]][Dependency Status]
5
+ [![Code Climate][CC img]][Code Climate]
6
+ [![Coverage Status][CS img]][Coverage Status]
7
+
8
+ Predicts how molecules will fragment in a mass spectrometer. Currently
9
+ focused on lipid fragmentation under CID, HCD or PQD.
10
+
11
+ ## Installation
12
+
13
+ msplinter is built on rubabel, which is built on openbabel. To get the
14
+ necessary openbabel dependencies on ubuntu/debian:
15
+
16
+ sudo apt-get install openbabel libopenbabel-dev cmake make curl
17
+
18
+ Then
19
+
20
+ gem install msplinter
21
+
22
+ See [the "Installing" section](https://github.com/princelab/rubabel) for
23
+ complete instructions for installing rubabel and openbabel.
24
+
25
+ ## Commandline Usage
26
+
27
+ Type 'msplinter' with no arguments to see a help message.
28
+
29
+ ## Copyright
30
+
31
+ MIT license. See LICENSE.txt for further details.
32
+
33
+ [Gem Version]: https://rubygems.org/gems/msplinter
34
+ [Dependency Status]: https://gemnasium.com/princelab/msplinter
35
+ [Code Climate]: https://codeclimate.com/github/princelab/msplinter
36
+ [Coverage Status]: https://coveralls.io/r/princelab/msplinter
37
+
38
+ [GV img]: https://badge.fury.io/rb/msplinter.png
39
+ [DS img]: https://gemnasium.com/princelab/msplinter.png
40
+ [CC img]: https://codeclimate.com/github/princelab/msplinter.png
41
+ [CS img]: https://coveralls.io/repos/princelab/msplinter/badge.png?branch=master
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
8
+
9
+ task :default => :spec
10
+
11
+ require 'rdoc/task'
12
+ Rake::RDocTask.new do |rdoc|
13
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
14
+
15
+ rdoc.rdoc_dir = 'rdoc'
16
+ rdoc.title = "rubabel #{version}"
17
+ rdoc.rdoc_files.include('README*')
18
+ rdoc.rdoc_files.include('lib/**/*.rb')
19
+ end
data/bin/msplinter ADDED
@@ -0,0 +1,69 @@
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
+ progname = File.basename(__FILE__)
12
+
13
+ parser = Trollop::Parser.new do
14
+ banner "usage: #{progname} [OPTIONS|RULES] <SMARTS> ..."
15
+ text "\noptions:"
16
+ opt :ph, "the pH to use (experimental option)", :default => default_ph
17
+ opt :images, "print out svg images of fragments"
18
+ opt :format, "format of the molecules", :default => 'smiles'
19
+ #opt :uniq, "no repeated fragments", :default => false
20
+ text "\nrules:"
21
+ Rubabel::Molecule::Fragmentable::RULES.each do |rule|
22
+ opt rule, rule.to_s.gsub("_",' ')
23
+ end
24
+ text "\nexample:"
25
+ text " #{progname} -xeh 'CCC(=O)OCCC' 'CCC(=O)OCCC(=O)O'"
26
+ end
27
+
28
+ options = parser.parse(ARGV)
29
+ opts = {rules: []}
30
+ opts[:uniq] = options.delete(:uniq)
31
+ ph = options.delete(:ph)
32
+ opts[:rules] = Rubabel::Molecule::Fragmentable::RULES.map do |rule|
33
+ rule if options["#{rule}_given".to_sym]
34
+ end.compact
35
+
36
+ if ARGV.size == 0
37
+ parser.educate && exit
38
+ end
39
+
40
+ ARGV.each do |smiles|
41
+ mol = Rubabel[smiles, options[:format].to_sym]
42
+ puts "\nmolecule: #{mol.csmiles}"
43
+ mol.correct_for_ph!(ph)
44
+ puts "at ph #{ph}: #{mol.csmiles}"
45
+ fragment_sets = mol.fragment(opts)
46
+ puts %w(mz mass charge title smiles pairing).join("\t")
47
+ frags = []
48
+ fragment_sets.each_with_index do |frag_set,i|
49
+ frag_set.each_with_index do |frag,j|
50
+ unless frag.charge == 0
51
+ mz = (frag.mass / frag.charge).round(5)
52
+ end
53
+
54
+ frag.title = "#{i}-#{j}pair_" + (mz ? "#{mz}_mz" : "#{frag.mass.round(3)}_Mass")
55
+ frag_obj = Fragment.new(frag, frag.title, frag.title, mz, frag.exact_mass, frag.charge, frag.csmiles, i)
56
+ frags << frag_obj
57
+ end
58
+ end
59
+ frags = frags.sort_by {|frag| [-frag.charge, frag.mz] }
60
+ if options[:images]
61
+ frags.each do |frag|
62
+ fn = "#{frag.title}.svg"
63
+ frag.frag.write(fn)
64
+ end
65
+ end
66
+ frags.each do |frag|
67
+ puts [:mz, :mass, :charge, :title, :smiles, :pairing].map {|cat| frag.send(cat) }.join("\t")
68
+ end
69
+ end
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,3 @@
1
+ module Msplinter
2
+ VERSION = "0.0.1"
3
+ end
data/lib/msplinter.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "msplinter/version"
2
+
3
+ module Msplinter
4
+ end
@@ -0,0 +1,160 @@
1
+ require 'set'
2
+
3
+ module Rubabel
4
+ class Molecule
5
+ module Fragmentable
6
+
7
+ #RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh]
8
+ RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh, :oxhpd]
9
+
10
+ DEFAULT_OPTIONS = {
11
+ rules: RULES,
12
+ errors: :remove,
13
+ # return only the set of unique fragments
14
+ uniq: false,
15
+ }
16
+
17
+ # molecules and fragments should all have hydrogens added (add_h!)
18
+ # before calling this method
19
+ #
20
+ # For instance, water loss with double bond formation is not allowable
21
+ # for NCC(O)CC => CCC=C[NH2+], presumably because of the lone pair and
22
+ # double bond resonance.
23
+ def allowable_fragmentation?(frags)
24
+ self.num_atoms(true) == frags.reduce(0) {|cnt,fr| cnt + fr.num_atoms(true) }
25
+ end
26
+
27
+ # splits the molecule between the carbon and carbon_nbr, adds a double
28
+ # bond between the carbon and oxygen, and moves whatever was on the
29
+ # oxygen (e.g., an OH or a charge) to the carbon_nbr. Returns two new
30
+ # molecules.
31
+ def carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
32
+ appendage = oxygen.atoms.find {|a| a.el != :C }
33
+ if oxygen.charge != 0
34
+ ocharge = oxygen.charge
35
+ end
36
+ nmol = self.dup
37
+ new_oxygen = nmol.atom(oxygen.id)
38
+ new_carbon = nmol.atom(carbon.id)
39
+ new_carbon_nbr = nmol.atom(carbon_nbr.id)
40
+ new_appendage = nmol.atom(appendage.id) if appendage
41
+ nmol.delete_bond(new_carbon.get_bond(new_carbon_nbr))
42
+ if new_appendage
43
+ nmol.delete_bond(new_oxygen.get_bond(new_appendage))
44
+ nmol.add_bond!(new_carbon_nbr, new_appendage)
45
+ end
46
+ if ocharge
47
+ new_carbon_nbr.charge += ocharge
48
+ new_oxygen.charge -= ocharge
49
+ end
50
+ new_carbon.get_bond(new_oxygen).bond_order = 2
51
+ nmol.split
52
+ end
53
+
54
+ # breaks the bond and gives the electrons to the oxygen
55
+ def carbon_oxygen_esteal(carbon, oxygen)
56
+ nmol = self.dup
57
+ ncarbon = nmol.atom(carbon.id)
58
+ noxygen = nmol.atom(oxygen.id)
59
+
60
+ is_carboxyl = noxygen.carboxyl_oxygen?
61
+
62
+ nmol.delete_bond(ncarbon, noxygen)
63
+ ncarbon.remove_a_hydride!
64
+ noxygen.remove_a_proton!
65
+ nmol.split
66
+ end
67
+
68
+ # returns the duplicated molecule and the equivalent atoms
69
+ def dup_molecule(atoms=[])
70
+ nmol = self.dup
71
+ [nmol, atoms.map {|old_atom| nmol.atom(old_atom.id) }]
72
+ end
73
+
74
+ # returns molecules created from splitting between the electrophile and
75
+ # the center and where the bond order is increased between the center
76
+ # and center_nbr
77
+ def break_with_double_bond(electrophile, center, center_nbr)
78
+ (nmol, (nele, ncarb, ncarb_nbr)) = self.dup_molecule([electrophile, center, center_nbr])
79
+ nmol.delete_bond(nele, ncarb)
80
+ ncarb_nbr.get_bond(ncarb) + 1
81
+ nmol.split
82
+ end
83
+
84
+ # an empty array is returned if there are no fragments generated.
85
+ # Hydrogens are added at a pH of 7.4, unless they have already been
86
+ # added.
87
+ #
88
+ # :rules => queryable by :include? set of rules
89
+ # :uniq => false
90
+ # :errors => :remove | :fix | :ignore (default is :remove)
91
+ def fragment(opts={})
92
+ only_uniqs = true
93
+ opts = DEFAULT_OPTIONS.merge(opts)
94
+ opts[:rules].each do |rule|
95
+ raise ArgumentError, "bad rule: #{rule}" unless RULES.include?(rule)
96
+ end
97
+
98
+ had_hydrogens = self.h_added?
99
+ self.correct_for_ph!(7.4) unless had_hydrogens
100
+ self.remove_h!
101
+
102
+ fragment_sets = []
103
+
104
+ if opts[:rules].any? {|r| [:cod, :codoo].include?(r) }
105
+ self.each_match("C[O;h1,O]", only_uniqs) do |carbon, oxygen|
106
+ carbon.atoms.select {|a| a.el == :C }.each do |carbon_nbr|
107
+ fragment_sets << carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
108
+ end
109
+ end
110
+ end
111
+ if opts[:rules].any? {|r| [:oxe].include?(r) }
112
+ self.each_match("C-O", only_uniqs) do |carbon, oxygen|
113
+ fragment_sets << carbon_oxygen_esteal(carbon, oxygen)
114
+ end
115
+ end
116
+ # right now implemented so that a beta hydrogen has to be availabe for
117
+ # extraction
118
+ if opts[:rules].any? {|r| [:oxh].include?(r) }
119
+ self.each_match("C[C,O]-O", only_uniqs) do |beta_c, center, oxygen|
120
+ next unless beta_c.hydrogen_count > 0
121
+ fragment_sets << break_with_double_bond(oxygen, center, beta_c)
122
+ end
123
+ end
124
+ if opts[:rules].any? {|r| [:oxhpd].include?(r) }
125
+ self.each_match("C-O-P-O", only_uniqs) do |carbon, alc_oxy, phosphate, beta_carb_oxy|
126
+ next unless beta_carb_oxy.hydrogen_count > 0
127
+ frag_set = break_with_double_bond(alc_oxy, phosphate, beta_carb_oxy)
128
+ frag_set.map! &:convert_dative_bonds!
129
+ fragment_sets << frag_set
130
+ end
131
+ end
132
+ if opts[:rules].any? {|r| [:oxepd].include?(r) }
133
+ self.each_match("P-O-C", only_uniqs) do |phosphate, oxygen, carbon|
134
+ frag_set = carbon_oxygen_esteal(phosphate, oxygen)
135
+ frag_set.map! &:convert_dative_bonds!
136
+ fragment_sets << frag_set
137
+ end
138
+ end
139
+
140
+ case opts[:errors]
141
+ when :remove
142
+ fragment_sets.select! {|set| allowable_fragmentation?(set) }
143
+ when :fix
144
+ raise NotImplementedError
145
+ when :ignore # do nothing
146
+ end
147
+
148
+ self.remove_h!
149
+ if opts[:uniq]
150
+ # TODO: impelent properly
151
+ raise NotImplementedError
152
+ #fragment_sets = fragment_sets.uniq_by(&:csmiles)
153
+ end
154
+
155
+ fragment_sets
156
+ end
157
+ end
158
+ include Fragmentable
159
+ end
160
+ end # Rubabel
data/msplinter.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'msplinter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "msplinter"
8
+ spec.version = Msplinter::VERSION
9
+ spec.authors = ["John T. Prince"]
10
+ spec.email = ["jtprince@gmail.com"]
11
+ spec.description = %q{Predicts how molecules will fragment in a mass spectrometer. Currently focused on lipid fragmentation under CID, HCD or PQD.}
12
+ spec.summary = %q{Predicts how molecules will fragment in a mass spectrometer}
13
+ spec.homepage = "https://github.com/princelab/msplinter"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ [
22
+ ["rubabel", "~> 0.4.1"],
23
+ ].each do |args|
24
+ spec.add_dependency(*args)
25
+ end
26
+ [
27
+ ["bundler", "~> 1.3"],
28
+ ["rake"],
29
+ ["rspec", "~> 2.13.0"],
30
+ ["rdoc", "~> 3.12"],
31
+ ["simplecov"],
32
+ ].each do |args|
33
+ spec.add_development_dependency(*args)
34
+ end
35
+
36
+ end
@@ -0,0 +1,200 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rubabel'
4
+ require 'rubabel/molecule/fragmentable'
5
+
6
+ $VERBOSE = nil
7
+
8
+ describe Rubabel::Molecule::Fragmentable do
9
+
10
+ # :peroxy_to_carboxy
11
+ # :oxygen_asymmetric_sp3, :nitrogen_asymmetric_sp3,
12
+ # :internal_phosphoester
13
+
14
+ describe 'fragmentation rules' do
15
+ # coenzyme: CC1=CC(=O)C=CC1=O
16
+ # 2-methylcyclohexa-2,5-diene-1,4-dione
17
+
18
+ #let(:test_mol) { "COP(=O)(O)OCNCOCC(OO)C(=O)O" }
19
+
20
+ it 'raises an error for a bad rule' do
21
+ mol = Rubabel["CCNC"]
22
+ expect { mol.fragment(rules: [:wackiness]) }.to raise_error
23
+ end
24
+
25
+ describe 'cod: carbonyl appendage dump' do
26
+ # a primary oxygen or peroxide => C=O appendage dump
27
+
28
+ specify 'cod: primary alcohol' do
29
+ mol = Rubabel["NCC(O)CC"]
30
+ frags = mol.fragment(rules: [:cod])
31
+ frags.flatten(1).map(&:csmiles).should == ["C[NH3+]", "CCC=O", "C([NH3+])C=O", "CC"]
32
+ end
33
+
34
+ specify 'peroxide' do
35
+ mol = Rubabel["NCC(OO)CC"]
36
+ frags = mol.fragment(rules: [:codoo])
37
+ frags.flatten(1).map(&:csmiles).should == ["OC[NH3+]", "CCC=O", "C([NH3+])C=O", "CCO"]
38
+ end
39
+
40
+ specify 'cod: carboxylate' do
41
+ mol = Rubabel["CCC(=O)O"]
42
+ pieces = mol.fragment(rules: [:cod])
43
+ pieces.flatten(1).map(&:csmiles).should == ["[CH2-]C", "O=C=O"]
44
+ end
45
+
46
+ specify 'cod: carboxylic acid' do
47
+ mol = Rubabel["CCC(=O)O"]
48
+ mol.add_h!(1.5)
49
+ pieces = mol.fragment(rules: [:cod])
50
+ pieces.flatten(1).map(&:csmiles).should == ["CC", "O=C=O"]
51
+ end
52
+ end
53
+
54
+ describe 'oxe: oxygen electron stealing' do
55
+ # oxygen just steals the electron pair it is attached to. This
56
+ # typically results in a negatively charged oxygen and a positively
57
+ # charged carbo-cation.
58
+ specify 'ether to ions' do
59
+ mol = Rubabel["CCOCCN"]
60
+ frag_set = mol.fragment(rules: [:oxe])
61
+ frags = frag_set.first
62
+ frags.first.csmiles.should == "C[CH2+]"
63
+ frags.last.csmiles.should == '[O-]CC[NH3+]'
64
+ frags.first.formula.should == 'C2H5+'
65
+ frags.last.formula.should == 'C2H7NO'
66
+ frags.first.exact_mass.should be_within(1e-6).of(29.03912516)
67
+ frags.last.exact_mass.should be_within(1e-6).of(61.052763849)
68
+ end
69
+
70
+ specify 'ester to ions' do
71
+ mol = Rubabel["CCOC(=O)CCN"]
72
+ frag_set = mol.fragment(rules: [:oxe])
73
+ ff = frag_set.first
74
+ ff.first.csmiles.should == 'C[CH2+]'
75
+ ff.last.csmiles.should == '[O-]C(=O)CC[NH3+]'
76
+ ff.first.formula.should == "C2H5+"
77
+
78
+ ff.last.formula.should == "C3H7NO2"
79
+ ff.first.exact_mass.should be_within(1e-6).of(29.03912516035)
80
+ ff.last.exact_mass.should be_within(1e-6).of(89.04767846841)
81
+ end
82
+
83
+ specify 'carboxyl group' do
84
+ mol = Rubabel["CCC(=O)O"]
85
+ frag_set = mol.fragment(rules: [:oxe])
86
+ ff = frag_set.first
87
+ ff.first.csmiles.should == 'CC[C+]=O'
88
+ # this is a carboxylate oxygen that falls off
89
+ ff.last.csmiles.should == '[O-2]'
90
+ #ff.first.formula.should == "C3H5O"
91
+ ff.first.formula.should == "C3H5O+"
92
+ ff.first.exact_mass.should be_within(1e-6).of(57.034039779909996)
93
+ #ff.last.formula.should == "O"
94
+ ff.last.formula.should == "O--"
95
+ end
96
+
97
+ specify 'phosphodiester' do
98
+ mol = Rubabel["CC(COP(=O)([O-])OCCN"]
99
+ frag_set = mol.fragment(rules: [:oxepd])
100
+ ff = frag_set.first
101
+ ff.first.csmiles.should == '[O-]CCC'
102
+ #ff.last.csmiles.should == '[NH3+]CCO[P](=O)=O'
103
+ ff.last.csmiles.should == "[NH3+]CCOP(=O)=O"
104
+ #ff.first.formula.should == 'C3H7O'
105
+ ff.first.formula.should == 'C3H7O-'
106
+ ff.first.exact_mass.should be_within(1e-6).of(59.049689844)
107
+ #ff.last.formula.should == 'C2H7NO3P'
108
+ ff.last.formula.should == 'C2H7NO3P+'
109
+ ff.last.exact_mass.should be_within(1e-6).of(124.016354719)
110
+
111
+ mol = Rubabel["CCCOP(=O)(OCC[N+](C)(C)C)[O-]"]
112
+ frag_set = mol.fragment(rules: [:oxepd, :oxe])
113
+ # some of these don't like right on first inspection, but that is
114
+ # because we 'converted dative bonds' meaning + and - next to each
115
+ # other are allowed to cancel one another out!
116
+ frag_set.size.should == 4
117
+ mols = frag_set.flatten
118
+ 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"]
119
+ mols.map(&:formula).should == ["C3H7+", "C5H13NO4P-", "C3H7O4P--", "C5H13N++", "C3H7O-", "C5H13NO3P+", "C3H7O3P", "C5H13NO"]
120
+ mols.map(&:exact_mass).zip([43.05477522449, 182.05821952995, 138.00819533273, 87.10479942171, 59.04968984405, 166.06330491039, 122.01328071317, 103.09971404127]) do |act, exp|
121
+ act.should be_within(1e-6).of(exp)
122
+ end
123
+
124
+ end
125
+ end
126
+
127
+ # this is really a subset of oxygen bond stealing: if the negatively
128
+ # charged oxygen can rip off a nearby proton, it will.
129
+ describe 'oxh: oxygen alpha/beta/gamma hydrogen stealing' do
130
+ specify 'primary alcohol giving water loss' do
131
+ mol = Rubabel["CC(O)CCN"]
132
+ frags = mol.fragment(rules: [:oxh])
133
+ ff = frags.first
134
+ ff.first.csmiles.should == 'C=CCC[NH3+]'
135
+ ff.last.csmiles.should == 'O'
136
+ ll = frags.last
137
+ ll.first.csmiles.should == 'CC=CC[NH3+]'
138
+ ll.last.csmiles.should == 'O'
139
+ #ff.first.formula.should == 'C4H10N'
140
+ ff.first.formula.should == 'C4H10N+'
141
+ ff.first.exact_mass.should be_within(1e-6).of(72.0813243255)
142
+ end
143
+
144
+ specify 'peroxide carbonyl formation (or peroxide formation [that what we want??])' do
145
+ # do we really see peroxide formation? Tamil didn't include this in
146
+ # the rules but it follows from the broad way for creating these
147
+ # rules. Can prohibit peroxide formation in future if necessary...
148
+ mol = Rubabel["CC(OO)CCN"]
149
+ frags = mol.fragment(rules: [:oxh])
150
+ mols = frags.flatten
151
+ mols.map(&:csmiles).should == ["C=CCC[NH3+]", "OO", "CC(=O)CC[NH3+]", "O", "CC=CC[NH3+]", "OO"]
152
+ mols.map(&:formula).should == ["C4H10N+", "H2O2", "C4H10NO+", "H2O", "C4H10N+", "H2O2"]
153
+ #mols.map(&:formula).should == ["C4H10N", "H2O2", "C4H10NO", "H2O", "C4H10N", "H2O2"]
154
+ mols.map(&:exact_mass).zip([72.081324325, 34.005479304, 88.076238945, 18.010564684, 72.081324325, 34.005479304]) do |act, exp|
155
+ act.should be_within(1e-6).of(exp)
156
+ end
157
+ end
158
+
159
+ specify 'ether to alcohol, ignoring errors' do
160
+ # this is a good example of a 'disallowed structure' where the
161
+ # formula's do not match up to the original formulas
162
+ mol = Rubabel["CCOCCN"]
163
+ frags = mol.fragment(rules: [:oxh], errors: :ignore)
164
+ mols = frags.flatten
165
+ mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]", "CCO", "C=C[NH2+]"]
166
+ end
167
+
168
+ specify 'ether to alcohol, removing errors' do
169
+ mol = Rubabel["CCOCCN"]
170
+ frags = mol.fragment(rules: [:oxh])
171
+ mols = frags.flatten
172
+ mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]"]
173
+ end
174
+
175
+ specify 'ester to alcohol' do
176
+ mol = Rubabel["CC(=O)OCCCN"]
177
+ frags = mol.fragment(rules: [:oxh])
178
+ mols = frags.flatten
179
+ mols.map(&:csmiles).should == ["C=C=O", "OCCC[NH3+]", "CC(=O)O", "C=CC[NH3+]"]
180
+ #mols.map(&:formula).should == ["C2H2O", "C3H10NO", "C2H4O2", "C3H8N"]
181
+ mols.map(&:formula).should == ["C2H2O", "C3H10NO+", "C2H4O2", "C3H8N+"]
182
+ mols.map(&:exact_mass).zip([42.010564684, 76.076238945, 60.021129368000004, 58.065674261]) do |act,exp|
183
+ act.should be_within(1e-6).of(exp)
184
+ end
185
+ end
186
+
187
+ specify 'phosphodiester (right now needs very low pH and NOT SURE WORKING PROPERLY)' do
188
+ mol = Rubabel["CC(COP(=O)(O)OCCCN"]
189
+ mol.add_h!(1.0)
190
+ frags = mol.fragment(rules: [:oxhpd])
191
+ frags = frags.flatten
192
+ frags.map(&:csmiles).should == ["CCCO", "[NH3+]CCCOP(=O)=O", "CCCOP(=O)=O", "OCCC[NH3+]"]
193
+ end
194
+ end
195
+
196
+ end
197
+ end
198
+
199
+
200
+
@@ -0,0 +1,28 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ require 'rspec'
5
+ require 'stringio'
6
+
7
+ require 'rspec/core/formatters/progress_formatter'
8
+ # doesn't say so much about pending guys
9
+ class QuietPendingFormatter < RSpec::Core::Formatters::ProgressFormatter
10
+ def example_pending(example)
11
+ output.print pending_color('*')
12
+ end
13
+ end
14
+
15
+ require 'rspec/core/formatters/documentation_formatter'
16
+ class QuietPendingDocFormatter < RSpec::Core::Formatters::DocumentationFormatter
17
+ def example_pending(example)
18
+ output.puts pending_color( "<pending>: #{example.execution_result[:pending_message]}" )
19
+ end
20
+ end
21
+
22
+ RSpec.configure do |config|
23
+ config.treat_symbols_as_metadata_keys_with_true_values = true
24
+ config.formatter = QuietPendingDocFormatter
25
+ config.color = true
26
+ end
27
+
28
+ TESTFILES = File.dirname(__FILE__) + "/testfiles"
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: msplinter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - John T. Prince
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubabel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.13.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 2.13.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdoc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '3.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '3.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
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
+ description: Predicts how molecules will fragment in a mass spectrometer. Currently
98
+ focused on lipid fragmentation under CID, HCD or PQD.
99
+ email:
100
+ - jtprince@gmail.com
101
+ executables:
102
+ - msplinter
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - .gitignore
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - bin/msplinter
112
+ - lib/msplinter.rb
113
+ - lib/msplinter/commandline.rb
114
+ - lib/msplinter/version.rb
115
+ - lib/rubabel/molecule/fragmentable.rb
116
+ - msplinter.gemspec
117
+ - spec/rubabel/molecule/fragmentable_spec.rb
118
+ - spec/spec_helper.rb
119
+ homepage: https://github.com/princelab/msplinter
120
+ licenses:
121
+ - MIT
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.0.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Predicts how molecules will fragment in a mass spectrometer
143
+ test_files:
144
+ - spec/rubabel/molecule/fragmentable_spec.rb
145
+ - spec/spec_helper.rb
146
+ has_rdoc: