opentox-ruby 0.0.2 → 1.0.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.
data/lib/helper.rb CHANGED
@@ -1,26 +1,99 @@
1
1
  helpers do
2
2
 
3
- # Authentification
4
- def protected!
5
- response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth") and \
6
- throw(:halt, [401, "Not authorized\n"]) and \
7
- return unless authorized?
3
+ # Authentification
4
+ def protected!(subjectid)
5
+ if env["session"]
6
+ unless authorized?(subjectid)
7
+ flash[:notice] = "You don't have access to this section: "
8
+ redirect back
9
+ end
10
+ elsif !env["session"] && subjectid
11
+ unless authorized?(subjectid)
12
+ LOGGER.debug "URI not authorized: clean: " + clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}").to_s + " full: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']} with request: #{request.env['REQUEST_METHOD']}"
13
+ raise OpenTox::NotAuthorizedError.new "Not authorized"
14
+ end
15
+ else
16
+ raise OpenTox::NotAuthorizedError.new "Not authorized" unless authorized?(subjectid)
17
+ end
8
18
  end
9
19
 
10
- def authorized?
11
- @auth ||= Rack::Auth::Basic::Request.new(request.env)
12
- @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['api', API_KEY]
20
+ #Check Authorization for URI with method and subjectid.
21
+ def authorized?(subjectid)
22
+ request_method = request.env['REQUEST_METHOD']
23
+ uri = clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}")
24
+ request_method = "GET" if request_method == "POST" && uri =~ /\/model\/\d+\/?$/
25
+ return OpenTox::Authorization.authorized?(uri, request_method, subjectid)
13
26
  end
14
27
 
15
-
16
- =begin
17
- def xml(object)
18
- builder do |xml|
19
- xml.instruct!
20
- object.to_xml
21
- end
22
- end
23
- =end
28
+ #cleans URI from querystring and file-extension. Sets port 80 to emptystring
29
+ # @param [String] uri
30
+ def clean_uri(uri)
31
+ uri = uri.sub(" ", "%20") #dirty hacks => to fix
32
+ uri = uri[0,uri.index("InChI=")] if uri.index("InChI=")
33
+
34
+ out = URI.parse(uri)
35
+ out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after /id/ for a&a
36
+ port = (out.scheme=="http" && out.port==80)||(out.scheme=="https" && out.port==443) ? "" : ":#{out.port.to_s}"
37
+ "#{out.scheme}://#{out.host}#{port}#{out.path.chomp("/")}" #"
38
+ end
39
+
40
+ #unprotected uri for login
41
+ def login_requests
42
+ return env['REQUEST_URI'] =~ /\/login$/
43
+ end
44
+
45
+ def uri_available?(urlStr)
46
+ url = URI.parse(urlStr)
47
+ unless @subjectid
48
+ Net::HTTP.start(url.host, url.port) do |http|
49
+ return http.head(url.request_uri).code == "200"
50
+ end
51
+ else
52
+ Net::HTTP.start(url.host, url.port) do |http|
53
+ return http.post(url.request_uri, "subjectid=#{@subjectid}").code == "202"
54
+ end
55
+ end
56
+ end
24
57
 
25
58
  end
26
59
 
60
+ before do
61
+ unless !AA_SERVER or login_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
62
+ begin
63
+ subjectid = nil
64
+ subjectid = session[:subjectid] if session[:subjectid]
65
+ subjectid = params[:subjectid] if params[:subjectid] and !subjectid
66
+ subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !subjectid
67
+ subjectid = request.cookies["subjectid"] unless subjectid
68
+ # see http://rack.rubyforge.org/doc/SPEC.html
69
+ subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
70
+ @subjectid = subjectid
71
+ rescue
72
+ #LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
73
+ subjectid = ""
74
+ end
75
+ @subjectid = subjectid
76
+ protected!(subjectid)
77
+
78
+ extension = File.extname(request.path_info) # params[:id] is not yet available
79
+ unless extension.empty?
80
+ #request.path_info.sub!(/\.#{extension}$/,'')
81
+ case extension
82
+ when "html"
83
+ @accept = 'text/html'
84
+ when "yaml"
85
+ @accept = 'application/x-yaml'
86
+ when "csv"
87
+ @accept = 'text/csv'
88
+ when "rdfxml"
89
+ @accept = 'application/rdf+xml'
90
+ when "xls"
91
+ @accept = 'application/ms-excel'
92
+ else
93
+ halt 404, "File format #{extension} not supported."
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+
data/lib/model.rb CHANGED
@@ -6,33 +6,71 @@ module OpenTox
6
6
 
7
7
  # Run a model with parameters
