mspire 0.7.13 → 0.7.17

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.13
1
+ 0.7.17
@@ -107,12 +107,12 @@ module Mspire
107
107
  class Isotope
108
108
  module Distribution
109
109
  def self.calculate(molecular_formula_like, normalize=Mspire::Isotope::Distribution::NORMALIZE, percent_cutoff=nil)
110
- mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.new(molecular_formula_like)
110
+ mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.from_any(molecular_formula_like)
111
111
  mf.isotope_distribution(normalize, percent_cutoff)
112
112
  end
113
113
 
114
114
  def self.spectrum(molecular_formula_like, normalize=Mspire::Isotope::Distribution::NORMALIZE, percent_cutoff=nil)
115
- mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.new(molecular_formula_like)
115
+ mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.from_any(molecular_formula_like)
116
116
  mf.isotope_distribution_spectrum(normalize, percent_cutoff)
117
117
  end
118
118
  end
data/lib/mspire/mass.rb CHANGED
@@ -4,11 +4,10 @@ require 'mspire/molecular_formula'
4
4
  module Mspire
5
5
  module Mass
6
6
 
7
- # takes a molecular formula in this format: C2BrH12O
7
+ # takes a molecular formula as a string, hash or MolecularFormula object
8
+ # and returns the exact mass.
8
9
  def self.formula_to_exact_mass(formula)
9
- Mspire::MolecularFormula.new(formula).map do |el,cnt|
10
- MONO[el] * cnt
11
- end.reduce(:+)
10
+ Mspire::MolecularFormula.from_any(formula).mass
12
11
  end
13
12
 
