genevalidatorapp 1.4.13 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +5 -1
- data/bin/genevalidatorapp +227 -73
- data/config.ru +1 -1
- data/genevalidatorapp.gemspec +7 -6
- data/lib/genevalidatorapp.rb +247 -0
- data/lib/{GeneValidatorApp → genevalidatorapp}/config.rb +7 -6
- data/lib/{GeneValidatorApp → genevalidatorapp}/database.rb +8 -13
- data/lib/genevalidatorapp/exceptions.rb +162 -0
- data/lib/{GeneValidatorApp → genevalidatorapp}/genevalidator.rb +52 -58
- data/lib/{GeneValidatorApp → genevalidatorapp}/logger.rb +0 -0
- data/lib/genevalidatorapp/routes.rb +81 -0
- data/lib/genevalidatorapp/server.rb +63 -0
- data/lib/{GeneValidatorApp → genevalidatorapp}/version.rb +1 -1
- data/public/{web_files → src}/css/bootstrap1.min.css +0 -0
- data/public/{web_files → src}/css/custom.css +8 -13
- data/public/{web_files → src}/css/custom.min.css +0 -0
- data/public/{web_files → src}/css/font-awesome.min.css +0 -0
- data/public/{web_files → src}/js/bionode-seq.min.js +0 -0
- data/public/{web_files → src}/js/bootstrap.min.js +0 -0
- data/public/{web_files → src}/js/d3.v3.min.js +0 -0
- data/public/{web_files → src}/js/genevalidator.js +44 -49
- data/public/{web_files → src}/js/jquery.cookie.min.js +0 -0
- data/public/{web_files → src}/js/jquery.min.js +0 -0
- data/public/{web_files → src}/js/jquery.tablesorter.min.js +0 -0
- data/public/{web_files → src}/js/jquery.validate.min.js +0 -0
- data/public/src/js/plots.js +814 -0
- data/public/web_files/css/GV_compiled_css.min.css +15 -0
- data/public/web_files/js/GV_compiled_js.min.js +34 -0
- data/spec/app_spec.rb +1 -1
- data/spec/database_spec.rb +2 -2
- data/views/index.slim +1 -1
- data/views/layout.slim +15 -24
- data/views/results.slim +54 -0
- metadata +39 -35
- data/lib/GeneValidatorApp.rb +0 -321
- data/public/web_files/css/bootstrap.min.css +0 -7
- data/public/web_files/js/genevalidator.min.js +0 -1
- data/public/web_files/js/plots.js +0 -744
- data/public/web_files/js/plots.min.js +0 -1
File without changes
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/cross_origin'
|
3
|
+
require 'genevalidator/version'
|
4
|
+
require 'genevalidatorapp/version'
|
5
|
+
require 'slim'
|
6
|
+
|
7
|
+
module GeneValidatorApp
|
8
|
+
# The Sinatra Routes
|
9
|
+
class Routes < Sinatra::Base
|
10
|
+
register Sinatra::CrossOrigin
|
11
|
+
|
12
|
+
configure do
|
13
|
+
# We don't need Rack::MethodOverride. Let's avoid the overhead.
|
14
|
+
disable :method_override
|
15
|
+
|
16
|
+
# Ensure exceptions never leak out of the app. Exceptions raised within
|
17
|
+
# the app must be handled by the app. We do this by attaching error
|
18
|
+
# blocks to exceptions we know how to handle and attaching to Exception
|
19
|
+
# as fallback.
|
20
|
+
disable :show_exceptions, :raise_errors
|
21
|
+
|
22
|
+
# Make it a policy to dump to 'rack.errors' any exception raised by the
|
23
|
+
# app so that error handlers don't have to do it themselves. But for it
|
24
|
+
# to always work, Exceptions defined by us should not respond to `code`
|
25
|
+
# or http_status` methods. Error blocks errors must explicitly set http
|
26
|
+
# status, if needed, by calling `status` method.
|
27
|
+
enable :dump_errors
|
28
|
+
|
29
|
+
# We don't want Sinatra do setup any loggers for us. We will use our own.
|
30
|
+
set :logging, nil
|
31
|
+
|
32
|
+
# This is the app root...
|
33
|
+
set :root, lambda { GeneValidatorApp.root }
|
34
|
+
|
35
|
+
# This is the full path to the public folder...
|
36
|
+
set :public_folder, lambda { GeneValidatorApp.public_dir }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set up global variables for the templates...
|
40
|
+
before '/' do
|
41
|
+
@default_db = Database.default_db
|
42
|
+
@non_default_dbs = Database.non_default_dbs
|
43
|
+
@max_characters = GeneValidatorApp.config[:max_characters]
|
44
|
+
@current_gv_version = GeneValidator::VERSION
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/' do
|
48
|
+
slim :index
|
49
|
+
end
|
50
|
+
|
51
|
+
post '/' do
|
52
|
+
cross_origin # Required for the API to work...
|
53
|
+
RunGeneValidator.init(request.url, params)
|
54
|
+
@json_results = RunGeneValidator.run
|
55
|
+
slim :results, layout: false
|
56
|
+
end
|
57
|
+
|
58
|
+
# This error block will only ever be hit if the user gives us a funny
|
59
|
+
# sequence or incorrect advanced parameter. Well, we could hit this block
|
60
|
+
# if someone is playing around with our HTTP API too.
|
61
|
+
error RunGeneValidator::ArgumentError do
|
62
|
+
status 400
|
63
|
+
slim :"500", layout: false
|
64
|
+
end
|
65
|
+
|
66
|
+
# This will catch any unhandled error and some very special errors. Ideally
|
67
|
+
# we will never hit this block. If we do, there's a bug in GeneValidatorApp
|
68
|
+
# or something really weird going on.
|
69
|
+
# TODO: If we hit this error block we show the stacktrace to the user
|
70
|
+
# requesting them to post the same to our Google Group.
|
71
|
+
error Exception, RunGeneValidator::RuntimeError do
|
72
|
+
status 500
|
73
|
+
slim :"500", layout: false
|
74
|
+
end
|
75
|
+
|
76
|
+
not_found do
|
77
|
+
status 404
|
78
|
+
slim :"500" # TODO: Create another Template
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rack/handler/webrick'
|
2
|
+
|
3
|
+
module GeneValidatorApp
|
4
|
+
# Simple wrapper around WEBrick and Rack::Handler::WEBrick to host
|
5
|
+
# GeneValidatorApp standalone.
|
6
|
+
class Server
|
7
|
+
class << self
|
8
|
+
def run(*args)
|
9
|
+
new(*args).start
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(app)
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :app
|
18
|
+
|
19
|
+
# Start server. Raises Errno::EADDRINUSE if port is in use by another
|
20
|
+
# process. Raises Errno::EACCES if binding to the port requires root
|
21
|
+
# privilege.
|
22
|
+
def start
|
23
|
+
setup_signal_handlers
|
24
|
+
@server = WEBrick::HTTPServer.new(options)
|
25
|
+
@server.mount '/', Rack::Handler::WEBrick, app
|
26
|
+
@server.start
|
27
|
+
end
|
28
|
+
|
29
|
+
# Stop server.
|
30
|
+
def stop
|
31
|
+
@server.shutdown
|
32
|
+
end
|
33
|
+
|
34
|
+
# Options Hash passed to WEBrick::HTTPServer.
|
35
|
+
# rubocop:disable Metrics/AbcSize
|
36
|
+
def options
|
37
|
+
@options ||= {
|
38
|
+
:BindAddress => app.config[:host],
|
39
|
+
:Port => app.config[:port],
|
40
|
+
:StartCallback => proc { app.on_start },
|
41
|
+
:StopCallback => proc { app.on_stop },
|
42
|
+
:OutputBufferSize => 5,
|
43
|
+
:AccessLog => [[logdev, WEBrick::AccessLog::COMMON_LOG_FORMAT]],
|
44
|
+
:Logger => WEBrick::Log.new(logdev)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
# rubocop:enable Metrics/AbcSize
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def setup_signal_handlers
|
52
|
+
[:INT, :TERM].each do |sig|
|
53
|
+
trap sig do
|
54
|
+
stop
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def logdev
|
60
|
+
@logdev ||= app.verbose? ? STDERR : '/dev/null'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
File without changes
|
@@ -6,7 +6,7 @@ html {
|
|
6
6
|
}
|
7
7
|
|
8
8
|
body {
|
9
|
-
margin: 0;
|
9
|
+
margin: 0;
|
10
10
|
margin-top: 60px;
|
11
11
|
background-color:#F5F5F5;
|
12
12
|
}
|
@@ -175,7 +175,7 @@ table .danger,
|
|
175
175
|
.table .danger,
|
176
176
|
table .info,
|
177
177
|
.table .info {
|
178
|
-
color: #333;
|
178
|
+
color: #333;
|
179
179
|
}
|
180
180
|
|
181
181
|
.table-bordered {
|
@@ -245,11 +245,11 @@ table .info,
|
|
245
245
|
.table-bordered>tbody>tr>td,
|
246
246
|
.table-bordered>tfoot>tr>td {
|
247
247
|
border:none;
|
248
|
-
}
|
248
|
+
}
|
249
249
|
|
250
250
|
.table-bordered>tbody>tr {
|
251
251
|
border-bottom: 2px solid #DDD;
|
252
|
-
}
|
252
|
+
}
|
253
253
|
|
254
254
|
.error_header {
|
255
255
|
margin-top: 10px;
|
@@ -291,11 +291,6 @@ tr {
|
|
291
291
|
text-align: center;
|
292
292
|
}
|
293
293
|
|
294
|
-
/* table striped backgrounds ___________*/
|
295
|
-
|
296
|
-
/*tbody > tr:nth-child(4n+1), tbody > tr:nth-child(4n+2) {
|
297
|
-
}
|
298
|
-
*/
|
299
294
|
/* table sorter ___________*/
|
300
295
|
|
301
296
|
|
@@ -337,7 +332,7 @@ tr {
|
|
337
332
|
.table tbody td.success,
|
338
333
|
.table tbody td.danger,
|
339
334
|
.table tbody td.warning {
|
340
|
-
padding-left:30px !important;
|
335
|
+
padding-left:30px !important;
|
341
336
|
position:relative;
|
342
337
|
}
|
343
338
|
|
@@ -390,7 +385,7 @@ ___________________________*/
|
|
390
385
|
border-right:5px solid transparent;
|
391
386
|
border-top:5px solid #CCC
|
392
387
|
}
|
393
|
-
|
388
|
+
|
394
389
|
/* D3Js & Axis
|
395
390
|
___________________________*/
|
396
391
|
.axis path,
|
@@ -490,7 +485,7 @@ ___________________________*/
|
|
490
485
|
float:right !important;
|
491
486
|
margin-top: -43px;
|
492
487
|
}
|
493
|
-
|
488
|
+
|
494
489
|
.show_examples_text {
|
495
490
|
text-align: left;
|
496
491
|
}
|
@@ -501,7 +496,7 @@ ___________________________*/
|
|
501
496
|
}
|
502
497
|
|
503
498
|
|
504
|
-
/* Browser Specific
|
499
|
+
/* Browser Specific
|
505
500
|
___________________________*/
|
506
501
|
|
507
502
|
/* Border on Stars ________*/
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -4,6 +4,7 @@ $(document).ready(function() {
|
|
4
4
|
keepFooterFixedToBottom();
|
5
5
|
addSeqValidation();
|
6
6
|
inputValidation();
|
7
|
+
bindTdClicks();
|
7
8
|
|
8
9
|
$(document).bind('keydown', function (e) {
|
9
10
|
if (e.ctrlKey && e.keyCode === 13 ) {
|
@@ -12,9 +13,9 @@ $(document).ready(function() {
|
|
12
13
|
});
|
13
14
|
});
|
14
15
|
|
15
|
-
// Looks for a cookie (called 'GeneValidator_adv_params_status') to check the state of the adv_params box when it was last closed.
|
16
|
-
// This function is called upon as soon as the website is loaded;
|
17
|
-
function
|
16
|
+
// Looks for a cookie (called 'GeneValidator_adv_params_status') to check the state of the adv_params box when it was last closed.
|
17
|
+
// This function is called upon as soon as the website is loaded;
|
18
|
+
var checkCollapseState = function () {
|
18
19
|
'use strict';
|
19
20
|
if ($.cookie('GeneValidator_adv_params_status')){
|
20
21
|
var adv_params_status = $.cookie('GeneValidator_adv_params_status');
|
@@ -24,25 +25,26 @@ function checkCollapseState() {
|
|
24
25
|
$('#adv_params').addClass('in');
|
25
26
|
}
|
26
27
|
}
|
27
|
-
}
|
28
|
+
};
|
28
29
|
|
29
30
|
// This function simply ensures that the footer stays to fixed to the bottom of the window
|
30
|
-
function
|
31
|
+
var keepFooterFixedToBottom = function () {
|
31
32
|
'use strict';
|
32
33
|
$('#mainbody').css({'margin-bottom': (($('#footer').height()) + 15)+'px'});
|
33
34
|
$(window).resize(function(){
|
34
35
|
$('#mainbody').css({'margin-bottom': (($('#footer').height()) + 15)+'px'});
|
35
36
|
});
|
36
|
-
}
|
37
|
+
};
|
37
38
|
|
38
39
|
// Creates a custom Validation for Jquery Validation plugin...
|
39
40
|
// It ensures that sequences are either protein or DNA data...
|
40
41
|
// If there are multiple sequences, ensures that they are of the same type
|
41
42
|
// It utilises the checkType function (further below)...
|
42
|
-
function
|
43
|
+
var addSeqValidation = function () {
|
43
44
|
'use strict';
|
44
45
|
jQuery.validator.addMethod('checkInputType', function(value, element) {
|
45
|
-
var types = []
|
46
|
+
var types = [],
|
47
|
+
type = '';
|
46
48
|
if (value.charAt(0) === '>') {
|
47
49
|
var seqs_array = value.split('>');
|
48
50
|
for (var i = 1; i < seqs_array.length; i++) {
|
@@ -52,13 +54,13 @@ function addSeqValidation() {
|
|
52
54
|
if (clean_lines.length !== 0){
|
53
55
|
clean_lines.shift();
|
54
56
|
var seq = clean_lines.join('');
|
55
|
-
|
57
|
+
type = checkType(seq, 0.9);
|
56
58
|
types.push(type);
|
57
59
|
if ((type !== 'protein') && (type !== 'dna') && (type !== 'rna')) {
|
58
60
|
return false;
|
59
61
|
}
|
60
62
|
}
|
61
|
-
}
|
63
|
+
}
|
62
64
|
}
|
63
65
|
var firstType = types[0];
|
64
66
|
for (var j = 0; j < types.length; j++) {
|
@@ -68,7 +70,7 @@ function addSeqValidation() {
|
|
68
70
|
}
|
69
71
|
return true;
|
70
72
|
} else {
|
71
|
-
|
73
|
+
type = checkType(value, 0.9);
|
72
74
|
if ((type !== 'protein') && (type !== 'dna') && (type !== 'rna')) {
|
73
75
|
return false;
|
74
76
|
} else {
|
@@ -76,11 +78,11 @@ function addSeqValidation() {
|
|
76
78
|
}
|
77
79
|
}
|
78
80
|
}, '* The Input must be either DNA or protein sequence(s). Please ensure that your sequences do not contains any non-letter character(s). If there are multiple sequences, ensure that they are all of one type. ');
|
79
|
-
}
|
81
|
+
};
|
80
82
|
|
81
83
|
|
82
84
|
// A function that validates the input - Utilises Jquery.Validator.js
|
83
|
-
function
|
85
|
+
var inputValidation = function () {
|
84
86
|
'use strict';
|
85
87
|
var maxCharacters = $('#seq').attr('data-maxCharacters'); // returns a number or undefined
|
86
88
|
$('#input').validate({
|
@@ -123,10 +125,22 @@ function inputValidation() {
|
|
123
125
|
ajaxFunction();
|
124
126
|
}
|
125
127
|
});
|
126
|
-
}
|
128
|
+
};
|
129
|
+
|
130
|
+
var bindTdClicks = function () {
|
131
|
+
$( document ).on( "click", "td, .plot_btn", function( event ) {
|
132
|
+
if ($(this).hasClass('success') || $(this).hasClass('danger')){
|
133
|
+
var title = $(this).attr('title');
|
134
|
+
var val = title.replace(/[ \/]/g, '');
|
135
|
+
GV.addData(this, val);
|
136
|
+
} else if ($(this).hasClass('plot_btn')){
|
137
|
+
GV.addData(this, 'all');
|
138
|
+
}
|
139
|
+
});
|
140
|
+
};
|
127
141
|
|
128
142
|
// Sends the data within the form to the Server
|
129
|
-
function
|
143
|
+
var ajaxFunction = function () {
|
130
144
|
'use strict';
|
131
145
|
$.ajax({
|
132
146
|
type: 'POST',
|
@@ -135,15 +149,15 @@ function ajaxFunction() {
|
|
135
149
|
success: function(response){
|
136
150
|
$('#results_box').show();
|
137
151
|
$('#output').html(response);
|
152
|
+
GV.toggleOverviewBtn(); // add overview info from JSON
|
138
153
|
initTableSorter(); // initiate the table sorter
|
139
154
|
$("[data-toggle='tooltip']").tooltip(); // Initiate the tooltips
|
140
|
-
removeEmptyColumns(); // Remove Unwanted Columns
|
141
155
|
|
142
156
|
$('#mainbody').css({'background-color': '#fff'});
|
143
157
|
$('#search').css({'background-color': '#F5F5F5'});
|
144
158
|
$('#results').css({'border-top': '3px solid #DBDBDB'});
|
145
159
|
$('#search').css({'margin-bottom': '0'});
|
146
|
-
|
160
|
+
|
147
161
|
$('#spinner').modal('hide'); // remove progress notification
|
148
162
|
},
|
149
163
|
error: function (e, status) {
|
@@ -161,11 +175,11 @@ function ajaxFunction() {
|
|
161
175
|
}
|
162
176
|
}
|
163
177
|
});
|
164
|
-
}
|
178
|
+
};
|
165
179
|
|
166
|
-
// Table sortert Initialiser
|
167
|
-
// Contains a custom parser that allows the Stars to be sorted.
|
168
|
-
function
|
180
|
+
// Table sortert Initialiser
|
181
|
+
// Contains a custom parser that allows the Stars to be sorted.
|
182
|
+
var initTableSorter = function () {
|
169
183
|
'use strict';
|
170
184
|
$.tablesorter.addParser({
|
171
185
|
id: 'star_scores',
|
@@ -174,7 +188,7 @@ function initTableSorter() {
|
|
174
188
|
var $cell = $(cell);
|
175
189
|
if (cellIndex === 1) {
|
176
190
|
return $cell.attr('data-score') || s;
|
177
|
-
}
|
191
|
+
}
|
178
192
|
return s;
|
179
193
|
},
|
180
194
|
parsed: false,
|
@@ -187,29 +201,10 @@ function initTableSorter() {
|
|
187
201
|
},
|
188
202
|
sortList: [[0,0]],
|
189
203
|
});
|
190
|
-
}
|
191
|
-
|
192
|
-
// Remove empty colums that are not used for that type of input data...
|
193
|
-
function removeEmptyColumns() {
|
194
|
-
'use strict';
|
195
|
-
$('#sortable_table tr th').each(function(i) {
|
196
|
-
var tds = $(this).parents('table') // Select all tds in column
|
197
|
-
.find('tr td:nth-child(' + (i + 1) + ')');
|
198
|
-
// Check if all cells in the column are empty
|
199
|
-
if ($(this).hasClass( 'chart-column' )) {
|
200
|
-
} else {
|
201
|
-
if ($(this).text().trim() == '') {
|
202
|
-
//hide header
|
203
|
-
$(this).hide();
|
204
|
-
//hide cells
|
205
|
-
tds.hide();
|
206
|
-
}
|
207
|
-
}
|
208
|
-
});
|
209
|
-
}
|
204
|
+
};
|
210
205
|
|
211
206
|
// Function is called each time the Adv. Params button is pressed...
|
212
|
-
function
|
207
|
+
var changeAdvParamsBtnText = function () {
|
213
208
|
'use strict';
|
214
209
|
var btn = document.getElementById('adv_params_btn');
|
215
210
|
if (btn.innerHTML === '<i class="fa fa-pencil-square-o"></i> Show Advanced Parameters') {
|
@@ -222,10 +217,10 @@ function changeAdvParamsBtnText() {
|
|
222
217
|
$('#adv_params').collapse('hide');
|
223
218
|
$.cookie('GeneValidator_adv_params_status', 'closed');
|
224
219
|
}
|
225
|
-
}
|
220
|
+
};
|
226
221
|
|
227
222
|
// Changes the input to an examplar dna or protein sequence...
|
228
|
-
function
|
223
|
+
var examplarSequence = function (type){
|
229
224
|
'use strict';
|
230
225
|
var dna = '>Insulin\n' +
|
231
226
|
'ATGGCTCTCTGGATCCGGTCGCTGCCTCTCCTGGCCCTTCTTGCTCTTTCTGGCCCTGGGATCAGCCACGCAGCTGCCAACCAGCACCTCTGTGGCTCCCACTTGGTTGAGGCTCTCTACCTGGTGTGTGGGGAGCGGGGTTTCTTCTACTCCCCCAAAACACGGCGGGACGTTGAGCAGCCTCTAGTGAACGGTCCCCTGCATGGCGAGGTGGGAGAGCTGCCGTTCCAGCATGAGGAATACCAGAAAGTCAAGCGAGGCATCGTTGAGCAATGCTGTGAAAACCCGTGCTCCCTCTACCAACTGGAAAACTACTGCAACTAG\n' +
|
@@ -241,11 +236,11 @@ function examplarSequence(type){
|
|
241
236
|
} else if (type === 'protein') {
|
242
237
|
document.getElementById('seq').value = protein;
|
243
238
|
}
|
244
|
-
}
|
239
|
+
};
|
245
240
|
|
246
241
|
// FROM BIONODE-Seq - See https://github.com/bionode/bionode-seq
|
247
242
|
// Checks whether a sequence is a protein or dna sequence...
|
248
|
-
function
|
243
|
+
var checkType = function (sequence, threshold, length, index) {
|
249
244
|
'use strict';
|
250
245
|
if (threshold === undefined) {
|
251
246
|
threshold = 0.9;
|
@@ -263,7 +258,7 @@ function checkType(sequence, threshold, length, index) {
|
|
263
258
|
var acgMatch = ((dnaSeq.match(/[ACG]/gi) || []).length) / dnaTotal;
|
264
259
|
var tMatch = ((dnaSeq.match(/[T]/gi) || []).length) / dnaTotal;
|
265
260
|
var uMatch = ((dnaSeq.match(/[U]/gi) || []).length) / dnaTotal;
|
266
|
-
|
261
|
+
|
267
262
|
var proteinSeq = seq.replace(/X/gi,'');
|
268
263
|
var proteinTotal = proteinSeq.length;
|
269
264
|
var proteinMatch = ((seq.match(/[ARNDCQEGHILKMFPSTWYV\*]/gi) || []).length) / proteinTotal;
|
@@ -279,4 +274,4 @@ function checkType(sequence, threshold, length, index) {
|
|
279
274
|
} else if (proteinMatch >= threshold) {
|
280
275
|
return 'protein';
|
281
276
|
}
|
282
|
-
}
|
277
|
+
};
|