publish_my_data 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +37 -0
- data/Rakefile +41 -0
- data/app/assets/javascripts/publish_my_data/application.js +15 -0
- data/app/assets/javascripts/publish_my_data/resources.js +2 -0
- data/app/assets/stylesheets/publish_my_data/application.css +13 -0
- data/app/assets/stylesheets/publish_my_data/resources.css +4 -0
- data/app/controllers/publish_my_data/application_controller.rb +49 -0
- data/app/controllers/publish_my_data/datasets_controller.rb +48 -0
- data/app/controllers/publish_my_data/errors_controller.rb +9 -0
- data/app/controllers/publish_my_data/home_controller.rb +4 -0
- data/app/controllers/publish_my_data/resources_controller.rb +103 -0
- data/app/controllers/publish_my_data/sparql_controller.rb +50 -0
- data/app/helpers/publish_my_data/application_helper.rb +4 -0
- data/app/helpers/publish_my_data/resources_helper.rb +28 -0
- data/app/helpers/publish_my_data/sparql_helper.rb +7 -0
- data/app/models/publish_my_data/concept_scheme.rb +5 -0
- data/app/models/publish_my_data/dataset.rb +61 -0
- data/app/models/publish_my_data/ontology.rb +5 -0
- data/app/models/publish_my_data/rdf_type.rb +6 -0
- data/app/models/publish_my_data/resource.rb +21 -0
- data/app/views/layouts/publish_my_data/application.html.erb +14 -0
- data/app/views/layouts/publish_my_data/error.html.erb +3 -0
- data/app/views/publish_my_data/datasets/index.html.erb +20 -0
- data/app/views/publish_my_data/datasets/show.html.erb +18 -0
- data/app/views/publish_my_data/datasets/themes.html.erb +3 -0
- data/app/views/publish_my_data/errors/not_found.html.erb +1 -0
- data/app/views/publish_my_data/resources/_predicates_table.html.erb +22 -0
- data/app/views/publish_my_data/resources/_predicates_table_head.html.erb +6 -0
- data/app/views/publish_my_data/resources/_resource_formats.html.erb +11 -0
- data/app/views/publish_my_data/resources/_uri_and_label.html.erb +3 -0
- data/app/views/publish_my_data/resources/index.html.erb +39 -0
- data/app/views/publish_my_data/resources/show.html.erb +3 -0
- data/app/views/publish_my_data/sparql/_ask_formats.html.erb +3 -0
- data/app/views/publish_my_data/sparql/_construct_formats.html.erb +3 -0
- data/app/views/publish_my_data/sparql/_describe_formats.html.erb +1 -0
- data/app/views/publish_my_data/sparql/_error_message.html.erb +3 -0
- data/app/views/publish_my_data/sparql/_form.html.erb +4 -0
- data/app/views/publish_my_data/sparql/_formats.html.erb +6 -0
- data/app/views/publish_my_data/sparql/_pagination.html.erb +6 -0
- data/app/views/publish_my_data/sparql/_results.html.erb +5 -0
- data/app/views/publish_my_data/sparql/_results_data.html.erb +4 -0
- data/app/views/publish_my_data/sparql/_select_formats.html.erb +3 -0
- data/app/views/publish_my_data/sparql/endpoint.html.erb +10 -0
- data/config/initializers/tripod.rb +5 -0
- data/config/initializers/vocabularies.rb +1 -0
- data/config/routes.rb +33 -0
- data/lib/publish_my_data.rb +43 -0
- data/lib/publish_my_data/engine.rb +9 -0
- data/lib/publish_my_data/renderers.rb +44 -0
- data/lib/publish_my_data/sparql_query.rb +117 -0
- data/lib/publish_my_data/sparql_query_result.rb +49 -0
- data/lib/publish_my_data/version.rb +3 -0
- data/lib/tasks/publish_my_data_tasks.rake +4 -0
- data/spec/controllers/publish_my_data/datasets_controller_spec.rb +190 -0
- data/spec/controllers/publish_my_data/resources_controller_spec.rb +399 -0
- data/spec/controllers/publish_my_data/sparql_controller_spec.rb +172 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +68 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +38 -0
- data/spec/dummy/config/environments/production.rb +65 -0
- data/spec/dummy/config/environments/test.rb +41 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +10 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/log/development.log +211 -0
- data/spec/dummy/log/test.log +105012 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/dataset_factories.rb +12 -0
- data/spec/factories/property_factories.rb +13 -0
- data/spec/factories/resource_factories.rb +37 -0
- data/spec/features/running_a_sparql_query_spec.rb +324 -0
- data/spec/features/uri_dereferencing_flow_spec.rb +61 -0
- data/spec/features/uri_dereferencing_spec.rb +89 -0
- data/spec/features/viewing_a_def_spec.rb +45 -0
- data/spec/features/viewing_a_doc_spec.rb +124 -0
- data/spec/features/viewing_resource_not_in_our_domain_spec.rb +31 -0
- data/spec/lib/publish_my_data/sparql_query_spec.rb +495 -0
- data/spec/models/publish_my_data/dataset_spec.rb +29 -0
- data/spec/models/publish_my_data/resource_spec.rb +23 -0
- data/spec/renderers/publish_my_data/renderers_spec.rb +79 -0
- data/spec/spec_helper.rb +53 -0
- metadata +242 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
require "action_controller"
|
2
|
+
|
3
|
+
# turtle
|
4
|
+
Mime::Type.register("text/turtle", :ttl)
|
5
|
+
ActionController::Renderers.add :ttl do |obj, opts|
|
6
|
+
str = obj.respond_to?(:to_ttl) ? obj.to_ttl : obj.to_s
|
7
|
+
send_data str, :type => Mime::TTL, :disposition => "inline"
|
8
|
+
end
|
9
|
+
|
10
|
+
#rdf
|
11
|
+
Mime::Type.register("application/rdf+xml", :rdf)
|
12
|
+
ActionController::Renderers.add :rdf do |obj, opts|
|
13
|
+
str = obj.respond_to?(:to_rdf) ? obj.to_rdf : obj.to_s
|
14
|
+
send_data str, :type => Mime::RDF, :disposition => "inline"
|
15
|
+
end
|
16
|
+
|
17
|
+
#ntriples
|
18
|
+
# Note: We've elected not to respond with ntriples to text/plain as it confuses things
|
19
|
+
# (text/plain is used for plain-text tabular sparql-select results!
|
20
|
+
Mime::Type.register("application/n-triples", :nt )
|
21
|
+
|
22
|
+
ActionController::Renderers.add :nt do |obj, opts|
|
23
|
+
str = obj.respond_to?(:to_nt) ? obj.to_nt : obj.to_s
|
24
|
+
send_data str, :type => Mime::NT, :disposition => "inline"
|
25
|
+
end
|
26
|
+
|
27
|
+
# re-register JSON with extra headers
|
28
|
+
Mime::Type.unregister(:json)
|
29
|
+
Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest application/sparql-results+json )
|
30
|
+
# json already has a renderer
|
31
|
+
|
32
|
+
# likewise for XML
|
33
|
+
Mime::Type.unregister(:xml)
|
34
|
+
Mime::Type.register "application/xml", :xml, %w( text/xml application/x-xml application/sparql-results+xml )
|
35
|
+
# xml already has a renderer
|
36
|
+
|
37
|
+
# text mime type and renderer already defined
|
38
|
+
|
39
|
+
# csv mime type already registered.
|
40
|
+
# csv (for sparql SELECT results)
|
41
|
+
ActionController::Renderers.add :csv do |obj, opts|
|
42
|
+
str = obj.respond_to?(:to_csv) ? obj.to_csv : obj.to_s
|
43
|
+
send_data str, :type => Mime::CSV, :disposition => "inline"
|
44
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module PublishMyData
|
2
|
+
|
3
|
+
class SparqlQueryExecutionException < StandardError; end
|
4
|
+
|
5
|
+
class SparqlQuery < Tripod::SparqlQuery
|
6
|
+
|
7
|
+
attr_reader :request_format # symbol representing the format of the original request
|
8
|
+
attr_reader :parent_query # set if this query originated from another (e.g. pagination or count)
|
9
|
+
|
10
|
+
def initialize(query_string, request_format_symbol = :html, parent_query = nil)
|
11
|
+
super(query_string)
|
12
|
+
@parent_query = parent_query
|
13
|
+
@request_format = request_format_symbol
|
14
|
+
end
|
15
|
+
|
16
|
+
# executes the query, using the right format parameters (for fuseki) for the query type and request format
|
17
|
+
def execute
|
18
|
+
begin
|
19
|
+
case query_type
|
20
|
+
when :select
|
21
|
+
result_str = Tripod::SparqlClient::Query.select(self.query, select_format_str)
|
22
|
+
when :ask
|
23
|
+
result_str = Tripod::SparqlClient::Query.ask(self.query, ask_format_str)
|
24
|
+
when :construct
|
25
|
+
result_str = Tripod::SparqlClient::Query.construct(self.query, construct_or_describe_header)
|
26
|
+
when :describe
|
27
|
+
result_str = Tripod::SparqlClient::Query.describe(self.query, construct_or_describe_header)
|
28
|
+
else
|
29
|
+
raise SparqlQueryExecutionException.new("Unsupported Query Type. Please enter only SELECT, CONSTRUCT, DESCRIBE or ASK queries.")
|
30
|
+
end
|
31
|
+
|
32
|
+
rescue Tripod::Errors::BadSparqlRequest => bad_sparql
|
33
|
+
if self.parent_query
|
34
|
+
# call execute on the parent(this will fail too), but it means that we get the right error for
|
35
|
+
# the user-entered query
|
36
|
+
parent_query.execute
|
37
|
+
else
|
38
|
+
raise SparqlQueryExecutionException.new(process_sparql_parse_failed_exception_message(bad_sparql))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
PublishMyData::SparqlQueryResult.new(result_str)
|
43
|
+
end
|
44
|
+
|
45
|
+
# make a pagination version and execute that.
|
46
|
+
def paginate(page, per_page, look_ahead=0)
|
47
|
+
self.as_pagination_query(page, per_page, look_ahead).execute
|
48
|
+
end
|
49
|
+
|
50
|
+
# return the number of results that this query returns
|
51
|
+
# (creates and executes a count query behind the scenes)
|
52
|
+
def count
|
53
|
+
result = JSON.parse(self.as_count_query.execute.to_s)["results"]["bindings"]
|
54
|
+
result[0][".1"]["value"].to_i
|
55
|
+
end
|
56
|
+
|
57
|
+
def allow_pagination?
|
58
|
+
self.query_type == :select
|
59
|
+
end
|
60
|
+
|
61
|
+
def as_count_query(format = :json)
|
62
|
+
# return the paginated version
|
63
|
+
PublishMyData::SparqlQuery.new(as_count_query_str, format, self) # pass in the original query
|
64
|
+
end
|
65
|
+
|
66
|
+
# for selects only, turn this into a paginated version. Returns a whole new SparqlQuery object.
|
67
|
+
def as_pagination_query(page, per_page, look_ahead=0)
|
68
|
+
|
69
|
+
check_subqueryable!
|
70
|
+
|
71
|
+
limit = per_page + look_ahead
|
72
|
+
offset = per_page * (page-1)
|
73
|
+
# wrap it in a subselect with limit and offset
|
74
|
+
paginated_query = "SELECT * { #{self.body} } LIMIT #{limit} OFFSET #{offset}"
|
75
|
+
# put the prefixes back on the start
|
76
|
+
paginated_query = "#{self.prefixes} #{paginated_query}" if self.prefixes
|
77
|
+
|
78
|
+
# return the paginated version
|
79
|
+
PublishMyData::SparqlQuery.new(paginated_query, self.request_format, self) # pass in the original query
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def process_sparql_parse_failed_exception_message(bad_sparql_request)
|
85
|
+
message = bad_sparql_request.message
|
86
|
+
start = message.index(query) + query.size
|
87
|
+
finish = message.index('Fuseki')-1 || (message.length-1)
|
88
|
+
message[start..finish].strip
|
89
|
+
end
|
90
|
+
|
91
|
+
def select_format_str
|
92
|
+
if [:json, :csv, :xml, :text].include?(request_format)
|
93
|
+
self.request_format.to_s
|
94
|
+
else
|
95
|
+
'text'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def ask_format_str
|
100
|
+
if [:json, :xml, :text].include?(request_format)
|
101
|
+
self.request_format.to_s
|
102
|
+
else
|
103
|
+
'text'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def construct_or_describe_header
|
108
|
+
if [:nt, :ttl, :rdf].include?(request_format)
|
109
|
+
Mime::Type.lookup_by_extension( request_format.to_s )
|
110
|
+
else
|
111
|
+
Mime::NT
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'active_support/core_ext/numeric/bytes'
|
2
|
+
|
3
|
+
module PublishMyData
|
4
|
+
|
5
|
+
class SparqlQueryResultTooLargeException < StandardError; end
|
6
|
+
|
7
|
+
# class to wrap up a string sparql result
|
8
|
+
class SparqlQueryResult
|
9
|
+
|
10
|
+
cattr_accessor :MAX_SIZE
|
11
|
+
@@MAX_SIZE = 4.megabytes
|
12
|
+
|
13
|
+
attr_reader :result_str
|
14
|
+
|
15
|
+
def initialize(result_str)
|
16
|
+
@result_str = result_str
|
17
|
+
|
18
|
+
if self.length > SparqlQueryResult.MAX_SIZE
|
19
|
+
raise SparqlQueryResultTooLargeException.new(self.length)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# responds to a bunch of to_x methods to help with rails responders /rendering.
|
25
|
+
def length
|
26
|
+
self.to_s.length
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
self.result_str
|
31
|
+
end
|
32
|
+
|
33
|
+
[:csv, :nt, :ttl, :rdf, :text].each do |format|
|
34
|
+
define_method :"to_#{format.to_s}" do
|
35
|
+
self.to_s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_json(opts={})
|
40
|
+
to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_xml(opts={})
|
44
|
+
to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module PublishMyData
|
4
|
+
describe DatasetsController do
|
5
|
+
|
6
|
+
describe "#show" do
|
7
|
+
|
8
|
+
let(:dataset) { FactoryGirl.create(:my_dataset) }
|
9
|
+
|
10
|
+
shared_examples_for "dataset show" do
|
11
|
+
|
12
|
+
context "for an existing dataset" do
|
13
|
+
it "should respond successfully" do
|
14
|
+
get :show, id: dataset.slug, use_route: :publish_my_data, :format => format
|
15
|
+
response.should be_success
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should set the types variable" do
|
19
|
+
get :show, id: dataset.slug, use_route: :publish_my_data, :format => format
|
20
|
+
assigns['types'].class.should == Tripod::ResourceCollection
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with a non-existent dataset slug" do
|
25
|
+
it "should respond with not found" do
|
26
|
+
get :show, id: "slug-that-doesnt-exist", use_route: :publish_my_data, :format => format
|
27
|
+
response.should be_not_found
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
shared_examples_for "a non html format" do
|
33
|
+
|
34
|
+
context "for an existing dataset" do
|
35
|
+
it "should return the dataset dtls in that format" do
|
36
|
+
get :show, id: dataset.slug, use_route: :publish_my_data, :format => format
|
37
|
+
response.body.should == dataset.send("to_#{format}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "for a non-existent dataset slug" do
|
42
|
+
it "should return a blank body" do
|
43
|
+
get :show, id: "slug-that-doesnt-exist", use_route: :publish_my_data, :format => format
|
44
|
+
response.body.should be_blank
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "for rdf format" do
|
50
|
+
let(:format){ 'html' }
|
51
|
+
it_should_behave_like "dataset show"
|
52
|
+
end
|
53
|
+
|
54
|
+
context "for rdf format" do
|
55
|
+
let(:format){ 'rdf' }
|
56
|
+
it_should_behave_like "a non html format"
|
57
|
+
it_should_behave_like "dataset show"
|
58
|
+
end
|
59
|
+
|
60
|
+
context "for json format" do
|
61
|
+
let(:format){ 'json' }
|
62
|
+
it_should_behave_like "a non html format"
|
63
|
+
it_should_behave_like "dataset show"
|
64
|
+
end
|
65
|
+
|
66
|
+
context "for ttl format" do
|
67
|
+
let(:format){ 'ttl' }
|
68
|
+
it_should_behave_like "a non html format"
|
69
|
+
it_should_behave_like "dataset show"
|
70
|
+
end
|
71
|
+
|
72
|
+
context "for ntriples format" do
|
73
|
+
let(:format){ 'nt' }
|
74
|
+
it_should_behave_like "a non html format"
|
75
|
+
it_should_behave_like "dataset show"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#index" do
|
81
|
+
|
82
|
+
# make some datasets
|
83
|
+
before do
|
84
|
+
(1..30).each do |i|
|
85
|
+
slug = i
|
86
|
+
uri = Dataset.uri_from_slug(slug)
|
87
|
+
graph = Dataset.metadata_graph_uri(slug)
|
88
|
+
d = PublishMyData::Dataset.new(uri, graph)
|
89
|
+
d.title = "Dataset #{i.to_s}"
|
90
|
+
d.theme = (i.even? ? 'theme' : 'othertheme')
|
91
|
+
d.save!
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
shared_examples_for "a dataset collection in non-html" do
|
96
|
+
it "should render the collection in the right format" do
|
97
|
+
get :index, :page => page, :per_page => per_page, :format => format, use_route: :publish_my_data
|
98
|
+
response.body.should == Dataset.all.limit(per_page).offset(offset).resources.send("to_#{format}")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "shouldn't call Kaminari" do
|
102
|
+
Kaminari.should_not_receive(:paginate_array)
|
103
|
+
get :index, :page => page, :per_page => per_page, :format => format, use_route: :publish_my_data
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should render successfully" do
|
107
|
+
get :index, :page => page, :per_page => per_page, :format => format, use_route: :publish_my_data
|
108
|
+
response.should be_success
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
shared_examples_for "dataset kaminari pagination" do
|
113
|
+
it "should call kaminari to paginate the results" do
|
114
|
+
datasets_array = Dataset.all.limit(per_page).offset(offset).resources.to_a
|
115
|
+
count = Dataset.count
|
116
|
+
|
117
|
+
kam = Kaminari.paginate_array(datasets_array, total_count: count)
|
118
|
+
|
119
|
+
Kaminari.should_receive(:paginate_array).with(datasets_array, total_count: count).and_return(kam)
|
120
|
+
kam.should_receive(:page).with(page).and_return(kam)
|
121
|
+
kam.should_receive(:per).with(per_page).and_return(kam)
|
122
|
+
get :index, page: page, per_page: per_page, use_route: :publish_my_data
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should set @datasets with the right page of datasets" do
|
126
|
+
get :index, page: page, per_page: per_page, use_route: :publish_my_data
|
127
|
+
assigns['datasets'].map{ |d| d.uri.to_s }.should ==
|
128
|
+
Dataset.all.resources[offset...offset+per_page].map{ |d| d.uri.to_s }
|
129
|
+
assigns['datasets'].length.should == per_page
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'with no pagination params' do
|
135
|
+
let(:page) {1}
|
136
|
+
let(:per_page) {20}
|
137
|
+
let(:offset) { (page-1)*per_page }
|
138
|
+
|
139
|
+
it "should retreive the first page of results" do
|
140
|
+
crit = Dataset.all
|
141
|
+
Dataset.should_receive(:all).at_least(:once).and_return(crit)
|
142
|
+
crit.should_receive(:limit).with(per_page).and_call_original
|
143
|
+
crit.should_receive(:offset).with(offset).and_call_original
|
144
|
+
get :index, use_route: :publish_my_data
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'with html format' do
|
148
|
+
it_should_behave_like "dataset kaminari pagination"
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'with non-html format' do
|
152
|
+
let(:format) {'rdf'}
|
153
|
+
it_should_behave_like "a dataset collection in non-html"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'with pagination params' do
|
158
|
+
let(:page) {3}
|
159
|
+
let(:per_page) {10}
|
160
|
+
let(:offset) { (page-1)*per_page }
|
161
|
+
|
162
|
+
it "should retreive the right page of results" do
|
163
|
+
crit = Dataset.all
|
164
|
+
Dataset.should_receive(:all).at_least(:once).and_return(crit)
|
165
|
+
crit.should_receive(:limit).with(per_page).and_call_original
|
166
|
+
crit.should_receive(:offset).with(offset).and_call_original
|
167
|
+
get :index, page: page, per_page: per_page, use_route: :publish_my_data
|
168
|
+
end
|
169
|
+
|
170
|
+
it_should_behave_like "dataset kaminari pagination"
|
171
|
+
|
172
|
+
context 'with non-html format' do
|
173
|
+
let(:format) {'ttl'}
|
174
|
+
it_should_behave_like "a dataset collection in non-html"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "with a theme parameter" do
|
179
|
+
let(:theme) {'theme'}
|
180
|
+
|
181
|
+
it "should filter the results to only datasets in the theme" do
|
182
|
+
get :index, theme: theme, use_route: :publish_my_data
|
183
|
+
assigns['datasets'].length.should == 15 # only the even ones are in this theme
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,399 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module PublishMyData
|
4
|
+
describe ResourcesController do
|
5
|
+
|
6
|
+
describe "#id" do
|
7
|
+
|
8
|
+
context "with html mime type" do
|
9
|
+
|
10
|
+
before do
|
11
|
+
get :id, :path => "this/is/my/path", use_route: :publish_my_data
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should redirect to the corresponding doc view with a 303" do
|
15
|
+
response.status.should eq(303)
|
16
|
+
response.should redirect_to "/doc/this/is/my/path"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "with an alternative mime type passed in the header" do
|
21
|
+
before do
|
22
|
+
@request.env['HTTP_ACCEPT'] = "application/rdf+xml"
|
23
|
+
get :id, :path => "this/is/my/path", use_route: :publish_my_data
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should keep that mime type when doing the 303" do
|
27
|
+
response.status.should eq(303)
|
28
|
+
response.should redirect_to "/doc/this/is/my/path"
|
29
|
+
response.content_type.should == Mime::RDF
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#doc" do
|
36
|
+
|
37
|
+
before do
|
38
|
+
@resource = FactoryGirl.create(:yuri_unicorn_resource)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should respond successfully" do
|
42
|
+
get :doc, :path => "unicorns/yuri", use_route: :publish_my_data
|
43
|
+
response.should be_success
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should render the show template" do
|
47
|
+
get :doc, :path => "unicorns/yuri", use_route: :publish_my_data
|
48
|
+
response.should render_template("publish_my_data/resources/show")
|
49
|
+
end
|
50
|
+
|
51
|
+
context "for html" do
|
52
|
+
it "should eager load the labels" do
|
53
|
+
Resource.should_receive(:find).and_return(@resource)
|
54
|
+
@resource.should_receive(:eager_load_predicate_triples!)
|
55
|
+
@resource.should_receive(:eager_load_object_triples!)
|
56
|
+
get :doc, :path => "unicorns/yuri", use_route: :publish_my_data
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with an alternative mime type passed in the header" do
|
61
|
+
|
62
|
+
before do
|
63
|
+
@request.env['HTTP_ACCEPT'] = "application/rdf+xml"
|
64
|
+
get :doc, :path => "unicorns/yuri", use_route: :publish_my_data
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should resond with the right mime type" do
|
68
|
+
response.content_type.should == Mime::RDF
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should respond with the right content" do
|
72
|
+
response.body.should == @resource.to_rdf
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not eager load the labels" do
|
76
|
+
Resource.should_receive(:find).and_return(@resource)
|
77
|
+
@resource.should_not_receive(:eager_load_predicate_triples!)
|
78
|
+
@resource.should_not_receive(:eager_load_object_triples!)
|
79
|
+
get :doc, :path => "unicorns/yuri", use_route: :publish_my_data
|
80
|
+
end
|
81
|
+
|
82
|
+
context "and the resource doesn't exist" do
|
83
|
+
it "should 404 with a blank response" do
|
84
|
+
get :doc, :path => "unicorns/borat", use_route: :publish_my_data
|
85
|
+
response.should be_not_found
|
86
|
+
response.body.should be_blank
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with an alternative format passed on the url" do
|
93
|
+
|
94
|
+
it "should resond with the right mime type" do
|
95
|
+
get :doc, :path => "unicorns/yuri", format: 'ttl', use_route: :publish_my_data
|
96
|
+
response.content_type.should == Mime::TTL
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should respond with the right content" do
|
100
|
+
get :doc, :path => "unicorns/yuri", format: 'ttl', use_route: :publish_my_data
|
101
|
+
response.body.should == @resource.to_ttl
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when resource doesn't exist" do
|
107
|
+
|
108
|
+
before do
|
109
|
+
get :doc, :path => "doesnt/exist", use_route: :publish_my_data
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should 404" do
|
113
|
+
response.should be_not_found
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "#definition" do
|
121
|
+
|
122
|
+
before do
|
123
|
+
@resource = FactoryGirl.create(:mean_result)
|
124
|
+
end
|
125
|
+
|
126
|
+
context "for resource in our database" do
|
127
|
+
|
128
|
+
it "should respond successfully" do
|
129
|
+
get :definition, :path => "statistics/meanResult", use_route: :publish_my_data
|
130
|
+
response.should be_success
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should render the doc template" do
|
134
|
+
get :definition, :path => "statistics/meanResult", use_route: :publish_my_data
|
135
|
+
response.should render_template("publish_my_data/resources/show")
|
136
|
+
end
|
137
|
+
|
138
|
+
context "with an alternative mime type" do
|
139
|
+
it "should with the right mime type and content" do
|
140
|
+
get :definition, :path => "statistics/meanResult", :format => 'nt', use_route: :publish_my_data
|
141
|
+
response.content_type.should == Mime::NT
|
142
|
+
response.body.should == @resource.to_nt
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
context "when resource doesn't exist" do
|
149
|
+
it "should 404" do
|
150
|
+
get :definition, :path => "statistics/nonExistent", use_route: :publish_my_data
|
151
|
+
response.should be_not_found
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "#show" do
|
158
|
+
|
159
|
+
context "with a resource not in our database" do
|
160
|
+
|
161
|
+
uri = "http://purl.org/linked-data/sdmx/2009/dimension%23refArea"
|
162
|
+
|
163
|
+
context "html mime type" do
|
164
|
+
|
165
|
+
before do
|
166
|
+
get :show, :uri => uri, use_route: :publish_my_data
|
167
|
+
end
|
168
|
+
|
169
|
+
context "with resource not in our database" do
|
170
|
+
it "should redirect to the external uri" do
|
171
|
+
response.should redirect_to('http://purl.org/linked-data/sdmx/2009/dimension%23refArea')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
context "non html mime type" do
|
178
|
+
|
179
|
+
before do
|
180
|
+
get :show, :uri => uri, :format => 'rdf', use_route: :publish_my_data
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should 404" do
|
184
|
+
response.should be_not_found
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context "with a resource in our database" do
|
190
|
+
|
191
|
+
before do
|
192
|
+
uri = 'http://uri'
|
193
|
+
graph = 'http://graph'
|
194
|
+
r = Resource.new(uri, graph)
|
195
|
+
r.write_predicate('http://foo', 'blah')
|
196
|
+
r.save!
|
197
|
+
|
198
|
+
get :show, :uri => r.uri, use_route: :publish_my_data
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should respond succesfully" do
|
202
|
+
response.should be_success
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should render the show template" do
|
206
|
+
response.should render_template("publish_my_data/resources/show")
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "#index" do
|
213
|
+
|
214
|
+
shared_examples_for "resource kaminari pagination" do
|
215
|
+
it "should call kaminari to paginate the results" do
|
216
|
+
res_array = Resource.all.limit(per_page).offset(offset).resources.to_a
|
217
|
+
count = Resource.count
|
218
|
+
|
219
|
+
kam = Kaminari.paginate_array(res_array, total_count: count)
|
220
|
+
|
221
|
+
Kaminari.should_receive(:paginate_array).with(res_array, total_count: count).and_return(kam)
|
222
|
+
kam.should_receive(:page).with(page).and_return(kam)
|
223
|
+
kam.should_receive(:per).with(per_page).and_return(kam)
|
224
|
+
get :index, page: page, per_page: per_page, use_route: :publish_my_data
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should set @resources with the right page of datasets" do
|
228
|
+
get :index, page: page, per_page: per_page, use_route: :publish_my_data
|
229
|
+
assigns['resources'].map{ |d| d.uri.to_s }.should ==
|
230
|
+
Resource.all.resources[offset...offset+per_page].map{ |r| r.uri.to_s }
|
231
|
+
assigns['resources'].length.should == per_page
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
shared_examples_for "a resource collection in non-html" do
|
236
|
+
it "should render the collection in the right format" do
|
237
|
+
get :index, :page => page, :per_page => per_page, :format => format, use_route: :publish_my_data
|
238
|
+
response.body.should == Resource.all.limit(per_page).offset(offset).resources.send("to_#{format}")
|
239
|
+
end
|
240
|
+
|
241
|
+
it "shouldn't call Kaminari" do
|
242
|
+
Kaminari.should_not_receive(:paginate_array)
|
243
|
+
get :index, :page => page, :per_page => per_page, :format => format, use_route: :publish_my_data
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should render successfully" do
|
247
|
+
get :index, :page => page, :per_page => per_page, :format => format, use_route: :publish_my_data
|
248
|
+
response.should be_success
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
let(:dataset) { FactoryGirl.create(:my_dataset) }
|
253
|
+
|
254
|
+
let(:type) do
|
255
|
+
t = PublishMyData::RdfType.new('http://i-am-a-type', 'http://types')
|
256
|
+
t.label = 'I am a type'
|
257
|
+
t.save!
|
258
|
+
t
|
259
|
+
end
|
260
|
+
|
261
|
+
before do
|
262
|
+
|
263
|
+
# make some resources (in and out of our dataset and type)
|
264
|
+
(1..5).each do |i|
|
265
|
+
r = Resource.new("http://resource-in-ds/#{i}", dataset.data_graph_uri)
|
266
|
+
r.label = "resource #{i}"
|
267
|
+
r.write_predicate(RDF.type, RDF::URI.new(type.uri)) if i.even?
|
268
|
+
r.save!
|
269
|
+
end
|
270
|
+
|
271
|
+
(1..3).each do |i|
|
272
|
+
r = Resource.new("http://resource-not-in-ds/#{i}", 'http://anothergraph')
|
273
|
+
r.label = "resource #{i}"
|
274
|
+
r.write_predicate(RDF.type, RDF::URI.new(type.uri)) if i.even?
|
275
|
+
r.save!
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should set the resources variable' do
|
280
|
+
get :index, use_route: :publish_my_data
|
281
|
+
assigns['resources'].should_not be_blank
|
282
|
+
end
|
283
|
+
|
284
|
+
context "with no parameters" do
|
285
|
+
it "should respond successfully" do
|
286
|
+
get :index, use_route: :publish_my_data
|
287
|
+
end
|
288
|
+
|
289
|
+
it "should return paginated results for Resource.all" do
|
290
|
+
subject.should_receive(:paginate_resources).with(Resource.all).and_call_original
|
291
|
+
get :index, use_route: :publish_my_data
|
292
|
+
assigns['resources'].length.should == 10 # 8 resources, plus ds and type!
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'with pagination params' do
|
297
|
+
let(:page) {2}
|
298
|
+
let(:per_page) {2}
|
299
|
+
let(:offset) { (page-1)*per_page }
|
300
|
+
|
301
|
+
it "should retreive the right page of results" do
|
302
|
+
crit = Resource.all
|
303
|
+
Resource.should_receive(:all).at_least(:once).and_return(crit)
|
304
|
+
crit.should_receive(:limit).with(per_page).and_call_original
|
305
|
+
crit.should_receive(:offset).with(offset).and_call_original
|
306
|
+
get :index, page: page, per_page: per_page, use_route: :publish_my_data
|
307
|
+
end
|
308
|
+
|
309
|
+
it_should_behave_like "resource kaminari pagination"
|
310
|
+
|
311
|
+
context 'with non-html format' do
|
312
|
+
let(:format) {'ttl'}
|
313
|
+
it_should_behave_like "a resource collection in non-html"
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
context 'with a type parameter' do
|
318
|
+
context 'where the type exists' do
|
319
|
+
before do
|
320
|
+
get :index, type_uri: type.uri, use_route: :publish_my_data
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'should filter the results by things of that type' do
|
324
|
+
assigns['resources'].length.should == 3
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'should set the type filter variable' do
|
328
|
+
assigns['type_filter'].should == type.uri
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'should set the dataset variable to the dataset' do
|
332
|
+
assigns['type'].should == type
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
context 'where the type does not exist' do
|
337
|
+
before do
|
338
|
+
get :index, type_uri: 'bleh', use_route: :publish_my_data
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'should not find any results' do
|
342
|
+
assigns['resources'].length.should == 0
|
343
|
+
end
|
344
|
+
|
345
|
+
it 'should set the type filter variable' do
|
346
|
+
assigns['type_filter'].should == 'bleh'
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'should not set the type variable' do
|
350
|
+
assigns['type'].should be_nil
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
context "with a dataset parameter" do
|
356
|
+
context 'where the dataset exists' do
|
357
|
+
|
358
|
+
before do
|
359
|
+
get :index, dataset: dataset.slug, use_route: :publish_my_data
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should filter the results by datasets with that slug" do
|
363
|
+
assigns['resources'].length.should == 5
|
364
|
+
end
|
365
|
+
|
366
|
+
it 'should set the dataset filter variable' do
|
367
|
+
assigns['dataset_filter'].should == dataset.slug
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'should set the dataset variable to the dataset' do
|
371
|
+
assigns['dataset'].should == dataset
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
|
376
|
+
context 'where the dataset does not exist' do
|
377
|
+
before do
|
378
|
+
get :index, dataset: 'bleh', use_route: :publish_my_data
|
379
|
+
end
|
380
|
+
|
381
|
+
it 'should not find any results' do
|
382
|
+
assigns['resources'].length.should == 0
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'should set the dataset filter variable' do
|
386
|
+
assigns['dataset_filter'].should == 'bleh'
|
387
|
+
end
|
388
|
+
|
389
|
+
it 'should not set the dataset variable to the dataset' do
|
390
|
+
assigns['dataset'].should be_nil
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
|
398
|
+
end
|
399
|
+
end
|