8
8
  # @param [Hash] params Parameters for OpenTox model
9
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
9
10
  # @return [text/uri-list] Task or resource URI
10
- def run(params)
11
- if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
12
- accept = 'application/x-yaml'
13
- else
14
- accept = 'application/rdf+xml'
15
- end
16
- begin
17
- RestClientWrapper.post(@uri,{:accept => accept},params).to_s
18
- rescue => e
19
- LOGGER.error "Failed to run #{@uri} with #{params.inspect} (#{e.inspect})"
20
- raise "Failed to run #{@uri} with #{params.inspect}"
11
+ def run( params, accept_header=nil, waiting_task=nil )
12
+ unless accept_header
13
+ if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
14
+ accept_header = 'application/x-yaml'
15
+ else
16
+ accept_header = 'application/rdf+xml'
17
+ end
21
18
  end
19
+ LOGGER.info "running model "+@uri.to_s+", params: "+params.inspect+", accept: "+accept_header.to_s
20
+ RestClientWrapper.post(@uri,params,{:accept => accept_header},waiting_task).to_s
22
21
  end
23
22
 
24
23
  # Generic OpenTox model class for all API compliant services
25
24
  class Generic
26
25
  include Model
26
+
27
+ # Find Generic Opentox Model via URI, and loads metadata, could raise NotFound/NotAuthorized error
28
+ # @param [String] uri Model URI
29
+ # @return [OpenTox::Model::Generic] Model instance
30
+ def self.find(uri,subjectid=nil)
31
+ return nil unless uri
32
+ model = Generic.new(uri)
33
+ model.load_metadata(subjectid)
34
+ raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
35
+ model
36
+ end
37
+
38
+ # provides feature type, possible types are "regression" or "classification"
39
+ # @return [String] feature type, "unknown" if type could not be estimated
40
+ def feature_type(subjectid=nil)
41
+ return @feature_type if @feature_type
42
+
43
+ # dynamically perform restcalls if necessary
44
+ load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
45
+ algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid)
46
+ algorithm_title = algorithm ? algorithm.metadata[DC.title] : nil
47
+ algorithm_type = algorithm ? algorithm.metadata[OT.isA] : nil
48
+ dependent_variable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid )
49
+ dependent_variable_type = dependent_variable ? dependent_variable.feature_type : nil
50
+ type_indicators = [dependent_variable_type, @metadata[OT.isA], @metadata[DC.title],
51
+ @uri, algorithm_type, algorithm_title]
52
+ type_indicators.each do |type|
53
+ case type
54
+ when /(?i)classification/
55
+ @feature_type = "classification"
56
+ break
57
+ when /(?i)regression/
58
+ @feature_type = "regression"
59
+ end
60
+ end
61
+ raise "unknown model "+type_indicators.inspect unless @feature_type
62
+ @feature_type
63
+ end
64
+
27
65
  end
28
-
66
+
29
67
  # Lazy Structure Activity Relationship class
30
68
  class Lazar
31
69
 
32
70
  include Model
33
71
  include Algorithm
34
72
 
35
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim
73
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid
36
74
 
37
75
  def initialize(uri=nil)
38
76
 
@@ -60,15 +98,15 @@ module OpenTox
60
98
 
61
99
  # Get URIs of all lazar models
62
100
  # @return [Array] List of lazar model URIs
63
- def self.all
64
- RestClientWrapper.get(CONFIG[:services]["opentox-model"]).to_s.split("\n")
101
+ def self.all(subjectid=nil)
102
+ RestClientWrapper.get(CONFIG[:services]["opentox-model"], :subjectid => subjectid).to_s.split("\n")
65
103
  end
66
104
 
67
105
  # Find a lazar model
68
106
  # @param [String] uri Model URI
69
107
  # @return [OpenTox::Model::Lazar] lazar model
70
- def self.find(uri)
71
- YAML.load RestClientWrapper.get(uri,:accept => 'application/x-yaml')
108
+ def self.find(uri, subjectid=nil)
109
+ YAML.load RestClientWrapper.get(uri,{:accept => 'application/x-yaml', :subjectid => subjectid})
72
110
  end
73
111
 
74
112
  # Create a new lazar model
@@ -77,7 +115,7 @@ module OpenTox
77
115
  def self.create(params)
78
116
  lazar_algorithm = OpenTox::Algorithm::Generic.new File.join( CONFIG[:services]["opentox-algorithm"],"lazar")
79
117
  model_uri = lazar_algorithm.run(params)
80
- OpenTox::Model::Lazar.find(model_uri)
118
+ OpenTox::Model::Lazar.find(model_uri, params[:subjectid])
81
119
  end
