mspire 0.7.13 → 0.7.17

Sign up to get free protection for your applications and to get access to all the features.
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