ms-sequest 0.0.17 → 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +26 -10
- data/Gemfile +4 -1
- data/Gemfile.lock +17 -2
- data/VERSION +1 -1
- data/bin/srf_to_pepxml.rb +7 -0
- data/bin/srf_to_search.rb +1 -1
- data/lib/ms/sequest/bioworks.rb +2 -2
- data/lib/ms/sequest/params.rb +0 -20
- data/lib/ms/sequest/pepxml.rb +7 -245
- data/lib/ms/sequest/pepxml/modifications.rb +247 -0
- data/lib/ms/sequest/pepxml/params.rb +32 -0
- data/lib/ms/sequest/sqt.rb +17 -17
- data/lib/ms/sequest/srf.rb +64 -54
- data/lib/ms/sequest/srf/pepxml.rb +316 -0
- data/lib/ms/sequest/srf/pepxml/sequest.rb +21 -0
- data/lib/ms/sequest/srf/sqt.rb +1 -1
- data/spec/ms/sequest/bioworks_spec.rb +11 -11
- data/spec/ms/sequest/pepxml/modifications_spec.rb +50 -0
- data/spec/ms/sequest/pepxml_spec.rb +0 -65
- data/spec/ms/sequest/srf/pepxml_spec.rb +84 -0
- data/spec/ms/sequest/srf_spec.rb +3 -3
- data/spec/ms/sequest/srf_spec_helper.rb +2 -2
- data/spec/spec_helper.rb +17 -18
- metadata +73 -19
@@ -241,71 +241,6 @@ describe Sequest::PepXML, " created from large bioworks.xml" do
|
|
241
241
|
end
|
242
242
|
|
243
243
|
|
244
|
-
|
245
|
-
describe Sequest::PepXML::Modifications do
|
246
|
-
before(:each) do
|
247
|
-
tf_params = Tfiles + "/bioworks32.params"
|
248
|
-
@params = Sequest::Params.new(tf_params)
|
249
|
-
# The params object here is completely unnecessary for this test, except
|
250
|
-
# that it sets up the mass table
|
251
|
-
@obj = Sequest::PepXML::Modifications.new(@params, "(M* +15.90000) (M# +29.00000) (S@ +80.00000) (C^ +12.00000) (ct[ +12.33000) (nt] +14.20000) ")
|
252
|
-
end
|
253
|
-
it 'creates a mod_symbols_hash' do
|
254
|
-
answ = {[:C, 12.0]=>"^", [:S, 80.0]=>"@", [:M, 29.0]=>"#", [:M, 15.9]=>"*", [:ct, 12.33]=>"[", [:nt, 14.2]=>"]"}
|
255
|
-
@obj.mod_symbols_hash.should == answ
|
256
|
-
## need more here
|
257
|
-
end
|
258
|
-
|
259
|
-
it 'creates a ModificationInfo object given a special peptide sequence' do
|
260
|
-
mod_string = "(M* +15.90000) (M# +29.00000) (S@ +80.00000) (C^ +12.00000) (ct[ +12.33000) (nt] +14.20000) "
|
261
|
-
@params.diff_search_options = "15.90000 M 29.00000 M 80.00000 S 12.00000 C"
|
262
|
-
@params.term_diff_search_options = "14.20000 12.33000"
|
263
|
-
mod = Sequest::PepXML::Modifications.new(@params, mod_string)
|
264
|
-
## no mods
|
265
|
-
peptide = "PEPTIDE"
|
266
|
-
mod.modification_info(peptide).should be_nil
|
267
|
-
peptide = "]M*EC^S@IDM#M*EMSCM["
|
268
|
-
modinfo = mod.modification_info(peptide)
|
269
|
-
modinfo.modified_peptide.should == peptide
|
270
|
-
modinfo.mod_nterm_mass.should be_close(146.40054, 0.000001)
|
271
|
-
modinfo.mod_cterm_mass.should be_close(160.52994, 0.000001)
|
272
|
-
end
|
273
|
-
|
274
|
-
end
|
275
|
-
|
276
|
-
describe Sequest::PepXML::SearchHit::ModificationInfo do
|
277
|
-
|
278
|
-
before(:each) do
|
279
|
-
modaaobjs = [[3, 150.3], [6, 345.2]].map do |ar|
|
280
|
-
Sequest::PepXML::SearchHit::ModificationInfo::ModAminoacidMass.new(ar)
|
281
|
-
end
|
282
|
-
hash = {
|
283
|
-
:mod_nterm_mass => 520.2,
|
284
|
-
:modified_peptide => "MOD*IFI^E&D",
|
285
|
-
:mod_aminoacid_masses => modaaobjs,
|
286
|
-
}
|
287
|
-
#answ = "<modification_info mod_nterm_mass=\"520.2\" modified_peptide=\"MOD*IFI^E&D\">\n\t<mod_aminoacid_mass position=\"3\" mass=\"150.3\"/>\n\t<mod_aminoacid_mass position=\"6\" mass=\"345.2\"/>\n</modification_info>\n"
|
288
|
-
@obj = Sequest::PepXML::SearchHit::ModificationInfo.new(hash)
|
289
|
-
end
|
290
|
-
|
291
|
-
def _re(st)
|
292
|
-
/#{Regexp.escape(st)}/
|
293
|
-
end
|
294
|
-
|
295
|
-
it 'can produce pepxml' do
|
296
|
-
answ = @obj.to_pepxml
|
297
|
-
answ.should =~ _re('<modification_info')
|
298
|
-
answ.should =~ _re(" mod_nterm_mass=\"520.2\"")
|
299
|
-
answ.should =~ _re(" modified_peptide=\"MOD*IFI^E&D\"")
|
300
|
-
answ.should =~ _re("<mod_aminoacid_mass")
|
301
|
-
answ.should =~ _re(" position=\"3\"")
|
302
|
-
answ.should =~ _re(" mass=\"150.3\"")
|
303
|
-
answ.should =~ _re(" position=\"6\"")
|
304
|
-
answ.should =~ _re(" mass=\"345.2\"")
|
305
|
-
answ.should =~ _re("</modification_info>")
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
244
|
describe 'bioworks file with modifications transformed into pepxml' do
|
310
245
|
|
311
246
|
spec_large do
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'ms/sequest/srf/pepxml'
|
4
|
+
|
5
|
+
describe 'an Ms::Ident::Pepxml object from an srf file with modifications' do
|
6
|
+
before do
|
7
|
+
FileUtils.mkdir @out_path unless File.exist?(@out_path)
|
8
|
+
end
|
9
|
+
after do
|
10
|
+
FileUtils.rm_rf @out_path
|
11
|
+
end
|
12
|
+
|
13
|
+
@srf_file = SEQUEST_DIR + '/opd1_2runs_2mods/sequest331/020.srf'
|
14
|
+
@out_path = TESTFILES + '/tmp'
|
15
|
+
@srf = Ms::Sequest::Srf.new(@srf_file)
|
16
|
+
|
17
|
+
it 'produces xml with all the expected parts' do
|
18
|
+
tags = %w(msms_pipeline_analysis msms_run_summary sample_enzyme specificity search_summary search_database enzymatic_search_constraint aminoacid_modification parameter spectrum_query search_result search_hit modification_info mod_aminoacid_mass search_score)
|
19
|
+
pepxml = @srf.to_pepxml(:verbose => false)
|
20
|
+
xml_string = pepxml.to_xml
|
21
|
+
tags.each do |tag|
|
22
|
+
xml_string.matches %r{<#{tag}}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# takes an xml string of attributes (' key="val" key2="val2" ') and a xml
|
27
|
+
# node that is expected to have those attributes
|
28
|
+
def has_attributes(node, string)
|
29
|
+
if node.nil?
|
30
|
+
raise "your xml node is nil!!!"
|
31
|
+
end
|
32
|
+
if node == []
|
33
|
+
raise "you gave me an empty array instead of a node"
|
34
|
+
end
|
35
|
+
# strips the tail end quote mark, also
|
36
|
+
string.strip!
|
37
|
+
string.chomp!('"')
|
38
|
+
string.split(/"\s+/).each do |str|
|
39
|
+
(key,val) = str.split('=',2)
|
40
|
+
val=val[1..-1] if val[0,1] == '"'
|
41
|
+
if node[key] != val
|
42
|
+
puts "FAILING"
|
43
|
+
puts "EXPECT: #{key} => #{val} ACTUAL => #{val}"
|
44
|
+
puts "NODE KEYS: "
|
45
|
+
p node.keys
|
46
|
+
puts "NODE VALUES: "
|
47
|
+
p node.values
|
48
|
+
end
|
49
|
+
node[key].is val
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'gets everything right' do
|
54
|
+
xml_string = @srf.to_pepxml(:verbose => false).to_xml
|
55
|
+
doc = Nokogiri::XML.parse(xml_string, nil, nil, Nokogiri::XML::ParseOptions::DEFAULT_XML | Nokogiri::XML::ParseOptions::NOBLANKS)
|
56
|
+
|
57
|
+
root = doc.root
|
58
|
+
|
59
|
+
root.name.is "msms_pipeline_analysis"
|
60
|
+
has_attributes( root, 'schemaLocation="http://regis-web.systemsbiology.net/pepXML /tools/bin/TPP/tpp/schema/pepXML_v115.xsd"' )
|
61
|
+
root['date'].nil?.is false
|
62
|
+
root['summary_xml'].matches "020.xml"
|
63
|
+
root.namespaces.is( {"xmlns" => "http://regis-web.systemsbiology.net/pepXML" } )
|
64
|
+
|
65
|
+
mrs_node = root.child
|
66
|
+
mrs_node.name.is 'msms_run_summary'
|
67
|
+
has_attributes( mrs_node, 'msManufacturer="Thermo" msModel="LCQ Deca XP" msIonization="ESI" msMassAnalyzer="Ion Trap" msDetector="UNKNOWN" raw_data=".mzXML"' )
|
68
|
+
se_node = mrs_node.child
|
69
|
+
se_node.name.is 'sample_enzyme'
|
70
|
+
has_attributes se_node, 'name="Trypsin"'
|
71
|
+
specificity_node = se_node.child
|
72
|
+
specificity_node.name.is 'specificity'
|
73
|
+
has_attributes specificity_node, 'cut="KR" no_cut="P" sense="C"'
|
74
|
+
search_summary_node = se_node.next_sibling
|
75
|
+
search_summary_node.name.is 'search_summary'
|
76
|
+
has_attributes search_summary_node, 'search_engine="SEQUEST" precursor_mass_type="average" fragment_mass_type="average" search_id="1"'
|
77
|
+
search_summary_node['base_name'].matches %r{sequest/opd1_2runs_2mods/sequest331/020$}
|
78
|
+
# TODO: expand the search summary check!
|
79
|
+
# TODO: finish testing other guys for accurcy
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
data/spec/ms/sequest/srf_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ms/sequest/srf_spec_helper' # in spec/
|
3
3
|
|
4
4
|
require 'ms/sequest/srf'
|
5
5
|
|
@@ -12,7 +12,7 @@ class Hash
|
|
12
12
|
self.all? do |k,v|
|
13
13
|
k = k.to_sym
|
14
14
|
retval =
|
15
|
-
if k == :peaks or k == :hits or k == :
|
15
|
+
if k == :peaks or k == :hits or k == :proteins
|
16
16
|
obj.send(k).size == v
|
17
17
|
elsif v.class == Float
|
18
18
|
delta =
|
@@ -85,7 +85,7 @@ module SRFHelper
|
|
85
85
|
:rsp=>1,
|
86
86
|
:ions_matched=>5,
|
87
87
|
:ions_total=>35,
|
88
|
-
:
|
88
|
+
:proteins=>1,
|
89
89
|
:deltamass=>-0.00579976654989878,
|
90
90
|
:ppm=>5.16938660859491,
|
91
91
|
:base_name=>"020",
|
@@ -109,7 +109,7 @@ module SRFHelper
|
|
109
109
|
:rsp=>11,
|
110
110
|
:ions_matched=>6,
|
111
111
|
:ions_total=>40,
|
112
|
-
:
|
112
|
+
:proteins=>1,
|
113
113
|
:deltamass=>0.00243330985608736,
|
114
114
|
:ppm=>1.91215729542523,
|
115
115
|
:base_name=>"020",
|
data/spec/spec_helper.rb
CHANGED
@@ -1,25 +1,19 @@
|
|
1
|
-
|
2
1
|
require 'rubygems'
|
3
|
-
require '
|
4
|
-
|
5
|
-
Bacon.summary_on_exit
|
6
|
-
|
7
|
-
# is this already defined??
|
8
|
-
TESTFILES = File.expand_path(File.dirname(__FILE__)) + "/testfiles"
|
2
|
+
require 'bundler'
|
9
3
|
|
10
4
|
begin
|
11
|
-
|
12
|
-
rescue
|
13
|
-
puts
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
% git submodule init
|
18
|
-
% git submodule update
|
19
|
-
|
20
|
-
}
|
21
|
-
raise
|
5
|
+
Bundler.setup(:default, :development)
|
6
|
+
rescue Bundler::BundlerError => e
|
7
|
+
$stderr.puts e.message
|
8
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
9
|
+
exit e.status_code
|
22
10
|
end
|
11
|
+
require 'ms/testdata'
|
12
|
+
require 'spec/more'
|
13
|
+
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
16
|
+
|
23
17
|
|
24
18
|
def capture_stderr
|
25
19
|
begin
|
@@ -31,3 +25,8 @@ def capture_stderr
|
|
31
25
|
end
|
32
26
|
end
|
33
27
|
|
28
|
+
TESTFILES = File.dirname(__FILE__) + '/testfiles'
|
29
|
+
SEQUEST_DIR = Ms::TESTDATA + '/sequest'
|
30
|
+
|
31
|
+
|
32
|
+
Bacon.summary_on_exit
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 18
|
9
|
+
version: 0.0.18
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- John T. Prince
|
@@ -14,11 +14,11 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-03-08 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name: ms-
|
21
|
+
name: ms-ident
|
22
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
23
23
|
none: false
|
24
24
|
requirements:
|
@@ -27,14 +27,29 @@ dependencies:
|
|
27
27
|
segments:
|
28
28
|
- 0
|
29
29
|
- 0
|
30
|
-
-
|
31
|
-
version: 0.0.
|
30
|
+
- 17
|
31
|
+
version: 0.0.17
|
32
32
|
type: :runtime
|
33
33
|
prerelease: false
|
34
34
|
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
36
|
+
name: ms-core
|
37
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
- 0
|
45
|
+
- 14
|
46
|
+
version: 0.0.14
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: arrayclass
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
53
|
none: false
|
39
54
|
requirements:
|
40
55
|
- - ">="
|
@@ -46,10 +61,39 @@ dependencies:
|
|
46
61
|
version: 0.1.0
|
47
62
|
type: :runtime
|
48
63
|
prerelease: false
|
49
|
-
version_requirements: *
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: ms-msrun
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
- 3
|
75
|
+
- 3
|
76
|
+
version: 0.3.3
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: trollop
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
segments:
|
88
|
+
- 1
|
89
|
+
- 16
|
90
|
+
version: "1.16"
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: *id005
|
50
94
|
- !ruby/object:Gem::Dependency
|
51
95
|
name: ms-testdata
|
52
|
-
requirement: &
|
96
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
53
97
|
none: false
|
54
98
|
requirements:
|
55
99
|
- - ">="
|
@@ -61,10 +105,10 @@ dependencies:
|
|
61
105
|
version: 0.1.1
|
62
106
|
type: :development
|
63
107
|
prerelease: false
|
64
|
-
version_requirements: *
|
108
|
+
version_requirements: *id006
|
65
109
|
- !ruby/object:Gem::Dependency
|
66
110
|
name: spec-more
|
67
|
-
requirement: &
|
111
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
68
112
|
none: false
|
69
113
|
requirements:
|
70
114
|
- - ">="
|
@@ -74,10 +118,10 @@ dependencies:
|
|
74
118
|
version: "0"
|
75
119
|
type: :development
|
76
120
|
prerelease: false
|
77
|
-
version_requirements: *
|
121
|
+
version_requirements: *id007
|
78
122
|
- !ruby/object:Gem::Dependency
|
79
123
|
name: bundler
|
80
|
-
requirement: &
|
124
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
81
125
|
none: false
|
82
126
|
requirements:
|
83
127
|
- - ~>
|
@@ -89,10 +133,10 @@ dependencies:
|
|
89
133
|
version: 1.0.0
|
90
134
|
type: :development
|
91
135
|
prerelease: false
|
92
|
-
version_requirements: *
|
136
|
+
version_requirements: *id008
|
93
137
|
- !ruby/object:Gem::Dependency
|
94
138
|
name: jeweler
|
95
|
-
requirement: &
|
139
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
96
140
|
none: false
|
97
141
|
requirements:
|
98
142
|
- - ~>
|
@@ -104,10 +148,10 @@ dependencies:
|
|
104
148
|
version: 1.5.2
|
105
149
|
type: :development
|
106
150
|
prerelease: false
|
107
|
-
version_requirements: *
|
151
|
+
version_requirements: *id009
|
108
152
|
- !ruby/object:Gem::Dependency
|
109
153
|
name: rcov
|
110
|
-
requirement: &
|
154
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
111
155
|
none: false
|
112
156
|
requirements:
|
113
157
|
- - ">="
|
@@ -117,10 +161,11 @@ dependencies:
|
|
117
161
|
version: "0"
|
118
162
|
type: :development
|
119
163
|
prerelease: false
|
120
|
-
version_requirements: *
|
164
|
+
version_requirements: *id010
|
121
165
|
description: reads .SRF, .SQT and supports conversions
|
122
166
|
email: jtprince@gmail.com
|
123
167
|
executables:
|
168
|
+
- srf_to_pepxml.rb
|
124
169
|
- srf_to_search.rb
|
125
170
|
- srf_to_sqt.rb
|
126
171
|
extensions: []
|
@@ -138,22 +183,29 @@ files:
|
|
138
183
|
- README.rdoc
|
139
184
|
- Rakefile
|
140
185
|
- VERSION
|
186
|
+
- bin/srf_to_pepxml.rb
|
141
187
|
- bin/srf_to_search.rb
|
142
188
|
- bin/srf_to_sqt.rb
|
143
189
|
- lib/ms/sequest.rb
|
144
190
|
- lib/ms/sequest/bioworks.rb
|
145
191
|
- lib/ms/sequest/params.rb
|
146
192
|
- lib/ms/sequest/pepxml.rb
|
193
|
+
- lib/ms/sequest/pepxml/modifications.rb
|
194
|
+
- lib/ms/sequest/pepxml/params.rb
|
147
195
|
- lib/ms/sequest/sqt.rb
|
148
196
|
- lib/ms/sequest/srf.rb
|
197
|
+
- lib/ms/sequest/srf/pepxml.rb
|
198
|
+
- lib/ms/sequest/srf/pepxml/sequest.rb
|
149
199
|
- lib/ms/sequest/srf/search.rb
|
150
200
|
- lib/ms/sequest/srf/sqt.rb
|
151
201
|
- script/fasta_ipi_to_ncbi-ish.rb
|
152
202
|
- spec/ms/sequest/bioworks_spec.rb
|
153
203
|
- spec/ms/sequest/params_spec.rb
|
204
|
+
- spec/ms/sequest/pepxml/modifications_spec.rb
|
154
205
|
- spec/ms/sequest/pepxml_spec.rb
|
155
206
|
- spec/ms/sequest/sqt_spec.rb
|
156
207
|
- spec/ms/sequest/sqt_spec_helper.rb
|
208
|
+
- spec/ms/sequest/srf/pepxml_spec.rb
|
157
209
|
- spec/ms/sequest/srf/search_spec.rb
|
158
210
|
- spec/ms/sequest/srf/sqt_spec.rb
|
159
211
|
- spec/ms/sequest/srf_spec.rb
|
@@ -180,7 +232,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
180
232
|
requirements:
|
181
233
|
- - ">="
|
182
234
|
- !ruby/object:Gem::Version
|
183
|
-
hash:
|
235
|
+
hash: -2543561928840978627
|
184
236
|
segments:
|
185
237
|
- 0
|
186
238
|
version: "0"
|
@@ -202,9 +254,11 @@ summary: An mspire library supporting SEQUEST, Bioworks, SQT, etc
|
|
202
254
|
test_files:
|
203
255
|
- spec/ms/sequest/bioworks_spec.rb
|
204
256
|
- spec/ms/sequest/params_spec.rb
|
257
|
+
- spec/ms/sequest/pepxml/modifications_spec.rb
|
205
258
|
- spec/ms/sequest/pepxml_spec.rb
|
206
259
|
- spec/ms/sequest/sqt_spec.rb
|
207
260
|
- spec/ms/sequest/sqt_spec_helper.rb
|
261
|
+
- spec/ms/sequest/srf/pepxml_spec.rb
|
208
262
|
- spec/ms/sequest/srf/search_spec.rb
|
209
263
|
- spec/ms/sequest/srf/sqt_spec.rb
|
210
264
|
- spec/ms/sequest/srf_spec.rb
|