82
120
 
83
121
  # Get a parameter value
@@ -89,21 +127,30 @@ module OpenTox
89
127
 
90
128
  # Predict a dataset
91
129
  # @param [String] dataset_uri Dataset URI
130
+ # @param [optional,subjectid]
131
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
92
132
  # @return [OpenTox::Dataset] Dataset with predictions
93
- def predict_dataset(dataset_uri)
94
- @prediction_dataset = Dataset.create
133
+ def predict_dataset(dataset_uri, subjectid=nil, waiting_task=nil)
134
+ @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
95
135
  @prediction_dataset.add_metadata({
96
136
  OT.hasSource => @uri,
97
137
  DC.creator => @uri,
98
138
  DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
99
139
  OT.parameters => [{DC.title => "dataset_uri", OT.paramValue => dataset_uri}]
100
140
  })
101
- d = Dataset.new(dataset_uri)
102
- d.load_compounds
141
+ d = Dataset.new(dataset_uri,subjectid)
142
+ d.load_compounds(subjectid)
143
+ count = 0
103
144
  d.compounds.each do |compound_uri|
104
- predict(compound_uri,false)
145
+ begin
146
+ predict(compound_uri,false,subjectid)
147
+ count += 1
148
+ waiting_task.progress( count/d.compounds.size.to_f*100.0 ) if waiting_task
149
+ rescue => ex
150
+ LOGGER.warn "prediction for compound "+compound_uri.to_s+" failed: "+ex.message
151
+ end
105
152
  end
106
- @prediction_dataset.save
153
+ @prediction_dataset.save(subjectid)
107
154
  @prediction_dataset
108
155
  end
109
156
 
@@ -111,7 +158,7 @@ module OpenTox
111
158
  # @param [String] compound_uri Compound URI
112
159
  # @param [optinal,Boolean] verbose Verbose prediction (output includes neighbors and features)
113
160
  # @return [OpenTox::Dataset] Dataset with prediction
114
- def predict(compound_uri,verbose=false)
161
+ def predict(compound_uri,verbose=false,subjectid=nil)
115
162
 
116
163
  @compound = Compound.new compound_uri
117
164
  features = {}
@@ -119,7 +166,7 @@ module OpenTox
119
166
  unless @prediction_dataset
120
167
  #@prediction_dataset = cached_prediction
121
168
  #return @prediction_dataset if cached_prediction
122
- @prediction_dataset = Dataset.create
169
+ @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
123
170
  @prediction_dataset.add_metadata( {
124
171
  OT.hasSource => @uri,
125
172
  DC.creator => @uri,
@@ -129,7 +176,7 @@ module OpenTox
129
176
  } )
130
177
  end
131
178
 
132
- return @prediction_dataset if database_activity
179
+ return @prediction_dataset if database_activity(subjectid)
133
180
 
134
181
  neighbors
135
182
  prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
@@ -217,7 +264,7 @@ module OpenTox
217
264
  end
218
265
  end
219
266
 
220
- @prediction_dataset.save
267
+ @prediction_dataset.save(subjectid)
221
268
  @prediction_dataset
222
269
  end
223
270
 
@@ -245,11 +292,11 @@ module OpenTox
245
292
 
246
293
  # Find database activities and store them in @prediction_dataset
247
294
  # @return [Boolean] true if compound has databasse activities, false if not
248
- def database_activity
295
+ def database_activity(subjectid)
249
296
  if @activities[@compound.uri]
250
297
  @activities[@compound.uri].each { |act| @prediction_dataset.add @compound.uri, @metadata[OT.dependentVariables], act }
251
298
  @prediction_dataset.add_metadata(OT.hasSource => @metadata[OT.trainingDataset])
252
- @prediction_dataset.save
299
+ @prediction_dataset.save(subjectid)
253
300
  true
254
301
  else
255
302
  false
@@ -257,13 +304,13 @@ module OpenTox
257
304
  end
258
305
 
259
306
  # Save model at model service
260
- def save
261
- self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
307
+ def save(subjectid)
308
+ self.uri = RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
262
309
  end
263
310
 
264
311
  # Delete model at model service
265
- def delete
266
- RestClientWrapper.delete @uri unless @uri == CONFIG[:services]["opentox-model"]
312
+ def delete(subjectid)
313
+ RestClientWrapper.delete(@uri, :subjectid => subjectid) unless @uri == CONFIG[:services]["opentox-model"]
267
314
  end
268
315
 
269
316
  end
