quorum 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/Gemfile.lock +35 -28
  2. data/HISTORY.md +4 -0
  3. data/app/assets/javascripts/quorum/application.js +1 -0
  4. data/app/assets/javascripts/quorum/jobs.js +5 -345
  5. data/app/assets/javascripts/quorum/quorum.js +275 -0
  6. data/app/assets/javascripts/quorum/template_settings.js +8 -0
  7. data/app/assets/javascripts/quorum/utilities.js +12 -0
  8. data/app/assets/stylesheets/quorum/application.css +0 -4
  9. data/app/assets/stylesheets/quorum/autohint.css +4 -0
  10. data/app/controllers/quorum/jobs_controller.rb +9 -9
  11. data/app/views/quorum/jobs/form/_blastn_form.html.erb +62 -62
  12. data/app/views/quorum/jobs/form/_blastp_form.html.erb +62 -62
  13. data/app/views/quorum/jobs/form/_blastx_form.html.erb +62 -62
  14. data/app/views/quorum/jobs/form/_tblastn_form.html.erb +62 -62
  15. data/app/views/quorum/jobs/show.html.erb +1 -1
  16. data/app/views/quorum/jobs/templates/_blast_detailed_report_template.html.erb +22 -22
  17. data/app/views/quorum/jobs/templates/_blast_template.html.erb +29 -29
  18. data/app/views/shared/_error_messages.html.erb +8 -8
  19. data/lib/quorum/version.rb +1 -1
  20. data/lib/tasks/jasmine.rake +8 -0
  21. data/quorum.gemspec +1 -0
  22. data/spec/data/seqs_not_fa.txt +16 -16
  23. data/spec/javascripts/fixtures/formatted_sequence.html +6 -0
  24. data/spec/javascripts/fixtures/quorum_search_form.html +461 -0
  25. data/spec/javascripts/fixtures/quorum_tabs.html +10 -0
  26. data/spec/javascripts/helpers/jasmine-jquery.js +288 -0
  27. data/spec/javascripts/jobs_spec.js +99 -0
  28. data/spec/javascripts/jquery/jquery-ui.min.js +791 -0
  29. data/spec/javascripts/jquery/jquery.min.js +4 -0
  30. data/spec/javascripts/jquery/jquery_ujs.js +373 -0
  31. data/spec/javascripts/quorum_spec.js +106 -0
  32. data/spec/javascripts/string_spec.js +18 -0
  33. data/spec/javascripts/support/jasmine.yml +84 -0
  34. data/spec/javascripts/support/jasmine_config.rb +23 -0
  35. data/spec/javascripts/support/jasmine_runner.rb +33 -0
  36. data/spec/requests/jobs_spec.rb +34 -33
  37. data/vendor/assets/javascripts/jquery.autohint.js +87 -0
  38. metadata +62 -26
