quorum 0.2.1 → 0.3.0

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.
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);