opentox-ruby-api-wrapper 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
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
-