@@ -0,0 +1,106 @@
1
+ //
2
+ // Test the methods not covered in RSpec request specs.
3
+ //
4
+
5
+ describe("QUORUM", function() {
6
+
7
+ //
8
+ // Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
9
+ //
10
+ // Blastn should increment qseq's title by 1 and hseq's title by 1.
11
+ //
12
+ it("formats blastn sequence report for Blast detailed report", function() {
13
+ var report = QUORUM.formatSequenceReport(
14
+ "ACGT", "|| |", "ACCT", 6, 9, 2, 8, "blastn"
15
+ );
16
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=7>C</a><a rel='quorum-tipsy' title=8>G</a><a rel='quorum-tipsy' title=9>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
17
+ });
18
+
19
+ //
20
+ // Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
21
+ //
22
+ // Blastx should increment qseq's title by 3 and hseq's title by 1.
23
+ //
24
+ it("formats blastx sequence report for Blast detailed report", function() {
25
+ var report = QUORUM.formatSequenceReport(
26
+ "ACGT", "|| |", "ACCT", 6, 9, 2, 8, "blastx"
27
+ );
28
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=9>C</a><a rel='quorum-tipsy' title=12>G</a><a rel='quorum-tipsy' title=15>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
29
+ });
30
+
31
+ //
32
+ // Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
33
+ //
34
+ // Tblastn should increment qseq's title by 1 and hseq's title by 3.
35
+ //
36
+ it("formats tblastn sequence report for Blast detailed report", function() {
37
+ var report = QUORUM.formatSequenceReport(
38
+ "ELVIS", "ELVIS", "ELVIS", 10, 14, 121, 136, "tblastn"
39
+ );
40
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=124>L</a><a rel='quorum-tipsy' title=127>V</a><a rel='quorum-tipsy' title=130>I</a><a rel='quorum-tipsy' title=133>S</a>\n\n</pre></span>");
41
+ });
42
+
43
+ //
44
+ // Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
45
+ //
46
+ // Blastp should increment qseq's title by 1 and hseq's title by 1.
47
+ //
48
+ it("formats blastx sequence report for Blast detailed report", function() {
49
+ var report = QUORUM.formatSequenceReport(
50
+ "ELVIS", "ELVIS", "ELVIS", 10, 14, 121, 125, "blastp"
51
+ );
52
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=122>L</a><a rel='quorum-tipsy' title=123>V</a><a rel='quorum-tipsy' title=124>I</a><a rel='quorum-tipsy' title=125>S</a>\n\n</pre></span>");
53
+ });
54
+
55
+ it("should display title via jquery.tipsy on mouse over hide on mouse out", function() {
56
+ loadFixtures('formatted_sequence.html');
57
+ $('a[rel=quorum-tipsy]').tipsy({ gravity: 's' });
58
+
59
+ $('a[rel=quorum-tipsy]').trigger('mouseover');
60
+ expect($('.tipsy')).toBeVisible();
61
+
62
+ $('a[rel=quorum-tipsy]').trigger('mouseout');
63
+ expect($('.tipsy')).not.toBeVisible();
64
+ });
65
+
66
+ it("prints hit strand as forward / forward for + / + intergers", function() {
67
+ expect(QUORUM.formatStrand(1, 1)).toEqual("forward / forward");
68
+ });
69
+
70
+ it("prints hit strand as forward / reverse for + / - integers", function() {
71
+ expect(QUORUM.formatStrand(1, -1)).toEqual("forward / reverse");
72
+ });
73
+
74
+ it("prints hit strand as reverse / forward for - / + integers", function() {
75
+ expect(QUORUM.formatStrand(-1, 1)).toEqual("reverse / forward");
76
+ });
77
+
78
+ it("prints hit strand as reverse / reverse for - / - integers", function() {
79
+ expect(QUORUM.formatStrand(-1, -1)).toEqual("reverse / reverse");
80
+ });
81
+
82
+ //
83
+ // Only print links to HSPs whers data id != focus.
84
+ //
85
+ it("prints HSP links", function() {
86
+ var focus = 1;
87
+ var group = "1,2";
88
+ var data = [
89
+ {"id":1,"hsp_group":"1,2","hsp_num":1},
90
+ {"id":2,"hsp_group":"1,2","hsp_num":2}
91
+ ];
92
+ var hsps = QUORUM.displayHspLinks(focus, group, data);
93
+ expect(hsps).toEqual("Related <a onclick=\"(QUORUM.openWindow('http://www.ncbi.nlm.nih.gov/books/NBK62051/def-item/blast_glossary.HSP','HSP', 800, 300))\">HSPs</a>: 1 <a onclick='(QUORUM.autoScroll(2, true))'>2</a> ");
94
+ });
95
+
96
+ it("opens url in a new window", function() {
97
+ spyOn(window, 'open');
98
+ var url = "http://google.com";
99
+ var name = "Google";
100
+ var width = 300;
101
+ var height = 300;
102
+ QUORUM.openWindow(url, name, width, height);
103
+ expect(window.open).toHaveBeenCalledWith(url, name, "width=" + width + ",height=" + height + ",scrollbars=yes");
104
+ });
105
+
106
+ });
@@ -0,0 +1,18 @@
1
+ describe("String", function() {
2
+
3
+ it("truncates a string to length n", function() {
4
+ var str = "this is a long string.";
5
+ expect(str.trunc(5)).toEqual("this...");
6
+ });
7
+
8
+ it("truncates a string to length n", function() {
9
+ var str = "this is a long string.";
10
+ expect(str.trunc(15)).toEqual("this is a long...");
11
+ });
12
+
13
+ it("doesn't truncate string when length is less than n", function() {
14
+ var str = "this is a long string.";
15
+ expect(str.trunc(50)).toEqual(str);
16
+ });
17
+
18
+ });
@@ -0,0 +1,84 @@
1
+ # src_files
2
+ #
3
+ # Return an array of filepaths relative to src_dir to include before jasmine specs.
4
+ # Default: []
5
+ #
6
+ # EXAMPLE:
7
+ #
8
+ # src_files:
9
+ # - lib/source1.js
10
+ # - lib/source2.js
11
+ # - dist/**/*.js
12
+ #
13
+ src_files:
14
+ - spec/javascripts/jquery/jquery.min.js
15
+ - spec/javascripts/jquery/jquery-ui.min.js
16
+ - spec/javascripts/jquery/jquery_ujs.js
17
+ - vendor/assets/javascripts/underscore-min.js
18
+ - app/assets/javascripts/quorum/jobs.js
19
+ - app/assets/javascripts/quorum/quorum.js
20
+ - app/assets/javascripts/quorum/utilities.js
21
+ - app/assets/javascripts/quorum/template_settings.js
22
+ - vendor/assets/javascripts/jquery.autohint.js
23
+ - vendor/assets/javascripts/jquery.tipsy.js
24
+
25
+ # stylesheets
26
+ #
27
+ # Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
28
+ # Default: []
29
+ #
30
+ # EXAMPLE:
31
+ #
32
+ # stylesheets:
33
+ # - css/style.css
34
+ # - stylesheets/*.css
35
+ #
36
+ stylesheets:
37
+
38
+ # helpers
39
+ #
40
+ # Return an array of filepaths relative to spec_dir to include before jasmine specs.
41
+ # Default: ["helpers/**/*.js"]
42
+ #
43
+ # EXAMPLE:
44
+ #
45
+ # helpers:
46
+ # - helpers/**/*.js
47
+ #
48
+ helpers:
49
+ - helpers/**/*.js
50
+
51
+ # spec_files
52
+ #
53
+ # Return an array of filepaths relative to spec_dir to include.
54
+ # Default: ["**/*[sS]pec.js"]
55
+ #
56
+ # EXAMPLE:
57
+ #
58
+ # spec_files:
59
+ # - **/*[sS]pec.js
60
+ #
61
+ spec_files:
62
+ - '**/*[sS]pec.js'
63
+
64
+ # src_dir
65
+ #
66
+ # Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
67
+ # Default: project root
68
+ #
69
+ # EXAMPLE:
70
+ #
71
+ # src_dir: public
72
+ #
73
+ src_dir:
74
+
75
+ # spec_dir
76
+ #
77
+ # Spec directory path. Your spec_files must be returned relative to this path.
78
+ # Default: spec/javascripts
79
+ #
80
+ # EXAMPLE:
81
+ #
82
+ # spec_dir: spec/javascripts
83
+ #
84
+ spec_dir: spec/javascripts
@@ -0,0 +1,23 @@
1
+ module Jasmine
2
+ class Config
3
+
4
+ # Add your overrides or custom config code here
5
+
6
+ end
7
+ end
8
+
9
+
10
+ # Note - this is necessary for rspec2, which has removed the backtrace
11
+ module Jasmine
12
+ class SpecBuilder
13
+ def declare_spec(parent, spec)
14
+ me = self
15
+ example_name = spec["name"]
16
+ @spec_ids << spec["id"]
17
+ backtrace = @example_locations[parent.description + " " + example_name]
18
+ parent.it example_name, {} do
19
+ me.report_spec(spec["id"])
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ $:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
2
+
3
+ require 'rubygems'
4
+ require File.expand_path("../../../dummy/config/environment", __FILE__)
5
+ require 'jasmine'
6
+ jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
7
+ require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
8
+ if Jasmine::Dependencies.rspec2?
9
+ require 'rspec'
10
+ else
11
+ require 'spec'
12
+ end
13
+
14
+ jasmine_config = Jasmine::Config.new
15
+ spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
16
+
17
+ should_stop = false
18
+
19
+ if Jasmine::Dependencies.rspec2?
20
+ RSpec.configuration.after(:suite) do
21
+ spec_builder.stop if should_stop
22
+ end
23
+ else
24
+ Spec::Runner.configure do |config|
25
+ config.after(:suite) do
26
+ spec_builder.stop if should_stop
27
+ end
28
+ end
29
+ end
30
+
31
+ spec_builder.start
32
+ should_stop = true
33
+ spec_builder.declare_suites
@@ -17,7 +17,7 @@ describe "Jobs" do
17
17
  click_button "Submit"