14
13
  MONO_STR = {
@@ -4,46 +4,132 @@ require 'mspire/mass'
4
4
  module Mspire
5
5
  class MolecularFormula < Hash
6
6
 
7
+ class << self
8
+ def from_aaseq(aaseq)
9
+ hash = aaseq.each_char.inject({}) do |hash,aa|
10
+ hash.merge(Mspire::Isotope::AA::FORMULAS[aa]) {|h,o,n| (o ? o : 0) +n }
11
+ end
12
+ hash[:h] += 2
13
+ hash[:o] += 1
14
+ self.new(hash)
15
+ end
16
+
17
+ # takes a string, with properly capitalized elements making up the
18
+ # formula. The elements may be in any order.
19
+ def from_string(mol_form_str, charge=0)
20
+ mf = self.new({}, charge)
21
+ mol_form_str.scan(/([A-Z][a-z]?)(\d*)/).each do |k,v|
22
+ mf[k.downcase.to_sym] = (v == '' ? 1 : v.to_i)
23
+ end
24
+ mf
25
+ end
26
+
27
+ # arg may be a String, Hash, or MolecularFormula object.
28
+ def from_any(arg, charge=0)
29
+ if arg.is_a?(String)
30
+ from_string(arg, charge)
31
+ else
32
+ self.new(arg, arg.respond_to?(:charge) ? arg.charge : 0)
33
+ end
34
+ end
35
+ alias_method :[], :from_any
36
+
37
+ end
38
+
7
39
  # integer desribing the charge state
8
40
  # mass calculations will add/remove electron mass from this
9
41
  attr_accessor :charge
10
- # takes a string or a hash:
11
- #
12
- # "H22C12N1O3S2BeLi2" # <= order doesn't matter
42
+
43
+ # Takes a hash and an optional Integer expressing the charge
13
44
  # {h: 22, c: 12, n: 1, o: 3, s: 2} # case and string/sym doesn't matter
14
- def initialize(arg, charge=0)
45
+ def initialize(hash={}, charge=0)
15
46
  @charge = charge
16
- if arg.is_a?(String)
17
- arg.scan(/([A-Z][a-z]?)(\d*)/).each do |k,v|
18
- self[k.downcase.to_sym] = (v == '' ? 1 : v.to_i)
19
- end
20
- else
21
- self.merge!(arg)
22
- end
47
+ self.merge!(hash)
23
48
  end
24
49
 
25
50
  # returns a new formula object where all the atoms have been added up
26
51
  def +(*others)
27
- new_form = self.dup
28
- others.each do |form|
29
- new_form.merge!(form) {|key, oldval, newval| new_form[key] = oldval+newval }
52
+ self.dup.add!(*others)
53
+ end
54
+
55
+ # returns self
56
+ def add!(*others)
57
+ others.each do |other|
58
+ self.merge!(other) {|key, oldval, newval| self[key] = oldval + newval }
59
+ self.charge += other.charge
60
+ end
61
+ self
62
+ end
63
+
64
+ # returns a new formula object where all the formulas have been subtracted
65
+ # from the caller
66
+ def -(*others)
67
+ self.dup.sub!(*others)
68
+ end
69
+
70
+ def sub!(*others)
71
+ others.each do |other|
72
+ oth = other.dup
73
+ self.each do |k,v|
74
+ if oth.key?(k)
75
+ self[k] -= oth.delete(k)
76
+ end
77
+ end
78
+ oth.each do |k,v|
79
+ self[k] = -v
80
+ end
81
+ self.charge -= other.charge
82
+ end
83
+ self
84
+ end
85
+
86
+ def *(int)
87
+ self.dup.mul!(int)
88
+ end
89
+
90
+ def mul!(int, also_do_charge=true)
91
+ raise ArgumentError, "must be an integer" unless int.is_a?(Integer)
92
+ self.each do |k,v|
93
+ self[k] = v * int
30
94
  end
31
- new_form
95
+ self.charge *= int if also_do_charge
96
+ self
32
97
  end
33
98
 
34
- def self.from_aaseq(aaseq)
35
- hash = aaseq.each_char.inject({}) do |hash,aa|
36
- hash.merge(Mspire::Isotope::AA::FORMULAS[aa]) {|h,o,n| (o ? o : 0) +n }
99
+ def /(int)
100
+ self.dup.div!(int)
101
+ end
102
+
103
+ def div!(int, also_do_charge=true)
104
+ raise ArgumentError, "must be an integer" unless int.is_a?(Integer)
105
+ self.each do |k,v|
106
+ quotient, modulus = v.divmod(int)
107
+ raise ArgumentError "all numbers must be divisible by int" unless modulus == 0
108
+ self[k] = quotient
109
+ end
110
+ if also_do_charge
111
+ quotient, modulus = self.charge.divmod(int)
112
+ raise ArgumentError "charge must be divisible by int" unless modulus == 0
113
+ self.charge = quotient
37
114
  end
38
- hash[:h] += 2
39
- hash[:o] += 1
40
- self.new(hash)
115
+ self
41
116
  end
42
117
 
43
- # gives the monoisotopic mass adjusted by the current charge
44
- def mass
118
+ # gives the monoisotopic mass adjusted by the current charge (i.e.,
119
+ # adds/subtracts electron masses for the charges)
120
+ def mass(consider_electron_masses = true)
45
121
  mss = inject(0.0) {|sum,(el,cnt)| sum + (Mspire::Mass::MONO[el]*cnt) }
46
- mss - (Mspire::Mass::ELECTRON * charge)
122
+ mss -= (Mspire::Mass::ELECTRON * charge) if consider_electron_masses
123
+ mss
124
+ end
125
+
126
+ # returns nil if the charge == 0
127
+ def mz(consider_electron_masses = true)
128
+ if charge == 0
129
+ nil
130
+ else
131
+ mass(consider_electron_masses) / charge
132
+ end
47
133
  end
48
134
 
49
135
  def to_s(alphabetize=true)
@@ -49,7 +49,7 @@ describe 'Mspire::Isotope::Distribution class methods' do
49
49
  end
50
50
 
51
51
  it 'gives proper m/z values if the molecule is charged' do
52
- charged_molecule = Mspire::MolecularFormula.new( subject )
52
+ charged_molecule = Mspire::MolecularFormula.from_any( subject )
53
53
  charged_molecule.charge = -3
54
54
  spec = Mspire::Isotope::Distribution.spectrum( charged_molecule )
55
55
  [:mzs, :intensities].each {|att| spec.send(att).size.should == 253 }
@@ -2,52 +2,109 @@ require 'spec_helper'
2
2
 
3
3
  require 'mspire/molecular_formula'
4
4
 
5
+ MF = Mspire::MolecularFormula
5
6
  describe Mspire::MolecularFormula do
6
7
 
7
- it 'can be initialized with a String or Hash' do
8
- data = {h: 22, c: 12, n: 1, o: 3, s: 2}
9
- mf = Mspire::MolecularFormula.new "H22BeC12N1O3S2Li2"
10
- mf.to_hash.should == {:h=>22, :be=>1, :c=>12, :n=>1, :o=>3, :s=>2, :li=>2}
11
- mf = Mspire::MolecularFormula.new(data)
12
- mf.to_hash.should == data
13
- end
8
+ describe 'initialization' do
14
9
 
15
- it 'can be initialized with charge, too' do
16
- mf = Mspire::MolecularFormula.new "H22BeC12N1O3S2Li2", 2
17
- mf.to_hash.should == {:h=>22, :be=>1, :c=>12, :n=>1, :o=>3, :s=>2, :li=>2}
18
- mf.charge.should == 2
19
- end
10
+ it 'is initialized with Hash' do
11
+ data = {h: 22, c: 12, n: 1, o: 3, s: 2}
12
+ mf = Mspire::MolecularFormula.new(data)
13
+ mf.to_hash.should == {:h=>22, :c=>12, :n=>1, :o=>3, :s=>2}
14
+ mf.to_hash.should == data
15
+ end
20
16
 
21
- it 'expects properly capitalized abbreviations' do
22
- Mspire::MolecularFormula.new('Ni7Se3').to_hash.should == {:ni=>7, :se=>3}
23
- # there is no such thing as the E element, so this is going to get the
24
- # user in trouble. However, this is the proper interpretation of the
25
- # formula.
26
- Mspire::MolecularFormula.new('Ni7SE3').to_hash.should == {:ni=>7, :s=>1, :e=>3}
27
- end
17
+ it 'can be initialized with charge, too' do
18
+ mf = Mspire::MolecularFormula["H22BeC12N1O3S2Li2", 2]
19
+ mf.to_hash.should == {:h=>22, :be=>1, :c=>12, :n=>1, :o=>3, :s=>2, :li=>2}
20
+ mf.charge.should == 2
21
+ end
22
+
23
+ it 'from_string or ::[] to make from a capitalized string formula' do
24
+ Mspire::MolecularFormula.from_string("H22BeC12N1O3S2Li2").to_hash.should == {:h=>22, :be=>1, :c=>12, :n=>1, :o=>3, :s=>2, :li=>2}
25
+
26
+ mf = Mspire::MolecularFormula['Ni7Se3', 1]
27
+ mf.charge.should == 1
28
+ mf.to_hash.should == {:ni=>7, :se=>3}
29
+
30
+ # there is no such thing as the E element, so this is going to get the
31
+ # user in trouble. However, this is the proper interpretation of the
32
+ # formula.
33
+ Mspire::MolecularFormula['Ni7SE3'].to_hash.should == {:ni=>7, :s=>1, :e=>3}
34
+ end
28
35
 
29
- describe 'an object' do
30
-
31
- subject {
32
- data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
33
- Mspire::MolecularFormula.new(data)
34
- }
36
+ describe 'conversion' do
35
37
 
36
- it 'the string output is a standard molecular formula' do
37
- subject.to_s.should == "BeC12H22NO3S2"
38
+ subject {
39
+ data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
40
+ Mspire::MolecularFormula.new(data)
41
+ }
42
+
43
+ it 'the string output is a standard molecular formula' do
44
+ subject.to_s.should == "BeC12H22NO3S2"
45
+ end
46
+
47
+ it 'can be converted to a hash' do
48
+ subject.to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
49
+ end
38
50
  end
39
51
 
40
- it 'can be converted to a hash' do
41
- subject.to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
52
+ describe 'equality' do
53
+ subject {
54
+ data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
55
+ Mspire::MolecularFormula.new(data)
56
+ }
57
+ it 'is only equal if the charge is equal' do
58
+ another = subject.dup
59
+ another.should == subject
60
+ another.charge = 2
61
+ another.should_not == subject
62
+ end
42
63
  end
43
64
 
44
- it 'is only equal if the charge is equal' do
45
- another = subject.dup
46
- another.should == subject
47
- another.charge = 2
48
- another.should_not == subject
65
+ describe 'arithmetic' do
66
+ subject {
67
+ data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
68
+ Mspire::MolecularFormula.new(data, 2)
69
+ }
70
+ it 'can do non-destructive arithmetic' do
71
+ orig = subject.dup
72
+ reply = subject + MF["H2C3P2", 2]
73
+ reply.to_hash.should == {h: 24, c: 15, n: 1, o: 3, s: 2, be: 1, p: 2}
74
+ reply.charge.should == 4
75
+ subject.should == orig
76
+
77
+ reply = subject - MF["H2C3P2", 2]
78
+ reply.to_hash.should == {h: 20, c: 9, n: 1, o: 3, s: 2, be: 1, p: -2}
79
+ reply.charge.should == 0
80
+ subject.should == orig
81
+
82
+ by2 = subject * 2
83
+ by2.to_hash.should == {h: 44, c: 24, n: 2, o: 6, s: 4, be: 2}
84
+ by2.charge.should == 4
85
+ subject.should == orig
86
+
87
+ reply = by2 / 2
88
+ reply.to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
89
+ reply.charge.should == 2
90
+ subject.should == orig
91
+ end
92
+
93
+ it 'can do destructive arithmetic' do
94
+ orig = subject.dup
95
+ subject.sub!(MF["H2C3"]).to_hash.should == {h: 20, c: 9, n: 1, o: 3, s: 2, be: 1}
96
+ subject.should_not == orig
97
+ subject.add!(MF["H2C3"]).to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
98
+ subject.should == orig
99
+
100
+ by2 = subject.mul!(2)
101
+ subject.should_not == orig
102
+ by2.to_hash.should == {h: 44, c: 24, n: 2, o: 6, s: 4, be: 2}
103
+ by2.div!(2).to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
104
+ by2.to_hash.should == orig
105
+ end
106
+
49
107
  end
50
108
 
51
109
  end
52
-
53
110
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mspire
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.13
4
+ version: 0.7.17
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -390,7 +390,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
390
390
  version: '0'
391
391
  requirements: []
392
392
  rubyforge_project:
393
- rubygems_version: 1.8.18
393
+ rubygems_version: 1.8.24
394
394
  signing_key:
395
395
  specification_version: 3
396
396
  summary: mass spectrometry proteomics, lipidomics, and tools