rubabel 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # rubabel
2
2
 
3
- Ruby interface to the openbabel ruby bindings (or the openbabel gem). The
3
+ Ruby interface to the OpenBabel ruby bindings (or the openbabel gem). The
4
4
  interface attempts to be a ruby-ish analogue of
5
- [pybel](http://openbabel.org/docs/current/UseTheLibrary/Python_PybelAPI.html).
5
+ [pybel](http://openbabel.org/docs/current/UseTheLibrary/Python_PybelAPI.html). Works with ruby 1.9 and 2.0.
6
6
 
7
7
  ## Examples
8
8
 
@@ -12,150 +12,185 @@ The [Chemistry Toolkit Rosetta Wiki](http://ctr.wikia.com/wiki/Chemistry_Toolkit
12
12
 
13
13
  #### From a string
14
14
 
15
- require 'rubabel'
15
+ ```ruby
16
+ require 'rubabel'
16
17
 
17
- # by default, reads in smiles strings
18
- serine = Rubabel["C(C(C(=O)O)N)O"]
19
- # more formally:
20
- serine = Rubabel::Molecule.from_string("C(C(C(=O)O)N)O")
18
+ # by default, reads in smiles strings
19
+ serine = Rubabel["C(C(C(=O)O)N)O"]
20
+ # more formally:
21
+ serine = Rubabel::Molecule.from_string("C(C(C(=O)O)N)O")
21
22
 
22
- # also any other format openbabel supports, for example inchi
23
- serine = Rubabel["InChI=1S/C3H7NO3/c4-2(1-5)3(6)7/h2,5H,1,4H2,(H,6,7)", :inchi]
23
+ # also any other format openbabel supports, for example inchi
24
+ serine = Rubabel["InChI=1S/C3H7NO3/c4-2(1-5)3(6)7/h2,5H,1,4H2,(H,6,7)", :inchi]
24
25
 
25
- # from the internet:
26
- mol = Rubabel[some_molecule, Rubabel.format_from_mime(some_mime_type)]
26
+ # from the internet:
27
+ mol = Rubabel[some_molecule, Rubabel.format_from_mime(some_mime_type)]
27
28
 
28
29
  Find out all the formats Rubabel supports (hash is format key pointing to the description):
29
30
 
30
- hash = Rubabel.in_formats
31
- hash = Rubabel.out_formats
31
+ hash = Rubabel.in_formats
32
+ hash = Rubabel.out_formats
33
+ ```
32
34
 
33
35
  #### From a file
34
36
 
35
37
  Reading multiple entries from a file:
36
38
 
37
- Rubabel.foreach("file.sdf") do |mol|
38
- puts mol.exact_mass
39
- end
39
+ ```ruby
40
+ Rubabel.foreach("file.sdf") do |mol|
41
+ puts mol.exact_mass
42
+ end
43
+ ```
40
44
 
41
45
  Foreach returns an enumerator that can be chained:
42
46
 
43
- # return an array of every unique atom type in the file
44
- uniq_atom_types = Rubabel.foreach("file.mol").flat_map {|mol| mol.map(&:type) }.uniq
47
+ ```ruby
48
+ # return an array of every unique atom type in the file
49
+ uniq_atom_types = Rubabel.foreach("file.mol").flat_map {|mol| mol.map(&:type) }.uniq
50
+ ```
45
51
 
46
52
  Read a single molecule from a file (reads only the first molecule)
47
53
 
48
- mol = Rubabel::Molecule.from_file("file.sdf")
49
- # handles gzipped files seamlessly:
50
- mol = Rubabel::Molecule.from_file("file.sdf.gz")
51
- mol = Rubabel.molecule_from_file("file.sdf") # alternative
54
+ ```ruby
55
+ mol = Rubabel::Molecule.from_file("file.sdf")
56
+ # handles gzipped files seamlessly:
57
+ mol = Rubabel::Molecule.from_file("file.sdf.gz")
58
+ mol = Rubabel.molecule_from_file("file.sdf") # alternative
52
59
 
53
- # explicit format for uninformative/wrong extensions:
54
- mol = Rubabel::Molecule.from_file("file", :sdf)
60
+ # explicit format for uninformative/wrong extensions:
61
+ mol = Rubabel::Molecule.from_file("file", :sdf)
62
+ ```
55
63
 
56
64
  ### Writing/Drawing
57
65
 
58
66
  #### create string output
59
67
 
60
- mol = Rubabel["OCC"] # ethanol
68
+ ```ruby
69
+ mol = Rubabel["OCC"] # ethanol
61
70
 
62
- mol.to_s # canonical smiles -> "CCO"
63
- mol.csmiles # same thing
71
+ mol.to_s # canonical smiles -> "CCO"
72
+ mol.csmiles # same thing
64
73
 
65
- mol.to_s(:smi) # smiles -> "OCC"
66
- mol.smiles # same thing
74
+ mol.to_s(:smi) # smiles -> "OCC"
75
+ mol.smiles # same thing
76
+ ```
67
77
 
68
78
  For inclusion in a file with standard smiles formatting (SMILES\tID\n):
69
79
 
70
- can_smiles_string = mol.write_string # -> "CCO\t\n"
71
- mol.title = "ethanol"
72
- can_smiles_string = mol.write(:can) # -> "CCO\tethanol\n"
80
+ ```ruby
81
+ can_smiles_string = mol.write_string # -> "CCO\t\n"
82
+ mol.title = "ethanol"
83
+ can_smiles_string = mol.write(:can) # -> "CCO\tethanol\n"
84
+ ```
73
85
 
74
86
  Other formats in the same manner:
75
87
 
76
- pdb_string = mol.write(:pdb)
88
+ ```ruby
89
+ pdb_string = mol.write(:pdb)
90
+ ```
77
91
 
78
92
  Write to a file directly (single molecule only; depends on file extension for type):
79
93
 
80
- # write to a smiles file
81
- mol.write("file.smi")
82
- mol.write_file("file.smi")
94
+ ```ruby
95
+ # write to a smiles file
96
+ mol.write("file.smi")
97
+ mol.write_file("file.smi")
98
+ ```
83
99
 
84
100
  Write multiple molecules to a file:
85
101
 
86
- File.open("somefile.pdb", 'w') do |out|
87
- molecules.each {|mol| out.print mol.write(:pdb) }
88
- end
102
+ ```ruby
103
+ File.open("somefile.pdb", 'w') do |out|
104
+ molecules.each {|mol| out.print mol.write(:pdb) }
105
+ end
106
+ ```
89
107
 
90
108
  #### Drawing
91
109
 
92
110
  If you write to svg or png (png uses mini_magick to convert from svg) then the
93
111
  molecule is automatically drawn in 2D:
94
112
 
95
- mol = Rubabel["NCC(O)C(=O)O"]
96
- mol.write("file.svg")
113
+ ```ruby
114
+ mol = Rubabel["NCC(O)C(=O)O"]
115
+ mol.write("file.svg")
97
116
 
98
- # must have imagemagick ('convert' command) and mini_magick gem installed
99
- mol.write("file.png")
117
+ # must have imagemagick ('convert' command) and mini_magick gem installed
118
+ mol.write("file.png")
119
+ ```
100
120
 
101
121
  ### Searching and Splitting
102
122
 
103
123
  *each_match*, *matches*, *matches?*, *smarts_indices* all take the same input (SMARTS
104
124
  string or object and optional boolean specifying uniqueness of results):
105
125
 
106
- mol = Rubabel["NCC(O)C(=O)O"]
107
- mol.each_match("CO") do |match|
108
- # match is just an array of atoms that matched
109
- match.first.el # => :c
110
- match.last.el # => :o
111
- end
112
-
113
- # matches returns all the matches in an array
114
- all_matches = mol.matches("CO")
115
- # all the match routines take a boolean to alter uniqueness
116
- all_matches = mol.matches("CO", false) # some matches may not be uniq
126
+ ```ruby
127
+ mol = Rubabel["NCC(O)C(=O)O"]
128
+ mol.each_match("CO") do |match|
129
+ # match is just an array of atoms that matched
130
+ match.first.el # => :C
131
+ match.last.el # => :O
132
+ end
133
+
134
+ # matches returns all the matches in an array
135
+ all_matches = mol.matches("CO")
136
+ # all the match routines take a boolean to alter uniqueness
137
+ all_matches = mol.matches("CO", false) # some matches may not be uniq
138
+ ```
117
139
 
118
140
  Have some bonds to break?, split makes new molecules split from that bond(s)
119
-
120
- bonds = mol.matches("CO").map {|c, o| c.get_bond(o) }
121
- mol.split(*bonds) # splits between every carbon single bonded to oxygen
141
+
142
+ ```ruby
143
+ bonds = mol.matches("CO").map {|c, o| c.get_bond(o) }
144
+ mol.split(*bonds) # splits between every carbon single bonded to oxygen
145
+ ```
122
146
 
123
147
  ### Add, delete, modify atoms/bonds
124
148
 
125
149
  #### Adding
126
150
 
127
- mol = Rubabel["OCC"]
128
- # adds a carbon, then an oxygen to last indexed atom by atomic number
129
- mol << 6 << 8 # #<Mol "OCCCO">
130
- mol << :c << :o # same thing
151
+ ```ruby
152
+ mol = Rubabel["OCC"]
153
+ # adds a carbon, then an oxygen to the previous carbon
154
+ mol << 6 << 8 # #<Mol "OCCCO">
155
+ mol << :C << :O # same thing
131
156
 
132
- # add an ethyl group specifically to second carbon
133
- mol = Rubabel["OCC"]
134
- mol[1] << :c << :c
157
+ # add an ethyl group specifically to second atom (the first carbon)
158
+ mol = Rubabel["OCC"]
159
+ mol[1] << :C << :C
135
160
 
136
- # add a vinyl group to second carbon (use method notation and parenthesis
137
- # because we are going to specify 2 arguments (the bond order):
138
- ( mol[1] << :c).<<(:c, 2)
161
+ # add a vinyl group to second carbon (use method notation and parenthesis
162
+ # because we are going to specify 2 arguments (the bond order):
163
+ ( mol[1] << :C).<<(:C, 2)
164
+ ```
139
165
 
140
166
  #### Deleting
141
167
 
142
- # delete an atom:
143
- mol = Rubabel["NCO"]
144
- mol.delete(mol[0]) # -> #<Mol CO>
168
+ ```ruby
169
+ # delete an atom:
170
+ mol = Rubabel["NCO"]
171
+ mol.delete(mol[0])
172
+ # mol.to_s -> #<Mol CO>
145
173
 
146
- # delete a bond:
147
- bond = mol[0].get_bond(mol[1])
148
- mol.delete(bond) # -> #<Mol C.O>
174
+ # delete a bond:
175
+ bond = mol[0].get_bond(mol[1])
176
+ mol.delete(bond)
177
+ # mol.to_s -> #<Mol C.O>
178
+ ```
149
179
 
150
180
  #### Modifying
151
181
 
152
- Can add or subtract from bonds to change bond order:
182
+ Can easily change the bond order:
183
+
184
+ ```ruby
185
+ mol = Rubabel["CC"]
186
+ bond = mol[0].get_bond(mol[1]) # get the bond you want
187
+ bond = mol[0].bonds.first # alternate way to get at bonds
153
188
 
154
- mol = Rubabel["CC"]
155
- mol[0].get_bond(mol[1]) + 1 # now it is a double bond
156
- bond = mol[0].bonds.first
157
- bond - 1
158
- bond.bond_order # => 1
189
+ bond += 2 # now it is a triple bond
190
+ bond.dec! # now a double bond
191
+ bond -= 1 # now a single bond
192
+ bond.inc!(2) # back to a triple bond
193
+ ```
159
194
 
160
195
  ## Installing
161
196
 
@@ -165,11 +200,15 @@ First, many thanks to Andreas Maunz for packaging openbabel as a gem which makes
165
200
 
166
201
  On a POSIX system, make sure you have openbabel (including header files), cmake, curl, tar, sed and make {see openbabel instructions}[https://github.com/amaunz/openbabel-gem]. On ubuntu/debian:
167
202
 
168
- sudo apt-get install openbabel libopenbabel-dev cmake make curl
203
+ ```bash
204
+ sudo apt-get install openbabel libopenbabel-dev cmake make curl
205
+ ```
169
206
 
170
207
  Then install the gem (which should install the openbabel gem, too):
171
208
 
172
- gem install rubabel
209
+ ```bash
210
+ gem install rubabel
211
+ ```
173
212
 
174
213
  ### Building from Source
175
214
 
@@ -179,21 +218,26 @@ Then install the gem (which should install the openbabel gem, too):
179
218
 
180
219
  Here's a complete example of compiling for a single user on Ubuntu 11.10 and probably will be generally forward compatible for some time. This will compile bindings on whichever ruby comes up with '/usr/bin/env ruby':
181
220
 
182
- # install the dependencies:
183
- sudo apt-get install libeigen2-dev cmake libwxgtk2.8-dev libxml2-dev libcairo2-dev
184
- # unpack it:
185
- tar -xzvf openbabel-2.3.1.tar.gz
186
- # swap out buggy lines in ruby bindings:
187
- sed -i 's/Init_OpenBabel/Init_openbabel/g' openbabel-2.3.1/scripts/ruby/openbabel-ruby.cpp
188
- # make a separate build directory for building in:
189
- mkdir build-rvmruby1.9.3
190
- cd build-rvmruby1.9.3
191
- mkdir ~/tools
192
- cmake ../openbabel-2.3.1 -DRUBY_BINDINGS=ON -DCMAKE_INSTALL_PREFIX=~/tools/openbabel-rvmruby1.9.3
193
- make && make install
194
-
195
- [[Still need directions to install the gem on top of a build from source]]
196
-
221
+ ```bash
222
+ # install the dependencies:
223
+ sudo apt-get install libeigen2-dev cmake libwxgtk2.8-dev libxml2-dev libcairo2-dev
224
+ # unpack it:
225
+ tar -xzvf openbabel-2.3.1.tar.gz
226
+ # swap out buggy lines in ruby bindings:
227
+ sed -i 's/Init_OpenBabel/Init_openbabel/g' openbabel-2.3.1/scripts/ruby/openbabel-ruby.cpp
228
+ # make a separate build directory for building in:
229
+ mkdir build-rvmruby1.9.3
230
+ cd build-rvmruby1.9.3
231
+ mkdir ~/tools
232
+ cmake ../openbabel-2.3.1 -DRUBY_BINDINGS=ON -DCMAKE_INSTALL_PREFIX=~/tools/openbabel-rvmruby1.9.3
233
+ make && make install
234
+ ```
235
+ ## See also
236
+
237
+ * [Rubidium](http://rbtk.rubyforge.org/) (based on the Chemistry Development Kit [jruby])
238
+ * [ChemRuby](https://github.com/ank/chemruby) [standalone using MRI extensions]
239
+ * [Chemcaster Ruby API](https://github.com/metamolecular/chemcaster-ruby)
240
+
197
241
  ## Copyright
198
242
 
199
243
  MIT License. See LICENSE for further details.
data/Rakefile CHANGED
@@ -23,7 +23,7 @@ interface attempts to be a ruby-ish analogue of pybel.}
23
23
  end
24
24
 
25
25
  [
26
- ["rspec", "~> 2.8.0"],
26
+ ["rspec", "~> 2.13.0"],
27
27
  ["rdoc", "~> 3.12"],
28
28
  ["jeweler", "~> 1.8.3"]
29
29
  ].each do |args|
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.3.0
data/lib/rubabel/atom.rb CHANGED
@@ -37,11 +37,6 @@ module Rubabel
37
37
  #end
38
38
  end
39
39
 
40
- # adds an atom and returns the added atom (allows chaining)
41
- def <<(atom, bond_order=1)
42
- add_atom!(atom, bond_order)
43
- end
44
-
45
40
  # returns the molecule that is parent of this atom
46
41
  def mol
47
42
  @ob.get_parent.andand.upcast
@@ -67,24 +62,23 @@ module Rubabel
67
62
  @ob.get_idx
68
63
  end
69
64
 
70
- # abbreviated name, all lowercase as a Symbol
71
- def el
72
- NUM_TO_EL[atomic_num]
73
- end
74
-
75
- # abbreviated name, properly capitalized and as a String
65
+ # elemental symbol, properly capitalized and returned as a Symbol
76
66
  def element
77
67
  NUM_TO_ELEMENT[atomic_num]
78
68
  end
69
+ alias_method :el, :element
79
70
 
80
- # creates a bond and adds it to both atoms. Returns the passed in or
81
- # newly created atom.
82
- def add_atom!(arg, bond_order=1)
83
- unless arg.is_a?(Rubabel::Atom)
84
- arg = mol.add_atom!(arg)
85
- end
86
- @ob.get_parent.add_bond(self.ob.get_idx, arg.ob.get_idx, bond_order)
87
- arg
71
+ # connects the atom-like specifier to this atom through Molecule#add_atom!
72
+ # returns the atom that was just added for chaining. Takes any argument
73
+ # that Molecule#add_atom! will take.
74
+ def bond!(arg, bond_order=1)
75
+ mol.add_atom!(arg, bond_order, self)
76
+ end
77
+ alias_method :<<, :bond!
78
+
79
+ # connects a Rubabel::Atom object with a bond
80
+ def connect!(atom, bond_order=1)
81
+ @ob.get_parent.add_bond(@ob.get_idx, atom.ob.get_idx, bond_order)
88
82
  end
89
83
 
90
84
  def each_bond(&block)
@@ -319,7 +313,7 @@ module Rubabel
319
313
 
320
314
  def carbonyl_oxygen?
321
315
  ats = atoms
322
- ats.size == 1 && ats.first.el == :c && double_bond?
316
+ ats.size == 1 && ats.first.el == :C && double_bond?
323
317
  end
324
318
 
325
319
  def carbonyl_carbon?
data/lib/rubabel/bond.rb CHANGED
@@ -59,11 +59,13 @@ module Rubabel
59
59
  def bond_order
60
60
  @ob.get_bond_order
61
61
  end
62
+ alias_method :order, :bond_order
62
63
 
63
64
  # 1 = single, 2 = double, 5 = aromatic
64
65
  def bond_order=(val=1)
65
66
  @ob.set_bond_order(val)
66
67
  end
68
+ alias_method :order=, :bond_order=
67
69
 
68
70
  # returns self
69
71
  def set_atoms!(beg_atom, end_atom)
@@ -99,20 +101,31 @@ module Rubabel
99
101
  "#{atoms.map(&:inspect).join(bond_symbol)}"
100
102
  end
101
103
 
102
- # returns self
104
+ # Increases the bond order and returns a new Rubabel::Bond object--but it
105
+ # will still be pointing to the same underlying @ob object.
103
106
  def +(val)
104
- # do we need to check the bounds here?
107
+ inc!(val)
108
+ @ob.upcast
109
+ end
110
+
111
+ # increase the bond order by val
112
+ def inc!(val=1)
105
113
  newval = @ob.get_bond_order + val
114
+ newval = 0 if newval < 0
106
115
  @ob.set_bond_order(newval)
107
116
  self
108
117
  end
109
118
 
110
- # won't decrease below zero. returns self
119
+ # decrease the bond order by val
120
+ def dec!(val=1)
121
+ inc!(-val)
122
+ end
123
+
124
+ # Decreases the bond order and returns a new Rubabel::Bond object--but it
125
+ # will still be pointing to the same underlying @ob object. Won't
126
+ # decrease below zero.
111
127
  def -(val)
112
- newval = @ob.get_bond_order - val
113
- newval = 0 if newval < 0
114
- @ob.set_bond_order(newval)
115
- self
128
+ self.+(-val)
116
129
  end
117
130
 
118
131
  end
@@ -31,7 +31,7 @@ module Rubabel
31
31
  # oxygen (e.g., an OH or a charge) to the carbon_nbr. Returns two new
32
32
  # molecules.
33
33
  def carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
34
- appendage = oxygen.atoms.find {|a| a.el != :c }
34
+ appendage = oxygen.atoms.find {|a| a.el != :C }
35
35
  if oxygen.charge != 0
36
36
  ocharge = oxygen.charge
37
37
  end
@@ -104,7 +104,7 @@ module Rubabel
104
104
 
105
105
  if opts[:rules].any? {|r| [:cod, :codoo].include?(r) }
106
106
  self.each_match("C[O;h1,O]", only_uniqs) do |carbon, oxygen|
107
- carbon.atoms.select {|a| a.el == :c }.each do |carbon_nbr|
107
+ carbon.atoms.select {|a| a.el == :C }.each do |carbon_nbr|
108
108
  fragment_sets << carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
109
109
  end
110
110
  end
@@ -108,25 +108,40 @@ module Rubabel
108
108
  end
109
109
  end
110
110
 
111
+ # arg may be a Fixnum, a Symbol (Elemental symbol that is a Symbol), or a
112
+ # Rubabel::Atom. Returns the newly associated/created atom.
113
+ def associate_atom!(arg)
114
+ if arg.is_a?(Rubabel::Atom)
115
+ @ob.add_atom(arg.ob)
116
+ arg
117
+ else
118
+ (num, is_aromatic) =
119
+ if arg.is_a?(Symbol)
120
+ [Rubabel::ELEMENT_TO_NUM[arg], (arg.to_s.capitalize != arg.to_s)]
121
+ else
122
+ [arg, false]
123
+ end
124
+
125
+ new_obatom = @ob.new_atom
126
+ new_obatom.set_atomic_num(num)
127
+ new_obatom.set_aromatic if is_aromatic
128
+ Rubabel::Atom.new(new_obatom)
129
+ end
130
+ end
131
+
132
+
111
133
  # returns the atom passed in or that was created. arg is a pre-existing
112
134
  # atom, an atomic number or an element symbol (e.g. :c). default is to
113
135
  # add carbon.
114
- def add_atom!(arg=6, attach_to=nil, bond_order=1)
115
- if attach_to
116
- attach_to.add_atom!(arg, bond_order)
117
- else
118
- if arg.is_a?(Rubabel::Atom)
119
- @ob.add_atom(arg.ob)
120
- arg
121
- else
122
- new_obatom = @ob.new_atom
123
- arg = Rubabel::EL_TO_NUM[arg] if arg.is_a?(Symbol)
124
- new_obatom.set_atomic_num(arg)
125
- Rubabel::Atom.new(new_obatom)
126
- end
127
- end
136
+ def add_atom!(arg=6, bond_order=1, attach_to=nil)
137
+ attach_to ||= atoms.last
138
+ atom = associate_atom!(arg)
139
+ add_bond!(attach_to, atom, bond_order) if attach_to
140
+ atom
128
141
  end
129
142
 
143
+ alias_method :<<, :add_atom!
144
+
130
145
  # retrieves the atom by index (accepts everything an array would)
131
146
  def [](*args)
132
147
  atoms[*args]
@@ -490,18 +505,6 @@ module Rubabel
490
505
  Rubabel::MoleculeData.new(@ob)
491
506
  end
492
507
 
493
- # adds the atom (takes atomic number, element symbol or preexisting atom)
494
- # and returns self
495
- def <<(arg, bond_order=1)
496
- last_atom = atoms[-1]
497
- if last_atom
498
- last_atom.add_atom!(arg, bond_order)
499
- else
500
- add_atom!(arg)
501
- end
502
- self
503
- end
504
-
505
508
  # sensitive to add_h!
506
509
  def num_atoms(count_implied_hydrogens=false)
507
510
  if !count_implied_hydrogens
data/lib/rubabel.rb CHANGED
@@ -113,19 +113,28 @@ module Rubabel
113
113
  end
114
114
 
115
115
  module Rubabel
116
- # capitalized strings
117
- ELEMENTS = %w(H He Li Be B C N O F Ne Na Mg Al Si P S Cl Ar K Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Xe Cs Ba La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn Fr Ra Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr Rf Db Sg Bh Hs Mt Ds Rg Cn Uut Fl Uup Lv Uus Uuo)
116
+ # capitalized Symbols
117
+ ELEMENTS = %w(H He Li Be B C N O F Ne Na Mg Al Si P S Cl Ar K Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Xe Cs Ba La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn Fr Ra Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr Rf Db Sg Bh Hs Mt Ds Rg Cn Uut Fl Uup Lv Uus Uuo).map(&:to_sym)
118
118
 
119
- # atomic number to properly capitalized element abbreviation
119
+ # atomic number to properly capitalized element abbreviation (as Symbol)
120
120
  NUM_TO_ELEMENT = Hash[ ELEMENTS.each_with_index.map {|el,i| [i+1,el] } ]
121
+ # atomic number to properly capitalized element abbreviation (as Symbol)
121
122
 
122
- # atomic number to lowercase symbol abbreviation
123
- NUM_TO_EL = Hash[ ELEMENTS.each_with_index.map {|el,i| [i+1,el.downcase.to_sym] } ]
123
+ # the SMILES aromatic elements, listed in proper capitalized notation (e.g., :Se)
124
+ AROMATIC_ELEMENTS = [:C, :O, :S, :Se, :N]
125
+ # (http://esc.syrres.com/esc/docsmile.htm)
124
126
 
125
- EL_TO_NUM = NUM_TO_EL.invert
127
+ # Along with properly capitalized element symbols (e.g., :Se) ELEMENT_TO_NUM
128
+ # will include keys to lowercase versions of the AROMATIC_ELEMENTS
126
129
  ELEMENT_TO_NUM = NUM_TO_ELEMENT.invert
130
+
131
+ AROMATIC_ELEMENTS.each do |el|
132
+ ELEMENT_TO_NUM[el.to_s.downcase.to_sym] = ELEMENT_TO_NUM[el]
133
+ end
127
134
  end
128
135
 
136
+
137
+
129
138
  =begin
130
139
  OBConversion conv;
131
140
  OBMol mol;
@@ -24,8 +24,12 @@ end
24
24
 
25
25
  describe 'Chemistry Toolkit Rosetta Wiki' do
26
26
 
27
- def equivalent_pngs(png1, png2)
28
- (png1.size - png2.size < 50) && (png1[0..100] == png2[0..100])
27
+ def pngs_are_about_same_size(png1, png2, delta=150)
28
+ (png1.size - png2.size < delta)
29
+ end
30
+
31
+ def pngs_have_same_header(png1, png2, check_length=60)
32
+ png1[0..check_length] == png2[0..check_length]
29
33
  end
30
34
 
31
35
  before(:each) do
@@ -239,7 +243,9 @@ describe 'Chemistry Toolkit Rosetta Wiki' do
239
243
  end
240
244
  png_out = IO.read(@wiki_spec_dir + "/caffeine.png")
241
245
  key_out = IO.read(@keydir + "/caffeine.frozen.png")
242
- equivalent_pngs(png_out, key_out).should be_true
246
+
247
+ pngs_are_about_same_size(png_out, key_out).should be_true
248
+ pngs_have_same_header(png_out, key_out).should be_true
243
249
  File.unlink('caffeine.png')
244
250
  end
245
251
  #OR, using commandline
@@ -258,7 +264,8 @@ describe 'Chemistry Toolkit Rosetta Wiki' do
258
264
  end
259
265
  png_out = IO.read(@wiki_spec_dir + "/3016_highlighted.rubabel.png")
260
266
  key_out = IO.read(@keydir + "/3016_highlighted.rubabel.frozen.png")
261
- equivalent_pngs(png_out, key_out)
267
+ pngs_are_about_same_size(png_out, key_out).should be_true
268
+ pngs_have_same_header(png_out, key_out).should be_true
262
269
  File.unlink('3016_highlighted.rubabel.png')
263
270
  end
264
271
 
@@ -307,7 +314,7 @@ describe 'Chemistry Toolkit Rosetta Wiki' do
307
314
  mol.matches(smarts).each do |atom1, atom2|
308
315
  mol.delete(atom1.get_bond(atom2))
309
316
  [atom1, atom2].each do |old_a|
310
- mol.add_bond!(old_a, mol.add_atom!(0))
317
+ mol.add_atom!(0, 1, old_a)
311
318
  end
312
319
  end
313
320
  puts "#{mol.to_s.gsub('.',"\n")}"
@@ -23,6 +23,7 @@ describe Rubabel::Atom do
23
23
  end
24
24
 
25
25
  it 'attaches given an atomic number' do
26
+
26
27
  end
27
28
 
28
29
  it 'attaches given an element symbol' do
@@ -19,4 +19,61 @@ describe Rubabel::Bond do
19
19
  end
20
20
  end
21
21
 
22
+ describe 'manipulating the bond order' do
23
+ subject {
24
+ mol = Rubabel['CC']
25
+ mol[0].get_bond(mol[1])
26
+ }
27
+
28
+ specify '#inc! increases the bond order' do
29
+ subject.order.should == 1
30
+ subject.inc!
31
+ subject.order.should == 2
32
+ end
33
+
34
+ specify '#inc!(n) increases the bond order by n' do
35
+ subject.order.should == 1
36
+ subject.inc!(2)
37
+ subject.order.should == 3
38
+ end
39
+
40
+ specify '#inc!(-n) will not go below 0' do
41
+ subject.order.should == 1
42
+ subject.inc!(-1)
43
+ subject.order.should == 0
44
+ subject.inc!(-1)
45
+ subject.order.should == 0
46
+ end
47
+
48
+ specify '#+(n) will add but not return same ruby object (underlying ob object same)' do
49
+ other = subject + 1
50
+ other.order.should == 2
51
+ subject.order.should == 2
52
+ subject.should_not equal(other)
53
+ #other.object_id.should_not == subject.object_id
54
+ end
55
+
56
+ specify '#+(n) will add but not return same ruby object (underlying ob object same)' do
57
+ another_var = subject
58
+ another_var += 1
59
+ another_var.order.should == 2
60
+ subject.order.should == 2
61
+ subject.ob.should equal(another_var.ob)
62
+ end
63
+
64
+ specify '#dec!' do
65
+ subject.dec!
66
+ subject.order.should == 0
67
+ end
68
+
69
+ specify '#-(n)' do
70
+ var = subject
71
+ var.inc!
72
+ var.order.should == 2
73
+ var -= 2
74
+ var.order.should == 0
75
+ var -= 1
76
+ var.order.should == 0
77
+ end
78
+ end
22
79
  end
@@ -22,10 +22,10 @@ describe Rubabel::Molecule do
22
22
  end
23
23
 
24
24
  #xit 'can add a hydrogen to the formula' do
25
- #mol = Rubabel["CCC"]
26
- #p mol.formula
27
- #mol.add_hydrogen_to_formula!
28
- #p mol.formula
25
+ #mol = Rubabel["CCC"]
26
+ #p mol.formula
27
+ #mol.add_hydrogen_to_formula!
28
+ #p mol.formula
29
29
  #end
30
30
 
31
31
  describe 'png output' do
@@ -77,14 +77,14 @@ describe Rubabel::Molecule do
77
77
 
78
78
  specify '#[] retrieves atom by index' do
79
79
  mol = Rubabel["NCO"]
80
- mol[0].el.should == :n
81
- mol[1].el.should == :c
82
- mol[2].el.should == :o
83
- mol[-1].el.should == :o
84
- mol[-2].el.should == :c
80
+ mol[0].el.should == :N
81
+ mol[1].el.should == :C
82
+ mol[2].el.should == :O
83
+ mol[-1].el.should == :O
84
+ mol[-2].el.should == :C
85
85
  ar = mol[1..-1]
86
- ar.first.el.should == :c
87
- ar.last.el.should == :o
86
+ ar.first.el.should == :C
87
+ ar.last.el.should == :O
88
88
  ar.size.should == 2
89
89
  end
90
90
 
@@ -100,34 +100,44 @@ describe Rubabel::Molecule do
100
100
  mol.num_atoms(true).should == 11
101
101
  end
102
102
 
103
- describe 'adding an atom' do
104
- it 'can be added but not attached' do
103
+ describe 'adding or associating atoms' do
104
+
105
+ it 'can associate atoms with the molecule' do
105
106
  mol = Rubabel["CCO"]
106
- atom = mol.add_atom!(:n)
107
- atom.el.should == :n
108
- atom = mol.add_atom!(8)
109
- atom.el.should == :o
107
+ nitrogen = mol.associate_atom!(:N)
108
+ nitrogen.el.should == :N
109
+ oxygen = mol.associate_atom!(8)
110
+ oxygen.el.should == :O
110
111
  mol.csmiles.should == "CCO.N.O"
112
+
113
+ oxygen_aromatic = mol.associate_atom!(:O)
114
+ mol.csmiles.should == "CCO.N.O.O"
111
115
  end
112
116
 
113
- it "can be added and attached by el symbol or atomic number" do
117
+ it "can be added and attached by element symbol or atomic number" do
114
118
  mol = Rubabel["CCO"]
115
119
  first_carbon = mol[0]
116
- mol.add_atom!(:n, first_carbon)
120
+ mol.add_atom!(:N, 1, first_carbon)
117
121
  mol.csmiles.should == "NCCO"
118
122
 
119
- mol.add_atom!(16, first_carbon)
123
+ mol.add_atom!(16, 1, first_carbon)
120
124
  mol.csmiles.should == "NC(CO)S"
121
125
  end
122
126
 
123
127
  end
124
-
125
- specify '#<< adds atom to the last atom and returns the mol' do
128
+
129
+ specify '#<< adds atom to the last atom and returns the added atom' do
126
130
  mol = Rubabel::Molecule.new
131
+ reply = (mol << :N)
127
132
  # by element symbol or atomic number
128
- reply = (mol << :n << :c)
129
- reply.should be_a(Rubabel::Molecule)
130
- reply.csmiles.should == 'CN'
133
+ reply = (mol << :N << :C)
134
+ reply.should be_a(Rubabel::Atom)
135
+ reply.el.should == :C
136
+
137
+ # properly handles aromaticity
138
+ mol.atoms.last.aromatic?.should be_false
139
+ mol << :c # aromatic specifier in SMILES
140
+ mol.atoms.last.aromatic?.should be_true
131
141
  end
132
142
 
133
143
  specify '#dup duplicates the molecule' do
@@ -143,7 +153,7 @@ describe Rubabel::Molecule do
143
153
  describe '#add_bond! adds a bond (and updates atoms)' do
144
154
  specify 'given two atoms' do
145
155
  mol = Rubabel["CCO"]
146
- atom = mol.add_atom!(0)
156
+ atom = mol.associate_atom!(0)
147
157
  mol.add_bond!(mol[1], atom)
148
158
  mol.csmiles.should == '*C(O)C'
149
159
  end
@@ -151,7 +161,7 @@ describe Rubabel::Molecule do
151
161
 
152
162
  specify '#atom(id) retrieves atom by id num' do
153
163
  mol = Rubabel["CCO"]
154
- o = mol.find {|a| a.el == :o }
164
+ o = mol.find {|a| a.el == :O }
155
165
  mol.atom(o.id).id.should == o.id
156
166
  end
157
167
 
@@ -160,7 +170,7 @@ describe Rubabel::Molecule do
160
170
  carboxy_carbon = mol.atoms.find {|atom| atom.type == 'Cac' }
161
171
  single_bonded_oxygen = mol.atoms.find {|atom| atom.type == 'O.co2' && atom.get_bond(carboxy_carbon).bond_order == 1 }
162
172
  nit_carbon = mol.atoms.find {|atom| atom.atoms.any? {|nbr| nbr.type == 'N3' } }
163
- nitrogen = mol.atoms.find {|atom| atom.el == :n }
173
+ nitrogen = mol.atoms.find {|atom| atom.el == :N }
164
174
  swapped = mol.swap!(nit_carbon, nitrogen, carboxy_carbon, single_bonded_oxygen)
165
175
  swapped.should == mol
166
176
  swapped.csmiles.should == 'NC(=O)CO'
@@ -315,7 +325,7 @@ describe Rubabel::Molecule do
315
325
  describe 'breaking a molecule' do
316
326
  before(:each) do
317
327
  @mol = Rubabel::Molecule.from_string("NC(=O)CO")
318
- @n = @mol.find {|a| a.el == :n }
328
+ @n = @mol.find {|a| a.el == :N }
319
329
  end
320
330
 
321
331
  it 'num_atoms, atoms and each_atom are sensitive to #add_h!' do
data/spec/spec_helper.rb CHANGED
@@ -5,14 +5,14 @@ require 'rspec/core/formatters/progress_formatter'
5
5
  # doesn't say so much about pending guys
6
6
  class QuietPendingFormatter < RSpec::Core::Formatters::ProgressFormatter
7
7
  def example_pending(example)
8
- output.print yellow('*')
8
+ output.print pending_color('*')
9
9
  end
10
10
  end
11
11
 
12
12
  require 'rspec/core/formatters/documentation_formatter'
13
13
  class QuietPendingDocFormatter < RSpec::Core::Formatters::DocumentationFormatter
14
14
  def example_pending(example)
15
- output.puts yellow( "<pending>: #{example.execution_result[:pending_message]}" )
15
+ output.puts pending_color( "<pending>: #{example.execution_result[:pending_message]}" )
16
16
  end
17
17
  end
18
18
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubabel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-18 00:00:00.000000000 Z
12
+ date: 2013-03-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: openbabel
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ~>
68
68
  - !ruby/object:Gem::Version
69
- version: 2.8.0
69
+ version: 2.13.0
70
70
  type: :development
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,7 +74,7 @@ dependencies:
74
74
  requirements:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
- version: 2.8.0
77
+ version: 2.13.0
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: rdoc
80
80
  requirement: !ruby/object:Gem::Requirement