opentox-ruby-api-wrapper 1.2.5 → 1.2.6

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.
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  gem.email = "helma@in-silico.ch"
11
11
  gem.homepage = "http://github.com/helma/opentox-ruby-api-wrapper"
12
12
  gem.authors = ["Christoph Helma"]
13
- ["sinatra", "rest-client", "rack", "rack-contrib", "thin", "emk-sinatra-url-for", "cehoffman-sinatra-respond_to", "dm-more", "dm-core"].each do |dep|
13
+ ["sinatra", "rest-client", "rack", "rack-contrib", "rack-flash", "thin", "emk-sinatra-url-for", "cehoffman-sinatra-respond_to", "dm-more", "dm-core", "sinatra-static-assets"].each do |dep|
14
14
  gem.add_dependency dep
15
15
  end
16
16
  gem.add_development_dependency "cucumber"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.5
1
+ 1.2.6
data/lib/compound.rb CHANGED
@@ -20,13 +20,21 @@ module OpenTox
20
20
  @inchi = RestClient.get("#{@@cactus_uri}#{params[:name]}/stdinchi").chomp
21
21
  @uri = File.join(@@config[:services]["opentox-compound"],URI.escape(@inchi))
22
22
  elsif params[:uri]
23
- @inchi = params[:uri].sub(/^.*InChI/, 'InChI')
24
23
  @uri = params[:uri]
24
+ if params[:uri].match(/InChI/) # shortcut for IST services
25
+ @inchi = params[:uri].sub(/^.*InChI/, 'InChI')
26
+ else
27
+ @inchi = RestClient.get @uri, :accept => 'chemical/x-inchi'
28
+ # AMBIT does not provide InChIs
29
+ #smiles = RestClient.get(@uri, :accept => 'chemical/x-daylight-smiles').split(/\s+/).first # fix ambit output
30
+ #@inchi = obconversion(smiles,'smi','inchi')
31
+ end
25
32
  end
26
33
  end
27
34
 
28
35
  # Get the (canonical) smiles
29
36
  def smiles
37
+ #RestClient.get(@uri, :accept => 'chemical/x-daylight-smiles').split(/\s+/).first # fix ambit output
30
38
  obconversion(@inchi,'inchi','can')
31
39
  end
32
40
 
data/lib/dataset.rb CHANGED
@@ -85,14 +85,11 @@ module OpenTox
85
85
  end
86
86
 
87
87
  def self.find(uri)
88
- begin
89
- dataset = Dataset.new
90
- data = RestClient.get uri, :accept => 'application/rdf+xml' # check if the resource is available
91
- dataset.rdf = data
92
- dataset
93
- rescue
94
- nil
95
- end
88
+ dataset = Dataset.new
89
+ data = `curl "#{uri}"`
90
+ #data = RestClient.get uri, :accept => 'application/rdf+xml' # unclear why this does not work for complex uris, Dataset.find works from irb
91
+ dataset.rdf = data
92
+ dataset
96
93
  end
97
94
 
98
95
  def features
@@ -107,57 +104,44 @@ module OpenTox
107
104
  data = {}
108
105
  @model.subjects(RDF['type'], OT['DataEntry']).each do |data_entry|
109
106
  compound_node = @model.object(data_entry, OT['compound'])
110
- @model.find(compound_node, OT['identifier'],nil) {|s,p,o| puts o.to_s}
111
107
  compound_uri = @model.object(compound_node, DC['identifier']).to_s
112
- data[compound_uri] = [] unless data[compound_uri]
113
108
  @model.find(data_entry, OT['values'], nil) do |s,p,values|
114
- entry = {}
115
109
  feature_node = @model.object values, OT['feature']
116
- feature_uri = @model.object(feature_node, DC['identifier']).to_s
117
- # TODO simple features
110
+ feature_uri = @model.object(feature_node, DC['identifier']).to_s.sub(/\^\^.*$/,'') # remove XML datatype
118
111
  type = @model.object(values, RDF['type'])
119
112
  if type == OT['FeatureValue']