18
18
 
19
19
  page.should have_content("Please enter your sequence(s) in Plain Text " <<
20
- "as FASTA.")
20
+ "as FASTA.")
21
21
  end
22
22
  end
23
23
 
@@ -30,7 +30,7 @@ describe "Jobs" do
30
30
  attach_file "job_sequence_file", word_file
31
31
  click_button "Submit"
32
32
  page.should have_content("Please enter your sequence(s) in Plain Text " <<
33
- "as FASTA.")
33
+ "as FASTA.")
34
34
  end
35
35
  end
36
36
 
@@ -43,7 +43,7 @@ describe "Jobs" do
43
43
  attach_file "job_sequence_file", file
44
44
  click_button "Submit"
45
45
  page.should have_content("Please enter your sequence(s) in Plain Text " <<
46
- "as FASTA.")
46
+ "as FASTA.")
47
47
  end
48
48
  end
49
49
 
@@ -56,71 +56,72 @@ describe "Jobs" do
56
56
  ResqueSpec.inline = true
57
57
  end
58
58
  describe "submit sequences in attached file" do
59
- it "check algorithms, fill in values, view results and download hit sequence" do
60
- visit new_job_path
61
- current_path.should eq(new_job_path)
62
-
63
- nucl_seqs = File.expand_path("../../data/nucl_prot_seqs.txt", __FILE__)
64
- attach_file "job_sequence_file", nucl_seqs
65
-
59
+ it "check algorithms, fill in values, view results and download hit sequence" do
60
+ visit new_job_path
61
+ current_path.should eq(new_job_path)
62
+
63
+ nucl_seqs = File.expand_path("../../data/nucl_prot_seqs.txt", __FILE__)
64
+ attach_file "job_sequence_file", nucl_seqs
65
+
66
66
  # Blastn
