neurohmmerapp 0.0.1

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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +81 -0
  5. data/LICENSE.txt +661 -0
  6. data/README.md +96 -0
  7. data/Rakefile +21 -0
  8. data/bin/neurohmmerapp +166 -0
  9. data/config.ru +3 -0
  10. data/lib/neurohmmerapp/config.rb +87 -0
  11. data/lib/neurohmmerapp/exceptions.rb +77 -0
  12. data/lib/neurohmmerapp/logger.rb +24 -0
  13. data/lib/neurohmmerapp/neurohmmer.rb +158 -0
  14. data/lib/neurohmmerapp/routes.rb +79 -0
  15. data/lib/neurohmmerapp/server.rb +63 -0
  16. data/lib/neurohmmerapp/version.rb +3 -0
  17. data/lib/neurohmmerapp.rb +207 -0
  18. data/neurohmmerapp.gemspec +50 -0
  19. data/public/NeuroHmmer/loading.html +12 -0
  20. data/public/src/css/bootstrap1.min.css +7 -0
  21. data/public/src/css/custom.css +189 -0
  22. data/public/src/css/custom.min.css +1 -0
  23. data/public/src/css/font-awesome.min.css +4 -0
  24. data/public/src/js/bionode-seq.min.js +1 -0
  25. data/public/src/js/bootstrap.min.js +6 -0
  26. data/public/src/js/jquery.cookie.min.js +1 -0
  27. data/public/src/js/jquery.min.js +4 -0
  28. data/public/src/js/jquery.validate.min.js +4 -0
  29. data/public/src/js/neurohmmer.js +228 -0
  30. data/public/src/js/neurohmmer.min.js +1 -0
  31. data/public/web_files/css/nh_compiled_css.min.css +14 -0
  32. data/public/web_files/fonts/FontAwesome.otf +0 -0
  33. data/public/web_files/fonts/fontawesome-webfont.eot +0 -0
  34. data/public/web_files/fonts/fontawesome-webfont.svg +504 -0
  35. data/public/web_files/fonts/fontawesome-webfont.ttf +0 -0
  36. data/public/web_files/fonts/fontawesome-webfont.woff +0 -0
  37. data/public/web_files/js/nh_compiled_js.min.js +20 -0
  38. data/spec/empty_config.yml +0 -0
  39. data/spec/route_spec.rb +72 -0
  40. data/views/500.slim +5 -0
  41. data/views/index.slim +38 -0
  42. data/views/layout.slim +74 -0
  43. data/views/results.slim +9 -0
  44. metadata +281 -0