120
- #entry[feature_uri] = [] unless entry[feature_uri]
121
- entry[feature_uri] = @model.object(values, OT['value']).to_s
113
+ value = @model.object(values, OT['value']).to_s
114
+ case value.to_s
115
+ when TRUE_REGEXP # defined in environment.rb
116
+ value = true
117
+ when FALSE_REGEXP # defined in environment.rb
118
+ value = false
119
+ else
120
+ LOGGER.warn compound_uri + " has value '" + value.to_s + "' for feature " + feature_uri
121
+ value = nil
122
+ end
123
+ data[compound_uri] = {} unless data[compound_uri]
124
+ data[compound_uri][feature_uri] = [] unless data[compound_uri][feature_uri]
125
+ data[compound_uri][feature_uri] << value unless value.nil?
122
126
  elsif type == OT['Tuple']
123
- entry[feature_uri] = {} unless entry[feature_uri]
127
+ entry = {}
128
+ data[compound_uri] = {} unless data[compound_uri]
129
+ data[compound_uri][feature_uri] = [] unless data[compound_uri][feature_uri]
124
130
  @model.find(values, OT['complexValue'],nil) do |s,p,complex_value|
125
131
  name_node = @model.object complex_value, OT['feature']
126
132
  name = @model.object(name_node, DC['title']).to_s
127
133
  value = @model.object(complex_value, OT['value']).to_s
128
- entry[feature_uri][name] = value
134
+ v = value.sub(/\^\^.*$/,'') # remove XML datatype
135
+ v = v.to_f if v.match(/^[\.|\d]+$/) # guess numeric datatype
136
+ entry[name] = v
129
137
  end
138
+ data[compound_uri][feature_uri] << entry
130
139
  end
131
- data[compound_uri] << entry
132
140
  end
133
141
  end
134
142
  data
135
143
  end
136
144
 
137
- def feature_values(feature_uri)
138
- features = {}
139
- feature = @model.subject(DC["identifier"],feature_uri)
140
- @model.subjects(RDF['type'], OT["Compound"]).each do |compound_node|
141
- compound = @model.object(compound_node, DC["identifier"]).to_s.sub(/^\[(.*)\]$/,'\1')
142
- features[compound] = [] unless features[compound]
143
- data_entry = @model.subject(OT['compound'], compound_node)
144
- @model.find( data_entry, OT['values'], nil ) do |s,p,values|
145
- if feature == @model.object(values, OT['feature'])
146
- value = @model.object(values, OT['value'])
147
- case value.to_s
148
- when "true"
149
- features[compound] << true
150
- when "false"
151
- features[compound] << false
152
- else
153
- features[compound] << value.to_s
154
- end
155
- end
156
- end
157
- end
158
- features
159
- end
160
-
161
145
  def compounds
162
146
  compounds = []
163
147
  @model.subjects(RDF['type'], OT["Compound"]).each do |compound_node|
@@ -183,7 +167,8 @@ module OpenTox
183
167
  :source => self.source,
184
168
  :identifier => self.identifier,
185
169
  :compounds => self.compounds.collect{|c| c.to_s.to_s.sub(/^\[(.*)\]$/,'\1')},
186
- :features => self.features.collect{|f| f.to_s }
170
+ :features => self.features.collect{|f| f.to_s },
171
+ :data => self.data
187
172
  }.to_yaml
188
173
  end
189
174
 
data/lib/environment.rb CHANGED
@@ -1,21 +1,27 @@
1
+ require 'logger'
1
2
  # set default environment
2
3
  ENV['RACK_ENV'] = 'test' unless ENV['RACK_ENV']
3
4
 
4
5
  # load configuration
5
6
  basedir = File.join(ENV['HOME'], ".opentox")
6
7
  config_dir = File.join(basedir, "config")
7
- @@tmp_dir = File.join(basedir, "tmp")
8
8
  config_file = File.join(config_dir, "#{ENV['RACK_ENV']}.yaml")
9
9
 
10
+ TMP_DIR = File.join(basedir, "tmp")
11
+ LOG_DIR = File.join(basedir, "log")
12
+
10
13
  if File.exist?(config_file)