67
- check "job_blastn_job_attributes_queue"
68
- select "tmp", :from => "job_blastn_job_attributes_blast_dbs"
67
+ check "job_blastn_job_attributes_queue"
68
+ select "tmp", :from => "job_blastn_job_attributes_blast_dbs"
69
69
  check "job_blastn_job_attributes_filter"
70
70
  fill_in "job_blastn_job_attributes_expectation", :with => "5e-20"
71
71
  fill_in "job_blastn_job_attributes_min_bit_score", :with => "0"
72
72
  fill_in "job_blastn_job_attributes_max_score", :with => "25"
73
73
  select "Yes", :from => "job_blastn_job_attributes_gapped_alignments"
74
74
  select "11, 2", :from => "job_blastn_job_attributes_gap_opening_extension"
75
-
75
+
76
76
  # Blastx
77
- check "job_blastx_job_attributes_queue"
78
- select "tmp", :from => "job_blastx_job_attributes_blast_dbs"
77
+ check "job_blastx_job_attributes_queue"
78
+ select "tmp", :from => "job_blastx_job_attributes_blast_dbs"
79
79
  check "job_blastx_job_attributes_filter"
80
80
  fill_in "job_blastx_job_attributes_expectation", :with => "5e-20"
81
81
  fill_in "job_blastx_job_attributes_min_bit_score", :with => "0"
82
82
  fill_in "job_blastx_job_attributes_max_score", :with => "25"
83
83
  select "Yes", :from => "job_blastx_job_attributes_gapped_alignments"
84
84
  select "10, 2", :from => "job_blastx_job_attributes_gap_opening_extension"
85
-
86
- # Tblastn
87
- check "job_tblastn_job_attributes_queue"
88
- select "tmp", :from => "job_tblastn_job_attributes_blast_dbs"
85
+
86
+ # Tblastn
87
+ check "job_tblastn_job_attributes_queue"
88
+ select "tmp", :from => "job_tblastn_job_attributes_blast_dbs"
89
89
  check "job_tblastn_job_attributes_filter"
90
90
  fill_in "job_tblastn_job_attributes_expectation", :with => "5e-20"
91
91
  fill_in "job_tblastn_job_attributes_min_bit_score", :with => "0"
92
92
  fill_in "job_tblastn_job_attributes_max_score", :with => "25"
93
93
  select "Yes", :from => "job_tblastn_job_attributes_gapped_alignments"
94
94
  select "9, 2", :from => "job_tblastn_job_attributes_gap_opening_extension"
95
-
96
- # Blastp
97
- check "job_blastp_job_attributes_queue"
98
- select "tmp", :from => "job_blastp_job_attributes_blast_dbs"
95
+
96
+ # Blastp
97
+ check "job_blastp_job_attributes_queue"
98
+ select "tmp", :from => "job_blastp_job_attributes_blast_dbs"
99
99
  check "job_blastp_job_attributes_filter"
100
100
  fill_in "job_blastp_job_attributes_expectation", :with => "5e-20"
