sadi-rb 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab2044de34253723c4b946f38ffd1aa6c05ecc4f
4
- data.tar.gz: 0f6b13b3ee863ab5cf5fe751c4511f7ceacc44f0
3
+ metadata.gz: 710664e9e7b3fd1fa404d9789934fbaab1ca6761
4
+ data.tar.gz: fa4892f551d5f15234837a89edf87798e48656cb
5
5
  SHA512:
6
- metadata.gz: 4282d1f8e806189166e83517603e57a4718d4a55e7d528c359f1e3b4778c10fdb107fc765a070e3faf336bd89e7790aa8eb5e0502844af1212e8a40a5f2b7d36
7
- data.tar.gz: ba25e5a446f0229053c126cefbe0cc3b4caba059214f81efc0841d6d941b00566de933c164e4d6212e7390586ef4e29e70d4ca7d5af9367a715a738e0cae68d4
6
+ metadata.gz: 1e0dfb9db33fcb89220ba2d7dc7a5633510f6517728345342186f70fa933b6bc9a42c3ca030aa10043c38e0f6aff926a92c455e9bdf37fe92aa71b4223f37d7c
7
+ data.tar.gz: da6d8beb97e317df3e6677b7464abcd957f81f951fbf3acc765ce5d6547668f8b82db45c56b298f61ec2b2527ba338ec69a532edc7dfdbcfb81dcfb9cd2c68fe
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # sadi-rb
2
2
 