11
14
  @@config = YAML.load_file(config_file)
12
15
  else
13
- FileUtils.mkdir_p config_dir
14
- FileUtils.mkdir_p @@tmp_dir
16
+ FileUtils.mkdir_p TMP_DIR
17
+ FileUtils.mkdir_p LOG_DIR
15
18
  FileUtils.cp(File.join(File.dirname(__FILE__), 'templates/config.yaml'), config_file)
16
19
  puts "Please edit #{config_file} and restart your application."
17
20
  exit
18
21
  end
22
+ logfile = "#{LOG_DIR}/#{ENV["RACK_ENV"]}.log"
23
+ LOGGER = Logger.new(logfile,'daily') # daily rotation
24
+ LOGGER.level = Logger::DEBUG
19
25
 
20
26
  # RDF namespaces
21
27
  RDF = Redland::Namespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
@@ -23,19 +29,6 @@ OWL = Redland::Namespace.new 'http://www.w3.org/2002/07/owl#'
23
29
  DC = Redland::Namespace.new 'http://purl.org/dc/elements/1.1/'
24
30
  OT = Redland::Namespace.new 'http://www.opentox.org/api/1.1#'
25
31
 
26
- # configure redis database
27
- =begin
28
- begin
29
- case ENV['RACK_ENV']
30
- when 'production'
31
- @@redis = Redis.new :db => 0
32
- when 'development'
33
- @@redis = Redis.new :db => 1
34
- when 'test'
35
- @@redis = Redis.new :db => 2
36
- @@redis.flush_db
37
- end
38
- rescue
39
- puts "Redis database not running, please start it with 'rake redis:start'."
40
- end
41
- =end
32
+ # Regular expressions for parsing classification data
33
+ TRUE_REGEXP = /^(true|active|1)/
34
+ FALSE_REGEXP = /^(false|inactive|0)/
data/lib/model.rb CHANGED
@@ -31,6 +31,11 @@ module OpenTox
31
31
  def self.find_all
32
32
  RestClient.get(@@config[:services]["opentox-model"]).split("\n")
33
33
  end
34
+
35
+ def self.find(uri)
36
+ yaml = RestClient.get(uri, :accept => "application/x-yaml")
37
+ OpenTox::Model::Lazar.from_yaml(yaml)
38
+ end
34
39
 
35
40
  # Predict a compound
36
41
  def predict(compound)
@@ -46,7 +51,7 @@ module OpenTox
46
51
  end
47
52
 
48
53
  def endpoint
49
- YAML.load(RestClient.get uri)[:endpoint]
54
+ YAML.load(RestClient.get(uri))[:endpoint]
50
55
  end
51
56
 
52
57
  def algorithm=(algorithm)
data/lib/owl.rb CHANGED
@@ -42,7 +42,8 @@ module OpenTox
42
42
  # I have no idea, why 2 subjects are returned
43
43
  # iterating over all subjects leads to memory allocation problems
44
44
  # SPARQL queries also do not work
45
- me = @model.subjects(RDF['type'],OT[self.owl_class])[1]
45
+ #me = @model.subjects(RDF['type'],OT[self.owl_class])[1]
46
+ me = @model.subject(RDF['type'],OT[self.owl_class])
46
47
  @model.object(me, DC['title']).to_s
47
48
  end
48
49
 
data/lib/task.rb CHANGED
@@ -22,6 +22,11 @@ module OpenTox
22
22
  @@config[:services]["opentox-task"]
23
23
  end
24
24
 
25
+ def self.all
26
+ task_uris = RestClient.get(@@config[:services]["opentox-task"]).split(/\n/)
27
+ task_uris.collect{|uri| Task.new(uri)}
28
+ end
29
+
25
30
  def started
26
31
  #LOGGER.info File.join(@uri,'started')
27
32
  RestClient.put File.join(@uri,'started'), {}
@@ -35,6 +40,14 @@ module OpenTox
35
40
  RestClient.put File.join(@uri,'completed'), :resource => uri
36
41
  end
37
42
 
