msplinter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +23 -0
- data/README.md +41 -0
- data/Rakefile +19 -0
- data/bin/msplinter +69 -0
- data/lib/msplinter/commandline.rb +1 -0
- data/lib/msplinter/version.rb +3 -0
- data/lib/msplinter.rb +4 -0
- data/lib/rubabel/molecule/fragmentable.rb +160 -0
- data/msplinter.gemspec +36 -0
- data/spec/rubabel/molecule/fragmentable_spec.rb +200 -0
- data/spec/spec_helper.rb +28 -0
- metadata +146 -0
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
data/Gemfile
ADDED
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
|
+
|
data/lib/msplinter.rb
ADDED
@@ -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
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -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:
|