101
101
  fill_in "job_blastp_job_attributes_min_bit_score", :with => "0"
102
102
  fill_in "job_blastp_job_attributes_max_score", :with => "25"
103
103
  select "Yes", :from => "job_blastp_job_attributes_gapped_alignments"
104
104
  select "13, 1", :from => "job_blastp_job_attributes_gap_opening_extension"
105
-
106
- click_button "Submit"
107
-
108
- page.should have_content("Search Results")
109
-
105
+
106
+ click_button "Submit"
107
+
108
+ page.should have_content("Search Results")
109
+
110
110
  click_link "Blastx"
111
- page.should have_content("Your search returned 0 hits.")
111
+ page.should have_content("Your search returned 0 hits.")
112
112
 
113
113
  click_link "Tblastn"
114
- page.should have_content("Your search returned 0 hits.")
114
+ page.should have_content("Your search returned 0 hits.")
115
115
 
116
116
  ## Interact with the Blast results. ##
117
117
  click_link "Blastn"
118
118
 
119
119
  # Render modal box.
120
- find("#blastn-results").find("td a").click
120
+ find("#blastn-results").find("td a").click
121
121
  page.should have_content("Quorum Report Details")
122
122
  page.should have_content("qseq")
123
123
  page.should have_content("hseq")
124
+
124
125
  # Download sequence
125
126
  find("p.small a#download_sequence_1").click
126
127
  page.should have_content("Fetching sequence...")
@@ -129,11 +130,11 @@ describe "Jobs" do
129
130
  click_link "Blastp"
130
131
 
131
132
  # Render modal box.
132
- find("#blastp-results").find("td a").click
133
+ find("#blastp-results").find("td a").click
133
134
  page.should have_content("Quorum Report Details")
134
135
  page.should have_content("qseq")
135
136
  page.should have_content("hseq")
136
- end
137
+ end
137
138
  end
138
139
  after(:all) do
139
140
  Capybara.use_default_driver
@@ -0,0 +1,87 @@
1
+ //
2
+ // jQuery autoHint
3
+ //
4
+ // v0.2.0
5
+ // Ken Seal hunzinker@gmail.com
6
+ // License: MIT
7
+
8
+ (function($) {
9
+
10
+ var methods = {
11
+
12
+ init: function() {
13
+ return this.each(function() {
14
+ var $this = $(this);
15
+ $this.autoHint('addHints');
16
+ $this.autoHint('focusHint');
17
+ $this.autoHint('blurHint');
18
+ });
19
+ },
20
+
21
+ // Add hints to the form elements.
22
+ addHints: function() {
23
+ return this.each(function() {
24
+ var $this = $(this);
25
+ if ($this.attr('title') === '') {
26
+ return;
27
+ }
28
+
29
+ if ($this.val() === '') {
30
+ $this.val($this.attr('title'));
31
+
32
+ if (!$this.hasClass('auto-hint')) {
33
+ $this.addClass('auto-hint');
34
+ }
35
+ } else {
36
+ $this.removeClass('auto-hint');
37
+ }
38
+ });
39
+ },
40
+
41
+ // Remove hint and class on focus.
42
+ focusHint: function() {
43
+ return this.focus(function() {
44
+ var $this = $(this);
45
+ if ($this.val() === $this.attr('title')) {
46
+ $this.val('');
47
+ $this.removeClass('auto-hint');
48
+ }
49
+ });
50
+ },
51
+
52
+ // Retain value or add hint.
53
+ blurHint: function() {
54
+ return this.blur(function() {
55
+ var $this = $(this);
56
+ if ($this.val() === '' && $this.attr('title') !== '') {
57
+ $this.val($this.attr('title'));
58
+ $this.addClass('auto-hint');
59
+ }
60
+ });
61
+ },
62
+
63
+ // Remove hints.
64
+ removeHints: function() {
65
+ return this.each(function() {
66
+ var $this = $(this);
67
+ if ($this.val() === $this.attr('title')) {
68
+ $this.val('');
69
+ }
70
+ });
71
+ }
72
+
73
+ };
74
+
75
+ $.fn.autoHint = function(method) {
76
+
77
+ if (methods[method]) {
78
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
79
+ } else if (typeof method === 'object' || !method) {
80
+ return methods.init.apply(this, arguments);
81
+ } else {
82
+ $.error('Method ' + method + ' does not exist for jQuery autoHint.');
83
+ }
84
+
85
+ };
86
+
87
+ })(jQuery);