43
+ def created_at
44
+ RestClient.get File.join(@uri, 'created_at')
45
+ end
46
+
47
+ def finished_at
48
+ RestClient.get File.join(@uri, 'finished_at')
49
+ end
50
+
38
51
  def status
39
52
  RestClient.get File.join(@uri, 'status')
40
53
  end
@@ -42,6 +55,10 @@ module OpenTox
42
55
  def resource
43
56
  RestClient.get File.join(@uri, 'resource')
44
57
  end
58
+
59
+ def pid=(pid)
60
+ RestClient.put File.join(@uri, 'pid'), :pid => pid
61
+ end
45
62
 
46
63
  def completed?
47
64
  self.status.to_s == 'completed'
@@ -49,7 +66,7 @@ module OpenTox
49
66
 
50
67
  def wait_for_completion
51
68
  until self.completed?
52
- sleep 0.1
69
+ sleep 1
53
70
  end
54
71
  end
55
72
 
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+ require 'rack/contrib'
4
+ require 'application.rb'
5
+
6
+ # log at centralized place
7
+ logfile = "#{LOG_DIR}/#{ENV["RACK_ENV"]}.log"
8
+ log = File.new(logfile, "a+")
9
+ $stdout.reopen(log)
10
+ $stderr.reopen(log)
11
+ $stdout.sync = true
12
+ $stderr.sync = true
13
+ set :raise_errors, true
14
+
15
+ ['public','tmp'].each do |dir|
16
+ FileUtils.mkdir_p dir unless File.exists?(dir)
17
+ end
18
+
19
+ use Rack::ShowExceptions
data/lib/tasks/opentox.rb CHANGED
@@ -13,7 +13,7 @@ namespace :opentox do
13
13
  when /thin|mongrel|webrick/
14
14
  port = uri.sub(/^.*:/,'').sub(/\/$/,'')
15
15
  Dir.chdir dir
16
- pid_file = File.join(@@tmp_dir,"#{service}.pid")
16
+ pid_file = File.join(TMP_DIR,"#{service}.pid")
17
17
  begin
18
18
  `#{server} --trace --rackup config.ru start -p #{port} -e #{ENV['RACK_ENV']} -P #{pid_file} -d &`
19
19
  puts "#{service} started on localhost:#{port} in #{ENV['RACK_ENV']} environment with PID file #{pid_file}."
@@ -36,7 +36,7 @@ namespace :opentox do
36
36
  if server =~ /thin|mongrel|webrick/
37
37
  @@config[:services].each do |service,uri|
38
38
  port = uri.sub(/^.*:/,'').sub(/\/$/,'')
39
- pid_file = File.join(@@tmp_dir,"#{service}.pid")
39
+ pid_file = File.join(TMP_DIR,"#{service}.pid")
40
40
  begin
41
41
  puts `#{server} stop -P #{pid_file}`
42
42
  puts "#{service} stopped on localhost:#{port}"
@@ -71,7 +71,7 @@ task :start do
71
71
  case server
72
72
  when /thin|mongrel|webrick/
73
73
  port = @@config[:services][service].sub(/^.*:/,'').sub(/\/$/,'')
74
- pid_file = File.join(@@tmp_dir,"#{service}.pid")
74
+ pid_file = File.join(TMP_DIR,"#{service}.pid")
75
75
  begin
76
76
  `#{server} --trace --rackup config.ru start -p #{port} -e #{ENV['RACK_ENV']} -P #{pid_file} -d &`
77
77
  puts "#{service} started on localhost:#{port} in #{ENV['RACK_ENV']} environment with PID file #{pid_file}."
@@ -93,7 +93,7 @@ task :stop do
93
93
  server = @@config[:webserver]
94
94
  if server =~ /thin|mongrel|webrick/
95
95
  port = @@config[:services][service].sub(/^.*:/,'').sub(/\/$/,'')
96
- pid_file = File.join(@@tmp_dir,"#{service}.pid")
96
+ pid_file = File.join(TMP_DIR,"#{service}.pid")
97
97
  begin
98
98
  puts `thin stop -P #{pid_file}`
