publish_my_data 0.0.1
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/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
|