genomer 0.0.5

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.
@@ -0,0 +1,101 @@
1
+ require 'unindent'
2
+ require 'tempfile'
3
+ require 'ronn/index'
4
+ require 'ronn/document'
5
+
6
+ class Genomer::Runtime
7
+
8
+ attr :command
9
+ attr :arguments
10
+ attr :flags
11
+
12
+ def initialize(settings)
13
+ @command = settings.rest.shift
14
+ @arguments = settings.rest
15
+ @flags = settings
16
+ end
17
+
18
+ def execute!
19
+ case command
20
+ when nil then short_help
21
+ when "help" then help
22
+ when "init" then init
23
+ when "man" then man
24
+ else run_plugin
25
+ end
26
+ end
27
+
28
+ def short_help
29
+ msg =<<-EOF
30
+ genomer COMMAND [options]
31
+ run `genomer help` for a list of available commands
32
+ EOF
33
+ msg.unindent
34
+ end
35
+
36
+ def help
37
+ msg =<<-EOF
38
+ genomer COMMAND [options]
39
+
40
+ Available commands:
41
+ init Create a new genomer project
42
+ man View man page for the specified plugin
43
+ EOF
44
+ msg.unindent!
45
+
46
+ msg << Genomer::Plugin.plugins.inject(String.new) do |str,p|
47
+ str << ' '
48
+ str << p.name.gsub("genomer-plugin-","").ljust(12)
49
+ str << p.summary
50
+ str << "\n"
51
+ end
52
+ msg.strip
53
+ end
54
+
55
+ def man
56
+ if not arguments.empty?
57
+ man_file_location = man_file(arguments.clone)
58
+ unless File.exists?(man_file_location)
59
+ raise Genomer::Error, "No manual entry for command '#{arguments.join(' ')}'"
60
+ end
61
+
62
+ Kernel.exec "man #{groffed_man_file(man_file_location).path}"
63
+ else
64
+ msg =<<-EOF
65
+ genomer man COMMAND
66
+ run `genomer help` for a list of available commands
67
+ EOF
68
+ msg.unindent!
69
+ msg.strip
70
+ end
71
+ end
72
+
73
+ def man_file(arguments)
74
+ plugin = arguments.first
75
+ page = arguments.unshift("genomer").join('-') << ".ronn"
76
+ File.join(Genomer::Plugin.fetch(plugin).full_gem_path, 'man', page)
77
+ end
78
+
79
+ def groffed_man_file(original_man_file)
80
+ converted_man = Tempfile.new("genome-manpage-")
81
+ File.open(converted_man.path,'w') do |out|
82
+ out.puts Ronn::Document.new(original_man_file).convert('roff')
83
+ end
84
+ converted_man
85
+ end
86
+
87
+ def init
88
+ project_name = arguments.first
89
+ if File.exists?(project_name)
90
+ raise Genomer::Error, "Directory '#{project_name}' already exists."
91
+ else
92
+ Dir.mkdir project_name
93
+ Dir.mkdir File.join(project_name,'assembly')
94
+ end
95
+ end
96
+
97
+ def run_plugin
98
+ Genomer::Plugin[command].new(arguments,flags).run
99
+ end
100
+
101
+ end
@@ -0,0 +1,3 @@
1
+ module Genomer
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,20 @@
1
+ genomer-init(1) -- create a new genomer project
2
+ ===============================================
3
+
4
+ ## SYNOPSIS
5
+
6
+ `genomer init` <project-name>
7
+
8
+ ## DESCRIPTION
9
+
10
+ Creates a new genomer project directory named **project-name**. Returns an
11
+ error if the project directory already exists.
12
+
13
+ ## BUGS
14
+
15
+ **Genomer-init** is written in Ruby and uses several RubyGems dependencies. See
16
+ the Gemfile in the genomer gem install directory for version details.
17
+
18
+ ## COPYRIGHT
19
+
20
+ **Genomer** is Copyright (C) 2011 Michael Barton <http://michaelbarton.me.uk>
@@ -0,0 +1,341 @@
1
+ require 'spec_helper'
2
+
3
+ describe Genomer::Plugin do
4
+
5
+ describe "#[]" do
6
+
7
+ before do
8
+ mock(described_class).plugins do
9
+ [Gem::Specification.new do |s|
10
+ s.name = 'genomer-plugin-simple'
11
+ end]
12
+ end
13
+ end
14
+
15
+ describe "fetching an available plugin" do
16
+
17
+ before do
18
+ mock(described_class).require('genomer-plugin-simple')
19
+ end
20
+
21
+ it "should return the class for this plugin" do
22
+ expected = GenomerPluginSimple = Class.new
23
+ described_class['simple'].should == expected
24
+ end
25
+
26
+ end
27
+
28
+ describe "fethcing an unavailble plugin" do
29
+
30
+ it "should print an error message" do
31
+ error = "Unknown command or plugin 'unknown.'\n"
32
+ error << "run `genomer help` for a list of available commands\n"
33
+ lambda{ described_class['unknown'] }.should raise_error(Genomer::Error,error)
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ describe "#plugins" do
41
+
42
+ before do
43
+ mock(Bundler).setup do
44
+ mock!.gems{ gems }
45
+ end
46
+ end
47
+
48
+ describe "where a single genomer plugin is specified" do
49
+
50
+ let(:gems) do
51
+ [Gem::Specification.new do |s|
52
+ s.name = 'genomer-plugin-simple'
53
+ end]
54
+ end
55
+
56
+ it "should return the genomer plugin" do
57
+ described_class.plugins.should == gems
58
+ end
59
+
60
+ end
61
+
62
+ describe "where no gems at all are specified" do
63
+
64
+ let(:gems) do
65
+ []
66
+ end
67
+
68
+ it "should return an empty array" do
69
+ described_class.plugins.should be_empty
70
+ end
71
+
72
+ end
73
+
74
+ describe "where one plugin and one non-plugin are specified" do
75
+
76
+ let(:gems) do
77
+ [Gem::Specification.new{|s| s.name = 'genomer-plugin-simple' },
78
+ Gem::Specification.new{|s| s.name = 'not-a-plugin' }]
79
+ end
80
+
81
+ it "should return the genomer plugin" do
82
+ described_class.plugins.should == [gems.first]
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ describe "#to_class_name" do
90
+
91
+ it "should dash separated words to camel case" do
92
+ described_class.to_class_name('words-with-dashes').should == "WordsWithDashes"
93
+ end
94
+
95
+ end
96
+
97
+ describe "#scaffold" do
98
+
99
+ let(:entries) do
100
+ [Sequence.new(:name => 'seq1', :sequence => 'ATGC')]
101
+ end
102
+
103
+ let (:sequence_file) do
104
+ File.new("assembly/sequence.fna",'w')
105
+ end
106
+
107
+ let (:scaffold_file) do
108
+ File.new("assembly/scaffold.yml",'w')
109
+ end
110
+
111
+ before do
112
+ Dir.mkdir('assembly')
113
+ write_sequence_file(entries,sequence_file)
114
+ write_scaffold_file(entries,scaffold_file)
115
+ end
116
+
117
+ after do
118
+ FileUtils.rm_rf 'assembly'
119
+ end
120
+
121
+ subject do
122
+ described_class.new(nil,nil)
123
+ end
124
+
125
+ it "should return the expected scaffold built from the scaffold files" do
126
+ subject.scaffold.length.should == 1
127
+ end
128
+
129
+ end
130
+
131
+ describe "#annotations" do
132
+
133
+ before do
134
+ Dir.mkdir('assembly')
135
+ write_sequence_file(entries, File.new("assembly/sequence.fna",'w'))
136
+ write_scaffold_file(entries, File.new("assembly/scaffold.yml",'w'))
137
+ generate_gff3_file(records, File.new("assembly/annotations.gff",'w'))
138
+ end
139
+
140
+ after do
141
+ FileUtils.rm_rf 'assembly'
142
+ end
143
+
144
+ let(:entries) do
145
+ [Sequence.new(:name => 'seq1', :sequence => 'ATGCATGCATGC')]
146
+ end
147
+
148
+ let(:annotation) do
149
+ Annotation.new(
150
+ :seqname => 'seq1',
151
+ :start => 1,
152
+ :end => 3,
153
+ :feature => 'gene',
154
+ :attributes => {'ID' => 'gene1'})
155
+ end
156
+
157
+ let(:options) do
158
+ {}
159
+ end
160
+
161
+ subject do
162
+ described_class.new(nil,nil).annotations(options)
163
+ end
164
+
165
+ describe "with no annotations" do
166
+
167
+ let(:records) do
168
+ []
169
+ end
170
+
171
+ it "should return one annotation entry" do
172
+ subject.length.should == 0
173
+ end
174
+
175
+ end
176
+
177
+ describe "with one annotation" do
178
+
179
+ let(:records) do
180
+ [annotation]
181
+ end
182
+
183
+ it "should return no annotations" do
184
+ subject.length.should == 1
185
+ end
186
+
187
+ end
188
+
189
+ describe "with one contig annotation and one non-contig annotation" do
190
+
191
+ let(:records) do
192
+ [annotation,annotation.clone.seqname('seq2')]
193
+ end
194
+
195
+ it "should return only the contig annotation" do
196
+ subject.length.should == 1
197
+ end
198
+
199
+ end
200
+
201
+ describe "with multiple unordered annotations" do
202
+
203
+ let(:records) do
204
+ [
205
+ annotation.clone.start(4).end(6),
206
+ annotation.clone.start(7).end(9),
207
+ annotation
208
+ ]
209
+ end
210
+
211
+ it "should return the annotations in order" do
212
+ subject[0].start.should == 1
213
+ subject[1].start.should == 4
214
+ subject[2].start.should == 7
215
+ end
216
+
217
+ end
218
+
219
+ describe "with the prefix option" do
220
+
221
+ let(:records) do
222
+ [annotation]
223
+ end
224
+
225
+ let(:options) do
226
+ {:prefix => 'pre_'}
227
+ end
228
+
229
+ it "should prefix the annotation id" do
230
+ subject.first.id.should == 'pre_gene1'
231
+ end
232
+
233
+ end
234
+
235
+ describe "with reset numbering" do
236
+
237
+ let(:records) do
238
+ [
239
+ annotation.clone.start(4).end(6),
240
+ annotation.clone.start(7).end(9),
241
+ annotation
242
+ ]
243
+ end
244
+
245
+ let(:options) do
246
+ {:reset => true}
247
+ end
248
+
249
+ it "should reset the locus tag numbering at 000001" do
250
+ subject[0].id.should == '000001'
251
+ subject[1].id.should == '000002'
252
+ subject[2].id.should == '000003'
253
+ end
254
+
255
+ end
256
+
257
+ describe "with reset numbering and an argument" do
258
+
259
+ let(:records) do
260
+ [
261
+ annotation.clone.start(4).end(6),
262
+ annotation.clone.start(7).end(9),
263
+ annotation
264
+ ]
265
+ end
266
+
267
+ let(:options) do
268
+ {:reset => '5'}
269
+ end
270
+
271
+ it "should reset the locus tag numbering starting at 000005" do
272
+ subject[0].id.should == '000005'
273
+ subject[1].id.should == '000006'
274
+ subject[2].id.should == '000007'
275
+ end
276
+
277
+ end
278
+
279
+ describe "with the reset numbering and prefix option" do
280
+
281
+ let(:records) do
282
+ [
283
+ annotation.clone.start(4).end(6),
284
+ annotation.clone.start(7).end(9),
285
+ annotation
286
+ ]
287
+ end
288
+
289
+ let(:options) do
290
+ {:reset => true, :prefix => 'pre_'}
291
+ end
292
+
293
+ it "should prefix and reset the locus tag numbering at 000001" do
294
+ subject[0].id.should == 'pre_000001'
295
+ subject[1].id.should == 'pre_000002'
296
+ subject[2].id.should == 'pre_000003'
297
+ end
298
+
299
+ end
300
+
301
+ describe "with reset numbering given an argument and the prefix option" do
302
+
303
+ let(:records) do
304
+ [
305
+ annotation.clone.start(4).end(6),
306
+ annotation.clone.start(7).end(9),
307
+ annotation
308
+ ]
309
+ end
310
+
311
+ let(:options) do
312
+ {:reset => '5', :prefix => 'pre_'}
313
+ end
314
+
315
+ it "should prefix and reset the locus tag numbering at 000005" do
316
+ subject[0].id.should == 'pre_000005'
317
+ subject[1].id.should == 'pre_000006'
318
+ subject[2].id.should == 'pre_000007'
319
+ end
320
+
321
+ end
322
+
323
+ end
324
+
325
+ describe "#initialize" do
326
+
327
+ subject do
328
+ described_class.new(:arguments,:flags)
329
+ end
330
+
331
+ it "should set the #arguments attribute" do
332
+ subject.arguments.should == :arguments
333
+ end
334
+
335
+ it "should set the #flags attribute" do
336
+ subject.arguments.should == :arguments
337
+ end
338
+
339
+ end
340
+
341
+ end