3
+ [![Build Status](https://travis-ci.org/wstrinz/sadi-rb.png?branch=master)](https://travis-ci.org/wstrinz/sadi-rb)
4
+
3
5
  ### Installation
4
6
  `gem install sadi-rb`
5
7
 
@@ -7,13 +9,13 @@ or clone the repository and run `rake install` for the latest version
7
9
 
8
10
  ### Description
9
11
 
10
- Write [SADI] Services in Ruby, then host them as a Sinatra server
12
+ Write [SADI] Services in Ruby, using [ruby-rdf], then host them in a [Sinatra] application.
11
13
 
12
- Currently only supports [synchronous] service have been implemented.
14
+ Currently only support for [synchronous] services are fully supported, although an experimental [asynchronous] class is available.
13
15
 
14
16
  ### Usage
15
17
 
16
- To test the server, use the gem's executable `sadi-rb`. This will start the server on [http://localhost:4567](http://localhost:4567), and load the [demo service].
18
+ To test the server, use the gem's executable `sadi-rb`. This will start the server on [http://localhost:4567](http://localhost:4567), and load the [demo service], which is based on the service at [http://sadiframework.org/examples/hello](http://sadiframework.org/examples/hello).
17
19
 
18
20
  The server can also be run as part of a script using
19
21
 
@@ -25,35 +27,45 @@ SADI::Server.run!
25
27
 
26
28
  ### Writing your own services
27
29
 
28
- To create an asynchronous service, simply extend the `SADI::SynchronousService` module and implement the interface methods it requires;
30
+ #### Synchronous
31
+
32
+ To create a [synchronous] service, simply extend the `SADI::SynchronousService` module and implement the interface methods it requires;
29
33
 
30
34
  ```ruby
31
35
  require 'sadi-rb'
32
36
 
33
- Class MyService
34
- def service_name
35
- "my_service_name"
36
- end
37
+ class MyService
38
+ extend SADI::SynchronousService
39
+
40
+ def self.service_name
41
+ "my_service_name" # => service will be accessible at "/services/my_service_name"
42
+ end
37
43
 
38
- def service_description
39
- # an RDF::Graph of your service's description
40
- end
44
+ def self.service_description
45
+ # an RDF::Graph of your service's description
46
+ end
41
47
 
42
- def service_owl
43
- # an RDF::Graph of your service's OWL classes
44
- end
48
+ def self.service_owl
49
+ # an RDF::Graph of your service's OWL classes
50
+ end
45
51
 
46
- def process_object(input_graph, owl_object)
47
- # Service logic goes here
52
+ def self.process_object(input_graph, owl_object)
53
+ # Service logic goes here
48
54
 
49
- # Should return an RDF::Graph of
50
- # the output for the resource specified by the URI owl_object,
51
- # from the RDF::Graph input_graph
52
- end
55
+ # Should return an RDF::Graph of
56
+ # the output for the resource specified by the URI owl_object,
57
+ # from the RDF::Graph input_graph
58
+ end
53
59
  end
54
60
  ```
55
61
 
56
- Although SADI can theoretically use any vocabulary for its service description, the gem internals currently require that you use the [mygrid ontology] in implementing your `service_description` method
62
+ Although SADI can theoretically use any vocabulary for its service description, the gem internals currently require that you use the [mygrid ontology] in implementing your `service_description` method.
63
+
64
+ You also have access to the `parse_string(string, format)` method, inherited from [SADI::Converter](https://github.com/wstrinz/sadi-rb/blob/master/lib/sadi-rb/converter.rb) through `SADI::SynchronousService`, which can be used create a RDF::Graph from a serialized string. The `format` argument should be a symbol for an `RDF::Format` class, for example `:ttl` or `:rdfxml`.
65
+
66
+ #### Asynchronous Services
67
+
68
+ SADI also supports [asynchronous] services, which can be polled repeatedly until their results are available. To make a service asynchronous, you can simply extend the `SADI::AsynchronousService` module, and implement your service the same way you would a synchronous service. However beware that the implementation of asynchronous services is currently not thread safe or very well tested, so it may not work well on unless you're using MRI and Thin.
57
69
 
58
70
  ## Contributing to sadi-rb
59
71
 
@@ -70,6 +82,10 @@ Although SADI can theoretically use any vocabulary for its service description,
70
82
  Copyright (c) 2013 Will Strinz. See LICENSE.txt for
71
83
  further details.
72
84
 
73
- [demo service]: http://sadiframework.org/content/how-sadi-works/synchronous-sadi-services/
85
+ [synchronous]: http://sadiframework.org/content/how-sadi-works/synchronous-sadi-services/
86
+ [asynchronous]: https://code.google.com/p/sadi/wiki/AsynchronousServices
87
+ [demo service]: https://github.com/wstrinz/sadi-rb/blob/master/lib/sadi-rb/example_service.rb
74
88
  [SADI]: http://sadiframework.org
75
- [mygrid ontology]: http://www.mygrid.org.uk/tools/service-management/mygrid-ontology/
89
+ [mygrid ontology]: http://www.mygrid.org.uk/tools/service-management/mygrid-ontology/
90
+ [ruby-rdf]: http://ruby-rdf.github.io/
91
+ [Sinatra]: http://www.sinatrarb.com/
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ Jeweler::Tasks.new do |gem|
22
22
  gem.email = "wstrinz@gmail.com"
23
23
  # gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  gem.authors = ["Will Strinz"]
25
- gem.version = '0.0.2'
25
+ gem.version = '0.0.3'
26
26
  # dependencies defined in Gemfile
27
27
  end
28
28
  Jeweler::RubygemsDotOrgTasks.new
@@ -1,8 +1,11 @@
1
1
  require_relative 'sadi-rb/server.rb'
2
2
  require_relative 'sadi-rb/converter.rb'
3
+ require_relative 'sadi-rb/base_service.rb'
3
4
  require_relative 'sadi-rb/synchronous_service.rb'
5
+ require_relative 'sadi-rb/asynchronous_service.rb'
4
6
  require_relative 'sadi-rb/services.rb'
5
7
 
6
8
  require_relative 'sadi-rb/example_service.rb'
9
+ require_relative 'sadi-rb/example_service_async.rb'
7
10
 
8
11
  SADI.reload_services
@@ -0,0 +1,66 @@
1
+ module SADI
2
+ module AsynchronousService
3
+ include SADI::Converter
4
+ include SADI::BaseService
5
+
6
+ def self.included(base)
7
+ @classes ||= []
8
+ @classes << base
9
+ end
10
+
11
+ def self.extended(base)
12
+ @classes ||= []
13
+ @classes << base
14
+ end
15
+
16
+ def self.classes
17
+ @classes
18
+ end
19
+
20
+ def jobs
21
+ # Yay not thread safety!
22
+
23
+ @jobs ||= {}
24
+ end
25
+
26
+ def generate_job_id
27
+ # TODO better poll URLs
28
+
29
+ # "#{service_name}_#{Time.now.nsec.to_s(32)}"
30
+ Time.now.nsec.to_s(32)
31
+ end
32
+
33
+ def process_input(input, format, poll_base)
34
+ job_id = generate_job_id
35
+
36
+ raise "Job already exists (#{job_id})" if jobs[job_id]
37
+
38
+ jobs[job_id] = nil
39
+
40
+ Thread.new do
41
+
42
+ gr = RDF::Graph.new
43
+ in_graph = parse_string(input,format)
44
+
45
+ input_objects(in_graph).each do |obj|
46
+ gr << process_object(in_graph, obj)
47
+ end
48
+
49
+ jobs[job_id] = gr
50
+ end
51
+
52
+ gr = RDF::Graph.new
53
+ out_class = output_classes.first
54
+ input_objects(parse_string(input,format)).each do |obj|
55
+ gr << RDF::Statement.new(obj, RDF.type, out_class)
56
+ gr << RDF::Statement.new(obj, RDF::RDFS.isDefinedBy, RDF::URI("#{poll_base}/#{job_id}"))
57
+ end
58
+
59
+ gr
60
+ end
61
+
62
+ def poll(job_id)
63
+ jobs[job_id]
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,71 @@
1
+ module SADI
2
+ module BaseService
3
+ include SADI::Converter
4
+
5
+ # def self.included(base)
6
+ # @classes ||= []
7
+ # @classes << base
8
+ # end
9
+
10
+ # def self.extended(base)
11
+ # @classes ||= []
12
+ # @classes << base
13
+ # end
14
+
15
+ # def self.classes
16
+ # @classes
17
+ # end
18
+
19
+ def process_input(input, format)
20
+ raise "Input processing should be implemented by service module"
21
+ end
22
+
23
+ def input_objects(graph)
24
+ input_classes.map do |cl|
25
+ solutions = RDF::Query.execute(graph) do
26
+ pattern [:obj, RDF.type, cl]
27
+ end
28
+
29
+ solutions.map(&:obj)
30
+ end.flatten
31
+ end
32
+
33
+ def input_classes
34
+ moby = RDF::Vocabulary.new('http://www.mygrid.org.uk/mygrid-moby-service#')
35
+
36
+ solutions = RDF::Query.execute(service_description) do
37
+ pattern [nil, moby.inputParameter, :param]
38
+ pattern [:param, moby.objectType, :in_class]
39
+ end
40
+
41
+ solutions.map(&:in_class)
42
+ end
43
+
44
+ def output_classes
45
+ moby = RDF::Vocabulary.new('http://www.mygrid.org.uk/mygrid-moby-service#')
46
+
47
+ solutions = RDF::Query.execute(service_description) do
48
+ pattern [nil, moby.outputParameter, :param]
49
+ pattern [:param, moby.objectType, :out_class]
50
+ end
51
+
52
+ solutions.map(&:out_class)
53
+ end
54
+
55
+ def service_description(service)
56
+ raise "Must implement a #service_description method returning an RDF::Graph or Repository"
57
+ end
58
+
59
+ def service_owl(service)
60
+ raise "Must implement a #service_owl method returning an RDF::Graph or Repository"
61
+ end
62
+
63
+ def process_object(owl_graph, object)
64
+ raise "Must implement a #process_input that takes an RDF::Graph or Repository as input and returns a new one"
65
+ end
66
+
67
+ def service_name
68
+ raise "Must define a service name"
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,91 @@
1
+ class ExampleServiceAsync
2
+ extend SADI::AsynchronousService
3
+ class << self
4
+ def service_name
5
+ "hello_async"
6
+ end
7
+
8
+ def service_description
9
+ str = <<-EOS
10
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
11
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
12
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
13
+
14
+ <http://sadiframework.org/examples/hello> a <http://www.mygrid.org.uk/mygrid-moby-service#serviceDescription>;
15
+ rdfs:label "Hello, world"^^xsd:string;
16
+ <http://www.mygrid.org.uk/mygrid-moby-service#hasOperation> [ a <http://www.mygrid.org.uk/mygrid-moby-service#operation>;
17
+ <http://www.mygrid.org.uk/mygrid-moby-service#hasUnitTest> [ a <http://www.mygrid.org.uk/mygrid-moby-service#unitTest>;
18
+ <http://www.mygrid.org.uk/mygrid-moby-service#exampleInput> <http://sadiframework.org/examples/t/hello.input.1.rdf>;
19
+ <http://www.mygrid.org.uk/mygrid-moby-service#exampleOutput> <http://sadiframework.org/examples/t/hello.output.1.rdf>];
20
+ <http://www.mygrid.org.uk/mygrid-moby-service#inputParameter> [ a <http://www.mygrid.org.uk/mygrid-moby-service#parameter>;
21
+ <http://www.mygrid.org.uk/mygrid-moby-service#objectType> <http://sadiframework.org/examples/hello.owl#NamedIndividual>];
22
+ <http://www.mygrid.org.uk/mygrid-moby-service#outputParameter> [ a <http://www.mygrid.org.uk/mygrid-moby-service#parameter>;
23
+ <http://www.mygrid.org.uk/mygrid-moby-service#objectType> <http://sadiframework.org/examples/hello.owl#GreetedIndividual>]];
24
+ <http://www.mygrid.org.uk/mygrid-moby-service#hasServiceDescriptionText> "A simple \"Hello, World\" service that reads a name and attaches a greeting."^^xsd:string;
25
+ <http://www.mygrid.org.uk/mygrid-moby-service#hasServiceNameText> "Hello, world"^^xsd:string;
26
+ <http://www.mygrid.org.uk/mygrid-moby-service#providedBy> [ a <http://www.mygrid.org.uk/mygrid-moby-service#organisation>;
27
+ <http://protege.stanford.edu/plugins/owl/dc/protege-dc.owl#creator> "info@sadiframework.org"^^xsd:string;
28
+ <http://www.mygrid.org.uk/mygrid-moby-service#authoritative> true];
29
+ rdfs:comment "A simple \"Hello, World\" service that reads a name and attaches a greeting."^^xsd:string .
30
+ EOS
31
+
32
+ parse_string(str, :ttl)
33
+ end
34
+
35
+ def service_owl
36
+ str = <<-EOS
37
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
38
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
39
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
40
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
41
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
42
+
43
+ <> a owl:Ontology .
44
+
45
+ <#GreetedIndividual> a owl:Class;
46
+ owl:equivalentClass [ a owl:Restriction;
47
+ owl:onProperty <#greeting>;
48
+ owl:someValuesFrom xsd:string] .
49
+
50
+ <#NamedIndividual> a owl:Class;
51
+ owl:equivalentClass [ a owl:Restriction;
52
+ owl:minCardinality "1"^^xsd:int;
53
+ owl:onProperty foaf:name] .
54
+
55
+ <#SecondaryParameters> a owl:Class;
56
+ owl:equivalentClass [ a owl:Restriction;
57
+ owl:minCardinality "1"^^xsd:int;
58
+ owl:onProperty <#lang>] .
59
+
60
+ <#greeting> a owl:DatatypeProperty .
61
+
62
+ <#lang> a owl:DatatypeProperty .
63
+
64
+ foaf:name a owl:DatatypeProperty;
65
+ rdfs:isDefinedBy foaf:index.rdf .
66
+ EOS
67
+
68
+ parse_string(str, :ttl)
69
+ end
70
+
71
+ def owl_prefix
72
+ "http://sadiframework.org/examples/hello.owl#"
73
+ end
74
+
75
+ def process_object(in_graph, object)
76
+ out_graph = RDF::Graph.new
77
+
78
+ name = RDF::Query.execute(in_graph) do
79
+ pattern [object, RDF::FOAF.name, :name]
80
+ end
81
+ name = name.first.name
82
+
83
+ owl_vocab = RDF::Vocabulary.new(owl_prefix)
84
+
85
+ out_graph << RDF::Statement.new(object, RDF.type, output_classes.first)
86
+ out_graph << RDF::Statement.new(object, owl_vocab.greeting, "Hello, #{name}!")
87
+
88
+ out_graph
89
+ end
90
+ end
91
+ end
@@ -18,8 +18,13 @@ module SADI
18
18
  get_description(params[:service])
19
19
  end
20
20
 
21
+
21
22
  post '/services/:service' do
22
- handle_synchronous(params[:service])
23
+ handle_post(params[:service])
24
+ end
25
+
26
+ get '/poll/:service/:job' do
27
+ poll_service(params[:service], params[:job])
23
28
  end
24
29
 
25
30
  get '/files/:service/:file' do
@@ -32,10 +37,15 @@ module SADI
32
37
  repo
33
38
  end
34
39
 
35
- def handle_synchronous(service)
40
+ def handle_post(service)
36
41
  svc = SADI.service_for(service)
37
42
  raise "no service exists with name '#{service}'" unless svc
38
- rdf_response svc.process_input(request.body.read,request.content_type)
43
+ if svc.is_a? SynchronousService
44
+ rdf_response svc.process_input(request.body.read, request.content_type)
45
+ else
46
+ status 202
47
+ rdf_response svc.process_input(request.body.read, request.content_type, "http://#{request.host_with_port}/poll/#{svc.service_name}")
48
+ end
39
49
  end
40
50
 
41
51
  def get_description(service)
@@ -54,6 +64,34 @@ module SADI
54
64
  .map{|f| "#{f.content_type} (#{f.to_sym})"}
55
65
  .join('<br>')
56
66
  end
67
+
68
+ def poll_service(service, job)
69
+ svc = SADI.service_for(service)
70
+ result = svc.poll(job)
71
+ if result.is_a?(RDF::Graph) || result.is_a?(RDF::Repository)
72
+ result
73
+ else
74
+ redirect_poll(svc, job)
75
+ end
76
+ end
77
+
78
+ def redirect_poll(svc, job)
79
+ status 302
80
+ retry_time = 10
81
+ headers \
82
+ "Pragma" => "sadi-please-wait = #{retry_time}",
83
+ "Location" => request.url
84
+
85
+ end
86
+ end
87
+
88
+ class << self
89
+ alias_method :base_run!, :run!
90
+
91
+ def run!
92
+ SADI.reload_services
93
+ base_run!
94
+ end
57
95
  end
58
96
  end
59
97
  end
@@ -1,6 +1,5 @@
1
1
  module SADI
2
2
  class << self
3
-
4
3
  def service_for(name)
5
4
  services[name]
6
5
  end
@@ -16,7 +15,7 @@ module SADI
16
15
  def reload_services
17
16
  @@services = {}
18
17
 
19
- SADI::SynchronousService.classes.each do |service|
18
+ (SADI::SynchronousService.classes | SADI::AsynchronousService.classes).each do |service|
20
19
  if service.respond_to? 'service_name'
21
20
  name = service.service_name
22
21
  puts "Warning: service #{@@services[name]} already using name '#{name}', overwriting" if @@services[name]
@@ -1,6 +1,7 @@
1
1
  module SADI
2
2
  module SynchronousService
3
3
  include SADI::Converter
4
+ include SADI::BaseService
4
5
 
5
6
  def self.included(base)
6
7
  @classes ||= []
@@ -25,52 +26,5 @@ module SADI
25
26
 
26
27
  gr
27
28
  end
28
-
29
- def input_objects(graph)
30
- cl = input_classes.first
31
- solutions = RDF::Query.execute(graph) do
32
- pattern [:obj, RDF.type, cl]
33
- end
34
-
35
- solutions.map(&:obj)
36
- end
37
-
38
- def input_classes
39
- moby = RDF::Vocabulary.new('http://www.mygrid.org.uk/mygrid-moby-service#')
40
-
41
- solutions = RDF::Query.execute(service_description) do
42
- pattern [nil, moby.inputParameter, :param]
43
- pattern [:param, moby.objectType, :in_class]
44
- end
45
-
46
- solutions.map(&:in_class)
47
- end
48
-
49
- def output_classes
50
- moby = RDF::Vocabulary.new('http://www.mygrid.org.uk/mygrid-moby-service#')
51
-
52
- solutions = RDF::Query.execute(service_description) do
53
- pattern [nil, moby.outputParameter, :param]
54
- pattern [:param, moby.objectType, :out_class]
55
- end
56
-
57
- solutions.map(&:out_class)
58
- end
59
-
60
- def service_description(service)
61
- raise "Must implement a #service_description method returning an RDF::Graph or Repository"
62
- end
63
-
64
- def service_owl(service)
65
- raise "Must implement a #service_owl method returning an RDF::Graph or Repository"
66
- end
67
-
68
- def process_object(owl_graph, object)
69
- raise "Must implement a #process_input that takes an RDF::Graph or Repository as input and returns a new one"
70
- end
71
-
72
- def service_name
73
- raise "Must define a service name"
74
- end
75
29
  end
76
30
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "sadi-rb"
8
- s.version = "0.0.2"
8
+ s.version = "0.0.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Will Strinz"]
12
- s.date = "2013-10-15"
12
+ s.date = "2013-10-17"
13
13
  s.description = "Build and run SADI services with ruby-rdf and sinatra"
14
14
  s.email = "wstrinz@gmail.com"
15
15
  s.executables = ["sadi-rb"]
@@ -19,14 +19,18 @@ Gem::Specification.new do |s|
19
19
  ]
20
20
  s.files = [
21
21
  ".document",
22
+ ".travis.yml",
22
23
  "Gemfile",
23
24
  "LICENSE.txt",
24
25
  "README.md",
25
26
  "Rakefile",
26
27
  "bin/sadi-rb",
27
28
  "lib/sadi-rb.rb",
29
+ "lib/sadi-rb/asynchronous_service.rb",
30
+ "lib/sadi-rb/base_service.rb",
28
31
  "lib/sadi-rb/converter.rb",
29
32
  "lib/sadi-rb/example_service.rb",
33
+ "lib/sadi-rb/example_service_async.rb",
30
34
  "lib/sadi-rb/server.rb",
31
35
  "lib/sadi-rb/services.rb",
32
36
  "lib/sadi-rb/synchronous_service.rb",
@@ -43,7 +43,7 @@ describe SADI::Server do
43
43
 
44
44
  it "returns output on post" do
45
45
  header "Accept", "text/turtle"
46
- header "Content-Type", "application/rdf+xml"
46
+ header "Content-type", "application/rdf+xml"
47
47
 
48
48
  post '/services/hello', sample_input
49
49
 
@@ -54,16 +54,160 @@ describe SADI::Server do
54
54
  end
55
55
 
56
56
  context "content negotiation" do
57
- %w{application/rdf+xml text/turtle application/ld+json}.each do |format|
57
+ ['application/rdf+xml'].each do |format|
58
+ describe "accepts #{format} (JRuby issues)", no_travis: true do
59
+ it do
60
+ header "Accept", format
61
+ get '/services/hello'
62
+
63
+ last_response.should be_ok
64
+ last_response.content_type.should == format
65
+ end
66
+ end
67
+ end
68
+
69
+ %w{text/turtle application/ld+json application/json}.each do |format|
58
70
  describe "accepts #{format}" do
59
- it {
71
+ it do
60
72
  header "Accept", format
61
73
  get '/services/hello'
62
74
 
63
75
  last_response.should be_ok
64
76
  last_response.content_type.should == format
65
- }
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ describe "async services" do
83
+ it "basic get" do
84
+ get 'services/hello_async'
85
+ last_response.should be_ok
86
+ end
87
+
88
+ describe "post" do
89
+ it "receives poll url" do
90
+ header "Accept", "text/turtle"
91
+ header "Content-type", "application/rdf+xml"
92
+
93
+ post '/services/hello_async', sample_input
94
+ last_response.status.should == 202
95
+
96
+ last_response.body["rdf-schema#isDefinedBy"].should_not be nil
97
+ end
98
+
99
+ it "gets result from poll url" do
100
+ header "Accept", "text/turtle"
101
+ header "Content-type", "application/rdf+xml"
102
+
103
+ post '/services/hello_async', sample_input
104
+
105
+ last_response.status.should == 202
106
+
107
+ poll_id = last_response.body.scan(%r{http://example.org/poll/hello_async/(\w+)}).first.first
108
+
109
+ get "/poll/hello_async/#{poll_id}"
110
+
111
+ last_response.should be_ok
112
+ last_response.body["Hello, Guy Incognito"].should_not be nil
113
+ end
114
+
115
+ context "redirection" do
116
+ before :all do
117
+ @cl = Class.new do
118
+ extend SADI::AsynchronousService
119
+
120
+ def self.service_name
121
+ "my_async"
122
+ end
123
+
124
+ def self.service_description
125
+ ExampleServiceAsync.service_description
126
+ end
127
+
128
+ def self.service_owl
129
+ ExampleServiceAsync.service_owl
130
+ end
131
+
132
+ def self.process_object(input_graph, owl_object)
133
+ sleep(1)
134
+ ExampleServiceAsync.process_object(input_graph, owl_object)
135
+ end
136
+ end
137
+
138
+ SADI.reload_services
139
+ end
140
+
141
+ it "receives redirects" do
142
+ header "Accept", "text/turtle"
143
+ header "Content-type", "application/rdf+xml"
144
+
145
+ post '/services/my_async', sample_input
146
+
147
+ poll_id = last_response.body.scan(%r{http://example.org/poll/my_async/(\w+)}).first.first
148
+
149
+ get "/poll/my_async/#{poll_id}"
150
+
151
+ last_response.status.should == 302
152
+ # puts last_response.headers["Pragma"]
153
+ last_response.headers["Pragma"][/sadi-please-wait = \d+/].should_not be nil
154
+ last_response.headers["Location"].should == "http://example.org/poll/my_async/#{poll_id}"
155
+ end
156
+
157
+ it "eventually receives results" do
158
+ header "Accept", "text/turtle"
159
+ header "Content-type", "application/rdf+xml"
160
+
161
+ post '/services/my_async', sample_input.gsub("Guy Incognito", "Nick Danger")
162
+
163
+ poll_id = last_response.body.scan(%r{http://example.org/poll/my_async/(\w+)}).first.first
164
+
165
+ get "/poll/my_async/#{poll_id}"
166
+
167
+ last_response.status.should == 302
168
+
169
+ sleep 1
170
+
171
+ get "/poll/my_async/#{poll_id}"
172
+ last_response.body["Hello, Nick Danger"].should_not be nil
173
+ end
174
+ end
175
+
176
+ end
177
+ end
178
+
179
+ describe "define new classes" do
180
+ before do
181
+ @cl = Class.new do
182
+ extend SADI::SynchronousService
183
+
184
+ def self.service_name
185
+ "my_service_name" # => service will be accessible at "/services/my_service_name"
186
+ end
187
+
188
+ def self.service_description
189
+ # an RDF::Graph of your service's description
190
+ end
191
+
192
+ def self.service_owl
193
+ # an RDF::Graph of your service's OWL classes
194
+ end
195
+
196
+ def self.process_object(input_graph, owl_object)
197
+ # Service logic goes here
198
+
199
+ # Should return an RDF::Graph of
200
+ # the output for the resource specified by the URI owl_object,
201
+ # from the RDF::Graph input_graph
202
+ end
66
203
  end
204
+
205
+ SADI.reload_services
67
206
  end
207
+
208
+ it {
209
+ get 'services/my_service_name'
210
+ last_response.should be_ok
211
+ }
68
212
  end
69
213
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sadi-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Will Strinz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-15 00:00:00.000000000 Z
11
+ date: 2013-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -174,14 +174,18 @@ extra_rdoc_files:
174
174
  - README.md
175
175
  files:
176
176
  - .document
177
+ - .travis.yml
177
178
  - Gemfile
178
179
  - LICENSE.txt
179
180
  - README.md
180
181
  - Rakefile
181
182
  - bin/sadi-rb
182
183
  - lib/sadi-rb.rb
184
+ - lib/sadi-rb/asynchronous_service.rb
185
+ - lib/sadi-rb/base_service.rb
183
186
  - lib/sadi-rb/converter.rb
184
187
  - lib/sadi-rb/example_service.rb
188
+ - lib/sadi-rb/example_service_async.rb
185
189
  - lib/sadi-rb/server.rb
186
190
  - lib/sadi-rb/services.rb
187
191
  - lib/sadi-rb/synchronous_service.rb