@@ -0,0 +1,43 @@
1
+ module OpenTox
2
+ module OntologyService
3
+ module Endpoints
4
+ require 'sparql/client'
5
+ @sparql = SPARQL::Client.new("http://apps.ideaconsult.net:8080/ontology")
6
+ def self.qs(classname="Endpoints")
7
+ return "PREFIX ot:<http://www.opentox.org/api/1.1#>
8
+ PREFIX ota:<http://www.opentox.org/algorithms.owl#>
9
+ PREFIX owl:<http://www.w3.org/2002/07/owl#>
10
+ PREFIX dc:<http://purl.org/dc/elements/1.1/>
11
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
12
+ PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
13
+ PREFIX otee:<http://www.opentox.org/echaEndpoints.owl#>
14
+ PREFIX toxcast:<http://www.opentox.org/toxcast.owl#>
15
+ select ?Endpoints ?title ?id
16
+ where {?Endpoints rdfs:subClassOf otee:#{classname}.
17
+ OPTIONAL {?Endpoints dc:title ?title}.
18
+ OPTIONAL {?Endpoints dc:identifier ?id}.}
19
+ ORDER BY ?title"
20
+ end
21
+
22
+ def self.make_option_list(endpoint="Endpoints", level=1)
23
+ out = ""
24
+ results = @sparql.query(qs(endpoint)) rescue results = []
25
+ results.each do |result|
26
+ endpointname = result.Endpoints.to_s.split('#').last
27
+ title = result.bound?(:title) ? result.title : endpointname
28
+ out += "<option value='#{title}' id='#{endpointname}' class='level_#{level}'>#{title}</option>\n"
29
+ out += make_option_list(endpointname, level + 1)
30
+ end
31
+ return out
32
+ end
33
+
34
+ def self.get_endpoint_selectlist(include_blank=true)
35
+ out = "<select id='endpoint' name='endpoint'>\n"
36
+ out += "<option value='' id='please_select'>Please select</option>\n" if include_blank
37
+ out += make_option_list
38
+ out += "</select>\n"
39
+ return out
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/opentox-ruby.rb CHANGED
@@ -1,4 +1,4 @@
1
- ['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'overwrite', 'environment'].each do |lib|
1
+ ['rubygems', 'sinatra', 'sinatra/url_for', 'ohm', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
2
2
  require lib
3
3
  end
4
4
 
@@ -8,6 +8,7 @@ rescue LoadError
8
8
  puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
9
9
  end
10
10
 
11
- ['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper'].each do |lib|
11
+ ['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature',
12
+ 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html' ].each do |lib|
12
13
  require lib
13
14
  end
data/lib/opentox.rb CHANGED
@@ -19,14 +19,14 @@ module OpenTox
19
19
 
20
20
  # Get all objects from a service
21
21
  # @return [Array] List of available URIs
22
- def self.all(uri)
23
- RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.split(/\n/)
22
+ def self.all(uri, subjectid=nil)
23
+ RestClientWrapper.get(uri,:accept => "text/uri-list", :subjectid => subjectid).to_s.split(/\n/)
24
24
  end
25
25
 
26
26
  # Load (and return) metadata from object URI
27
27
  # @return [Hash] Metadata
28
- def load_metadata
29
- @metadata = Parser::Owl::Generic.new(@uri).load_metadata
28
+ def load_metadata(subjectid=nil)
29
+ @metadata = Parser::Owl::Generic.new(@uri).load_metadata(subjectid)
30
30
  @metadata
31
31
  end
32
32
 
@@ -43,5 +43,10 @@ module OpenTox
43
43
  s.to_rdfxml
44
44
  end
45
45
 
46
+ # deletes the resource, deletion should have worked when no RestCallError raised
47
+ def delete(subjectid=nil)
48
+ RestClientWrapper.delete(uri,:subjectid => subjectid)
49
+ end
50
+
46
51
  end
47
52
 
data/lib/overwrite.rb CHANGED
@@ -1,38 +1,91 @@
1
1
  # class overwrites aka monkey patches
2
- # hack: store sinatra in global var to make url_for and halt methods accessible
3
- before{ $sinatra = self unless $sinatra }
2
+ # hack: store sinatra instance in global var $url_provider to make url_for and halt methods accessible
3
+ before {
4
+ raise "should not happen, url provider already differently initialized "+
5
+ $url_provider.request.host.to_s+" != "+self.request.host.to_s if
6
+ $url_provider and $url_provider.request.host!=self.request.host and
7
+ $url_provider.request.script_name!=self.request.script_name
8
+ $url_provider = self
9
+ # stupid internet explorer does not ask for text/html, add this manually
10
+ request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/
11
+ }
12
+
13
+ # Error handling
14
+ # Errors are logged as error and formated according to acccept-header
15
+ # Non OpenTox::Errors (defined in error.rb) are handled as internal error (500), stacktrace is logged
16
+ # IMPT: set sinatra settings :show_exceptions + :raise_errors to false in config.ru, otherwise Rack::Showexceptions takes over
17
+ error Exception do
18
+ error = request.env['sinatra.error']
19
+ # log error message and backtrace to logfile
20
+ LOGGER.error error.class.to_s+": "+error.message
21
+ LOGGER.error ":\n"+error.backtrace.join("\n")
22
+
23
+ actor = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
24
+ rep = OpenTox::ErrorReport.create(error, actor)
25
+
26
+ case request.env['HTTP_ACCEPT']
27
+ when /rdf/
28
+ content_type 'application/rdf+xml'
29
+ halt error.http_code,rep.to_rdfxml
30
+ when /html/
31
+ content_type 'text/html'
32
+ halt error.http_code,(OpenTox.text_to_html rep.to_yaml, @subjectid)
33
+ else
34
+ content_type 'application/x-yaml'
35
+ halt error.http_code,rep.to_yaml
36
+ end
37
+ end
4
38
 
5
39
  class Sinatra::Base
6
- # overwriting halt to log halts (!= 202)
7
- def halt(*response)
8
- LOGGER.error "halt "+response.first.to_s+" "+(response.size>1 ? response[1].to_s : "") if response and response.first and response.first >= 300
9
- # orig sinatra code:
10
- response = response.first if response.length == 1
11
- throw :halt, response
40
+
41
+ def return_task( task )
42
+ code = task.running? ? 202 : 200
43
+ case request.env['HTTP_ACCEPT']
44
+ when /rdf/
45
+ response['Content-Type'] = "application/rdf+xml"
46
+ halt code,task.to_rdfxml
47
+ when /yaml/
48
+ response['Content-Type'] = "application/x-yaml"
49
+ halt code,task.to_yaml # PENDING differs from task-webservice
50
+ when /html/
51
+ response['Content-Type'] = "text/html"
52
+ halt code,OpenTox.text_to_html(task.to_yaml, @subjectid)
53
+ else # default /uri-list/
54
+ response['Content-Type'] = "text/uri-list"
55
+ halt code,task.uri+"\n"
56
+ end
12
57
  end
13
58
  end
14
59
 
15
60
  class String
16
- def task_uri?
17
- self.uri? && !self.match(/task/).nil?
18
- end
19
-
20
- def dataset_uri?
21
- self.uri? && !self.match(/dataset/).nil?
22
- end
23
-
24
- def self.model_uri?
25
- self.uri? && !self.match(/model/).nil?
26
- end
61
+ def task_uri?
62
+ self.uri? && !self.match(/task/).nil?
63
+ end
64
+
65
+ def dataset_uri?
66
+ self.uri? && !self.match(/dataset/).nil?
67
+ end
68
+
69
+ def self.model_uri?
70
+ self.uri? && !self.match(/model/).nil?
71
+ end
27
72
 
28
- def uri?
29
- begin
30
- u = URI::parse(self)
31
- return (u.scheme!=nil and u.host!=nil)
32
- rescue URI::InvalidURIError
33
- return false
34
- end
73
+ def uri?
74
+ begin
75
+ u = URI::parse(self)
76
+ return (u.scheme!=nil and u.host!=nil)
77
+ rescue URI::InvalidURIError
78
+ return false
35
79
  end
80
+ end
81
+
82
+ def underscore
83
+ self.gsub(/::/, '/').
84
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
85
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
86
+ tr("-", "_").
87
+ downcase
88
+ end
36
89
  end
37
90
 
38
91
  require 'logger'
@@ -52,7 +105,7 @@ class OTLogger < Logger
52
105
  n = 2
53
106
  line = lines[n]
54
107
 
55
- while (line =~ /spork.rb/ or line =~ /create/ or line =~ /ot-logger.rb/)
108
+ while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
56
109
  n += 1
57
110
  line = lines[n]
58
111
  end
@@ -63,7 +116,7 @@ class OTLogger < Logger
63
116
  end
64
117
 
65
118
  def format(msg)
66
- pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace+" :: "+($sinatra ? $sinatra.request.env['REMOTE_ADDR'] : nil).to_s
119
+ pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace
67
120
  end
68
121
 
69
122
  def debug(msg)
@@ -84,3 +137,9 @@ class OTLogger < Logger
84
137
 
85
138
  end
86
139
 
140
+ # make migration from datamapper more straightforward
141
+ class Ohm::Model
142
+ def self.get(id)
143
+ self[id]
144
+ end
145
+ end