@@ -0,0 +1,79 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/cross_origin'
3
+ require 'neurohmmer/version'
4
+ require 'neurohmmerapp/version'
5
+ require 'slim'
6
+
7
+ module NeuroHmmerApp
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 { NeuroHmmerApp.root }
34
+
35
+ # This is the full path to the public folder...
36
+ set :public_folder, lambda { NeuroHmmerApp.public_dir }
37
+ end
38
+
39
+ # Set up global variables for the templates...
40
+ before '/' do
41
+ @max_characters = NeuroHmmerApp.config[:max_characters]
42
+ @current_neurohmmer_version = '0.1'
43
+ end
44
+
45
+ get '/' do
46
+ slim :index
47
+ end
48
+
49
+ post '/' do
50
+ cross_origin # Required for the API to work...
51
+ RunNeuroHmmer.init(request.url, params)
52
+ @neurohmmer_results = RunNeuroHmmer.run
53
+ slim :results, layout: false
54
+ end
55
+
56
+ # This error block will only ever be hit if the user gives us a funny
57
+ # sequence or incorrect advanced parameter. Well, we could hit this block
58
+ # if someone is playing around with our HTTP API too.
59
+ error RunNeuroHmmer::ArgumentError do
60
+ status 400
61
+ slim :"500", layout: false
62
+ end
63
+
64
+ # This will catch any unhandled error and some very special errors. Ideally
65
+ # we will never hit this block. If we do, there's a bug in NeuroHmmerApp
66
+ # or something really weird going on.
67
+ # TODO: If we hit this error block we show the stacktrace to the user
68
+ # requesting them to post the same to our Google Group.
69
+ error Exception, RunNeuroHmmer::RuntimeError do
70
+ status 500
71
+ slim :"500", layout: false
72
+ end
73
+
74
+ not_found do
75
+ status 404
76
+ slim :"500" # TODO: Create another Template
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,63 @@
1
+ require 'rack/handler/webrick'
2
+
3
+ module NeuroHmmerApp
4
+ # Simple wrapper around WEBrick and Rack::Handler::WEBrick to host
5
+ # NeuroHmmerApp 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
@@ -0,0 +1,3 @@
1
+ module NeuroHmmerApp
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,207 @@
1
+ require 'yaml'
2
+ require 'fileutils'
3
+
4
+ require 'neurohmmerapp/config'
5
+ require 'neurohmmerapp/exceptions'
6
+ require 'neurohmmerapp/neurohmmer'
7
+ require 'neurohmmerapp/logger'
8
+ require 'neurohmmerapp/routes'
9
+ require 'neurohmmerapp/server'
10
+ require 'neurohmmerapp/version'
11
+
12
+ module NeuroHmmerApp
13
+ # Use a fixed minimum version of BLAST+
14
+ MINIMUM_HMMER_VERSION = '3.0.0'
15
+
16
+ class << self
17
+ def environment
18
+ ENV['RACK_ENV']
19
+ end
20
+
21
+ def verbose?
22
+ @verbose ||= (environment == 'development')
23
+ end
24
+
25
+ def root
26
+ File.dirname(File.dirname(__FILE__))
27
+ end
28
+
29
+ def logger
30
+ @logger ||= Logger.new(STDERR, verbose?)
31
+ end
32
+
33
+ # Setting up the environment before running the app...
34
+ def init(config = {})
35
+ @config = Config.new(config)
36
+
37
+ init_binaries
38
+ init_dirs
39
+
40
+ load_extension
41
+ check_num_threads
42
+ check_max_characters
43
+ self
44
+ end
45
+
46
+ attr_reader :config, :temp_dir, :public_dir
47
+
48
+ # Starting the app manually
49
+ def run
50
+ check_host
51
+ Server.run(self)
52
+ rescue Errno::EADDRINUSE
53
+ puts "** Could not bind to port #{config[:port]}."
54
+ puts " Is NeuroHmmer already accessible at #{server_url}?"
55
+ puts ' No? Try running NeuroHmmer on another port, like so:'
56
+ puts
57
+ puts ' neurohmmerapp -p 4570.'
58
+ rescue Errno::EACCES
59
+ puts "** Need root privilege to bind to port #{config[:port]}."
60
+ puts ' It is not advisable to run NeuroHmmer as root.'
61
+ puts ' Please use Apache/Nginx to bind to a privileged port.'
62
+ end
63
+
64
+ def on_start
65
+ puts '** NeuroHmmer is ready.'
66
+ puts " Go to #{server_url} in your browser and start analysing genes!"
67
+ puts ' Press CTRL+C to quit.'
68
+ open_in_browser(server_url)
69
+ end
70
+
71
+ def on_stop
72
+ puts
73
+ puts '** Thank you for using NeuroHmmerApp :).'
74
+ puts ' Please cite: '
75
+ puts ' Moghul M.I., Elphick M & Wurm Y (in prep).'
76
+ puts ' NeuroHmmer: identify Neuropeptide Precursors.'
77
+ end
78
+
79
+ # Rack-interface.
80
+ #
81
+ # Inject our logger in the env and dispatch request to our controller.
82
+ def call(env)
83
+ env['rack.logger'] = logger
84
+ Routes.call(env)
85
+ end
86
+
87
+ private
88
+
89
+ def init_dirs
90
+ config[:public_dir] = File.expand_path(config[:public_dir])
91
+ unique_start_id = 'NH_' + "#{Time.now.strftime('%Y%m%d-%H-%M-%S')}"
92
+ @public_dir = File.join(config[:public_dir], unique_start_id)
93
+ init_public_dir
94
+ end
95
+
96
+ # Create the Public Dir and copy files from gem root - this public dir
97
+ # is served by the app is accessible at URL/...
98
+ def init_public_dir
99
+ FileUtils.mkdir_p(File.join(@public_dir, 'NeuroHmmer'))
100
+ root_web_files = File.join(NeuroHmmerApp.root, 'public/web_files')
101
+ root_gv = File.join(NeuroHmmerApp.root, 'public/NeuroHmmer')
102
+ FileUtils.cp_r(root_web_files, @public_dir)
103
+ FileUtils.cp_r(root_gv, @public_dir)
104
+ end
105
+
106
+ def init_binaries
107
+ config[:bin] = init_bins if config[:bin]
108
+ assert_blast_installed_and_compatible
109
+ assert_mafft_installed
110
+ end
111
+
112
+ def load_extension
113
+ return unless config[:require]
114
+ config[:require] = File.expand_path config[:require]
115
+ unless File.exist?(config[:require]) && File.file?(config[:require])
116
+ fail EXTENSION_FILE_NOT_FOUND, config[:require]
117
+ end
118
+
119
+ logger.debug("Loading extension: #{config[:require]}")
120
+ require config[:require]
121
+ end
122
+
123
+ def check_num_threads
124
+ num_threads = Integer(config[:num_threads])
125
+ fail NUM_THREADS_INCORRECT unless num_threads > 0
126
+
127
+ logger.debug "Will use #{num_threads} threads to run BLAST."
128
+ if num_threads > 256
129
+ logger.warn "Number of threads set at #{num_threads} is unusually high."
130
+ end
131
+ rescue
132
+ raise NUM_THREADS_INCORRECT
133
+ end
134
+
135
+ def check_max_characters
136
+ if config[:max_characters] != 'undefined'
137
+ config[:max_characters] = Integer(config[:max_characters])
138
+ end
139
+ rescue
140
+ raise MAX_CHARACTERS_INCORRECT
141
+ end
142
+
143
+ def init_bins
144
+ bins = []
145
+ config[:bin].each do |bin|
146
+ bins << File.expand_path(bin)
147
+ unless File.exist?(bin) && File.directory?(bin)
148
+ fail BIN_DIR_NOT_FOUND, config[:bin]
149
+ end
150
+ export_bin_dir(bin)
151
+ end
152
+ bins
153
+ end
154
+
155
+ ## Checks if dir is in $PATH and if not, it adds the dir to the $PATH.
156
+ def export_bin_dir(bin_dir)
157
+ return unless bin_dir
158
+ return if ENV['PATH'].split(':').include?(bin_dir)
159
+ ENV['PATH'] = "#{bin_dir}:#{ENV['PATH']}"
160
+ end
161
+
162
+ def assert_blast_installed_and_compatible
163
+ fail HMMER_NOT_INSTALLED unless command? 'hmmscan'
164
+ # version = `hmmscan -version`.split[1]
165
+ # fail HMMER_NOT_COMPATIBLE, version unless version >= MINIMUM_HMMER_VERSION
166
+ end
167
+
168
+ def assert_mafft_installed
169
+ fail MAFFT_NOT_INSTALLED unless command? 'mafft'
170
+ end
171
+
172
+ # Check and warn user if host is 0.0.0.0 (default).
173
+ def check_host
174
+ return unless config[:host] == '0.0.0.0'
175
+ logger.warn 'Will listen on all interfaces (0.0.0.0).' \
176
+ ' Consider using 127.0.0.1 (--host option).'
177
+ end
178
+
179
+ def server_url
180
+ host = config[:host]
181
+ host = 'localhost' if host == '127.0.0.1' || host == '0.0.0.0'
182
+ "http://#{host}:#{config[:port]}"
183
+ end
184
+
185
+ def open_in_browser(server_url)
186
+ return if using_ssh? || verbose?
187
+ if RUBY_PLATFORM =~ /linux/ && xdg?
188
+ system "xdg-open #{server_url}system"
189
+ elsif RUBY_PLATFORM =~ /darwin/
190
+ system "open #{server_url}system"
191
+ end
192
+ end
193
+
194
+ def using_ssh?
195
+ true if ENV['SSH_CLIENT'] || ENV['SSH_TTY'] || ENV['SSH_CONNECTION']
196
+ end
197
+
198
+ def xdg?
199
+ true if ENV['DISPLAY'] && command?('xdg-open')
200
+ end
201
+
202
+ # Return `true` if the given command exists and is executable.
203
+ def command?(command)
204
+ system("which #{command} > /dev/null 2>&1")
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,50 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'neurohmmerapp/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'neurohmmerapp'
8
+ spec.version = NeuroHmmerApp::VERSION
9
+ spec.authors = ['Ismail Moghul', 'Yannick Wurm']
10
+ spec.email = 'y.wurm@qmul.ac.uk'
11
+ spec.summary = 'A Web App wrapper for NeuroHmmer.'
12
+ spec.description = 'A Web App wrapper for NeuroHmmer, a program for' \
13
+ ' validating gene predictions.'
14
+ spec.homepage = 'https://github.com/wurmlab/neurohmmerapp'
15
+ spec.license = 'AGPL'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.required_ruby_version = '>= 2.0.0'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.6'
25
+ spec.add_development_dependency 'rake', '~>10.3'
26
+ spec.add_development_dependency('rspec', '~> 2.8', '>= 2.8.0')
27
+ spec.add_development_dependency 'rack-test', '~> 0.6'
28
+ spec.add_development_dependency('capybara', '~> 2.4', '>= 2.4.4')
29
+ spec.add_development_dependency 'w3c_validators', '~>1.1'
30
+
31
+ spec.add_dependency 'neurohmmer', '~>0.1'
32
+ spec.add_dependency 'bio', '~>1.4'
33
+ spec.add_dependency 'sinatra', '~>1.4'
34
+ spec.add_dependency 'sinatra-cross_origin', '~> 0.3'
35
+ spec.add_dependency 'slim', '~>3.0'
36
+ spec.add_dependency 'slop', '~>3.6'
37
+ spec.post_install_message = <<INFO
38
+
39
+ ------------------------------------------------------------------------
40
+ Thank you for Installing the NeuroHmmer App!
41
+
42
+ To launch NeuroHmmerApp execute 'neurohmmerapp' from command line.
43
+
44
+ $ neurohmmerapp [options]
45
+
46
+ Visit https://github.com/wurmlab/neurohmmerapp for more information.
47
+ ------------------------------------------------------------------------
48
+
49
+ INFO
50
+ end
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html><html><head><title>NeuroHmmer: Identify Neuropeptide Precursors</title><meta content="text/html; charset=utf-8" http-equiv="Content-Type"><link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/flatly/bootstrap.min.css"><link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
2
+ <style type="text/css">html{position:relative;min-height:100%;}body{margin:0 0 100px;background-color:#F5F5F5}footer{bottom:0;width:100%;margin:0 auto;position:absolute;height:100px;overflow:hidden;border-top:2px solid #DBDBDB;padding-top:10px;color:#b4bcc2}
3
+ </style></head>
4
+ <body>
5
+ <div class="container text-center">
6
+ <h1 style="font-size: 78px">NeuroHmmer</h1>
7
+ <h4 style="margin-bottom:3em">Identify Neuropeptide Precursors</h4>
8
+ <i class="fa fa-spinner fa-spin" style="font-size: 10em"></i>
9
+ <h2> Calculating...</h2>
10
+ <p class="results_link"> This may take some time. Please leave this page open.</p>
11
+ </div>
12
+ <footer><div class="container center-block"><p class="text-muted text-center">Please cite: "Moghul MI, Elphick M &amp; Wurm Y <em>(in prep)</em> NeuroHmmer: Identify Neuropeptide Precursors"<br/> Developed at <a href="https://wurmlab.github.io" target="_blank">Wurm Lab</a>, <a href="http://www.sbcs.qmul.ac.uk" target="_blank">QMUL</a> with funding by <a href="http://www.bbsrc.ac.uk/home/home.aspx" target="_blank">BBSRC</a><br/>This page was created by <a href="https://github.com/wurmlab/neurohmmer" target="_blank" >NeuroHmmer</a> v0.01</p></div></footer></body></html>