99
99
  puts "#{service} stopped on localhost:#{port}"
@@ -1,10 +1,20 @@
1
- :base_dir: /home/ch/webservices
2
- :webserver: thin
3
- :services:
4
- # make sure to enter a full uri (including training slash)
5
- opentox-compound: "http://localhost:4000/"
6
- opentox-feature: "http://localhost:4001/"
7
- opentox-dataset: "http://localhost:4002/"
8
- opentox-algorithm: "http://localhost:4003/"
9
- opentox-model: "http://localhost:4004/"
10
- #opentox-task: "http://localhost:4005/"
1
+ # Example configuration for OpenTox, please adjust to your settings
2
+ #
3
+ # Example 1: Using external test services
4
+ #
5
+ # :services:
6
+ # opentox-compound: "http://webservices.in-silico.ch/test/compound/"
7
+ # opentox-dataset: "http://webservices.in-silico.ch/test/dataset/"
8
+ # opentox-algorithm: "http://webservices.in-silico.ch/test/algorithm/"
9
+ # opentox-model: "http://webservices.in-silico.ch/test/model/"
10
+ # opentox-task: "http://webservices.in-silico.ch/test/task/"
11
+ #
12
+ # Example 2: Using local services
13
+ # :base_dir: /home/ch/webservices
14
+ # :webserver: thin
15
+ # :services:
16
+ # opentox-compound: "http://localhost:4000/"
17
+ # opentox-dataset: "http://localhost:4001/"
18
+ # opentox-algorithm: "http://localhost:4002/"
19
+ # opentox-model: "http://localhost:4003/"
20
+ # opentox-task: "http://localhost:4004/"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opentox-ruby-api-wrapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.5
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christoph Helma
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-11 00:00:00 +01:00
12
+ date: 2010-01-31 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,6 +52,16 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: "0"
54
54
  version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack-flash
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
55
65
  - !ruby/object:Gem::Dependency
56
66
  name: thin
57
67
  type: :runtime
@@ -102,6 +112,16 @@ dependencies:
102
112
  - !ruby/object:Gem::Version
103
113
  version: "0"
104
114
  version:
115
+ - !ruby/object:Gem::Dependency
116
+ name: sinatra-static-assets
117
+ type: :runtime
118
+ version_requirement:
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: "0"
124
+ version:
105
125
  - !ruby/object:Gem::Dependency
106
126
  name: cucumber
107
127
  type: :development
@@ -140,9 +160,8 @@ files:
140
160
  - lib/owl.rb
141
161
  - lib/spork.rb
142
162
  - lib/task.rb
163
+ - lib/tasks/config.rb
143
164
  - lib/tasks/opentox.rb
144
- - lib/tasks/redis.rb
145
- - lib/templates/config.ru
146
165
  - lib/templates/config.yaml
147
166
  - lib/utils.rb
148
167
  has_rdoc: true
data/lib/tasks/redis.rb DELETED
@@ -1,125 +0,0 @@
1
- # Inspired by rabbitmq.rake the Redbox project at http://github.com/rick/redbox/tree/master
2
- require 'fileutils'
3
- require 'open-uri'
4
-
5
- class RedisRunner
6
-
7
- def self.redisdir
8
- "/tmp/redis/"
9
- end
10
-
11
- def self.redisconfdir
12
- '/etc/redis.conf'
13
- end
14
-
15
- def self.dtach_socket
16
- '/tmp/redis.dtach'
17
- end
18
-
19
- # Just check for existance of dtach socket
20
- def self.running?
21
- File.exists? dtach_socket
22
- end
23
-
24
- def self.start
25
- puts 'Detach with Ctrl+\ Re-attach with rake redis:attach'
26
- sleep 3
27
- exec "dtach -A #{dtach_socket} redis-server #{redisconfdir}"
28
- end
29
-
30
- def self.attach
31
- exec "dtach -a #{dtach_socket}"
32
- end
33
-
34
- def self.stop
35
- sh 'echo "SHUTDOWN" | nc localhost 6379'
36
- end
37
-
38
- end
39
-
40
- namespace :redis do
41
-
42
- desc 'About redis'
43
- task :about do
44
- puts "\nSee http://code.google.com/p/redis/ for information about redis.\n\n"
45
- end
46
-
47
- desc 'Start redis'
48
- task :start do
49
- RedisRunner.start
50
- end
51
-
52
- desc 'Stop redis'
53
- task :stop do
54
- RedisRunner.stop
55
- end
56
-
57
- desc 'Restart redis'
58
- task :restart do
59
- RedisRunner.stop
60
- RedisRunner.start
61
- end
62
-
63
- desc 'Attach to redis dtach socket'
64
- task :attach do
65
- RedisRunner.attach
66
- end
67
-
68
- desc 'Install the lastest verison of Redis from Github (requires git, duh)'
69
- task :install => [:about, :download, :make] do
70
- %w(redis-benchmark redis-cli redis-server).each do |bin|
71
- sh "sudo cp /tmp/redis/#{bin} /usr/bin/"
72
- end
73
-
74
- puts "Installed redis-benchmark, redis-cli and redis-server to /usr/bin/"
75
-
76
- unless File.exists?('/etc/redis.conf')
77
- sh 'sudo cp /tmp/redis/redis.conf /etc/'
78
- puts "Installed redis.conf to /etc/ \n You should look at this file!"
79
- end
80
- end
81
-
82
- task :make do
83
- sh "cd #{RedisRunner.redisdir} && make clean"
84
- sh "cd #{RedisRunner.redisdir} && make"
85
- end
86
-
87
- desc "Download package"
88
- task :download do
89
- sh 'rm -rf /tmp/redis/' if File.exists?("#{RedisRunner.redisdir}/.svn")
90
- sh 'git clone git://github.com/antirez/redis.git /tmp/redis' unless File.exists?(RedisRunner.redisdir)
91
- sh "cd #{RedisRunner.redisdir} && git pull" if File.exists?("#{RedisRunner.redisdir}/.git")
92
- end
93
-
94
- end
95
-
96
- namespace :dtach do
97
-
98
- desc 'About dtach'
99
- task :about do
100
- puts "\nSee http://dtach.sourceforge.net/ for information about dtach.\n\n"
101
- end
102
-
103
- desc 'Install dtach 0.8 from source'
104
- task :install => [:about] do
105
-
106
- Dir.chdir('/tmp/')
107
- unless File.exists?('/tmp/dtach-0.8.tar.gz')
108
- require 'net/http'
109
-
110
- url = 'http://downloads.sourceforge.net/project/dtach/dtach/0.8/dtach-0.8.tar.gz'
111
- open('/tmp/dtach-0.8.tar.gz', 'wb') do |file| file.write(open(url).read) end
112
- end
113
-
114
- unless File.directory?('/tmp/dtach-0.8')
115
- system('tar xzf dtach-0.8.tar.gz')
116
- end
117
-
118
- Dir.chdir('/tmp/dtach-0.8/')
119
- sh 'cd /tmp/dtach-0.8/ && ./configure && make'
120
- sh 'sudo cp /tmp/dtach-0.8/dtach /usr/bin/'
121
-
122
- puts 'Dtach successfully installed to /usr/bin.'
123
- end
124
- end
125
-
@@ -1,23 +0,0 @@
1
- require 'rubygems'
2
- require 'sinatra'
3
- require 'application.rb'
4
- require 'rack'
5
- require 'rack/contrib'
6
-
7
- FileUtils.mkdir_p 'log' unless File.exists?('log')
8
- log = File.new("log/#{ENV["RACK_ENV"]}.log", "a")
9
- $stdout.reopen(log)
10
- $stderr.reopen(log)
11
-
12
- if ENV['RACK_ENV'] == 'production'
13
- use Rack::MailExceptions do |mail|
14
- mail.to 'helma@in-silico.ch'
15
- mail.subject '[ERROR] %s'
16
- end
17
- elsif ENV['RACK_ENV'] == 'development'
18
- use Rack::Reloader
19
- use Rack::ShowExceptions
20
- end
21
-
22
- run Sinatra::Application
23
-