publish_my_data 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +37 -0
  3. data/Rakefile +41 -0
  4. data/app/assets/javascripts/publish_my_data/application.js +15 -0
  5. data/app/assets/javascripts/publish_my_data/resources.js +2 -0
  6. data/app/assets/stylesheets/publish_my_data/application.css +13 -0
  7. data/app/assets/stylesheets/publish_my_data/resources.css +4 -0
  8. data/app/controllers/publish_my_data/application_controller.rb +49 -0
  9. data/app/controllers/publish_my_data/datasets_controller.rb +48 -0
  10. data/app/controllers/publish_my_data/errors_controller.rb +9 -0
  11. data/app/controllers/publish_my_data/home_controller.rb +4 -0
  12. data/app/controllers/publish_my_data/resources_controller.rb +103 -0
  13. data/app/controllers/publish_my_data/sparql_controller.rb +50 -0
  14. data/app/helpers/publish_my_data/application_helper.rb +4 -0
  15. data/app/helpers/publish_my_data/resources_helper.rb +28 -0
  16. data/app/helpers/publish_my_data/sparql_helper.rb +7 -0
  17. data/app/models/publish_my_data/concept_scheme.rb +5 -0
  18. data/app/models/publish_my_data/dataset.rb +61 -0
  19. data/app/models/publish_my_data/ontology.rb +5 -0
  20. data/app/models/publish_my_data/rdf_type.rb +6 -0
  21. data/app/models/publish_my_data/resource.rb +21 -0
  22. data/app/views/layouts/publish_my_data/application.html.erb +14 -0
  23. data/app/views/layouts/publish_my_data/error.html.erb +3 -0
  24. data/app/views/publish_my_data/datasets/index.html.erb +20 -0
  25. data/app/views/publish_my_data/datasets/show.html.erb +18 -0
  26. data/app/views/publish_my_data/datasets/themes.html.erb +3 -0
  27. data/app/views/publish_my_data/errors/not_found.html.erb +1 -0
  28. data/app/views/publish_my_data/resources/_predicates_table.html.erb +22 -0
  29. data/app/views/publish_my_data/resources/_predicates_table_head.html.erb +6 -0
  30. data/app/views/publish_my_data/resources/_resource_formats.html.erb +11 -0
  31. data/app/views/publish_my_data/resources/_uri_and_label.html.erb +3 -0
  32. data/app/views/publish_my_data/resources/index.html.erb +39 -0
  33. data/app/views/publish_my_data/resources/show.html.erb +3 -0
  34. data/app/views/publish_my_data/sparql/_ask_formats.html.erb +3 -0
  35. data/app/views/publish_my_data/sparql/_construct_formats.html.erb +3 -0
  36. data/app/views/publish_my_data/sparql/_describe_formats.html.erb +1 -0
  37. data/app/views/publish_my_data/sparql/_error_message.html.erb +3 -0
  38. data/app/views/publish_my_data/sparql/_form.html.erb +4 -0
  39. data/app/views/publish_my_data/sparql/_formats.html.erb +6 -0
  40. data/app/views/publish_my_data/sparql/_pagination.html.erb +6 -0
  41. data/app/views/publish_my_data/sparql/_results.html.erb +5 -0
  42. data/app/views/publish_my_data/sparql/_results_data.html.erb +4 -0
  43. data/app/views/publish_my_data/sparql/_select_formats.html.erb +3 -0
  44. data/app/views/publish_my_data/sparql/endpoint.html.erb +10 -0
  45. data/config/initializers/tripod.rb +5 -0
  46. data/config/initializers/vocabularies.rb +1 -0
  47. data/config/routes.rb +33 -0
  48. data/lib/publish_my_data.rb +43 -0
  49. data/lib/publish_my_data/engine.rb +9 -0
  50. data/lib/publish_my_data/renderers.rb +44 -0
  51. data/lib/publish_my_data/sparql_query.rb +117 -0
  52. data/lib/publish_my_data/sparql_query_result.rb +49 -0
  53. data/lib/publish_my_data/version.rb +3 -0
  54. data/lib/tasks/publish_my_data_tasks.rake +4 -0
  55. data/spec/controllers/publish_my_data/datasets_controller_spec.rb +190 -0
  56. data/spec/controllers/publish_my_data/resources_controller_spec.rb +399 -0
  57. data/spec/controllers/publish_my_data/sparql_controller_spec.rb +172 -0
  58. data/spec/dummy/README.rdoc +261 -0
  59. data/spec/dummy/Rakefile +7 -0
  60. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  61. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  62. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  63. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  64. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  65. data/spec/dummy/config.ru +4 -0
  66. data/spec/dummy/config/application.rb +68 -0
  67. data/spec/dummy/config/boot.rb +10 -0
  68. data/spec/dummy/config/environment.rb +5 -0
  69. data/spec/dummy/config/environments/development.rb +38 -0
  70. data/spec/dummy/config/environments/production.rb +65 -0
  71. data/spec/dummy/config/environments/test.rb +41 -0
  72. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  73. data/spec/dummy/config/initializers/inflections.rb +15 -0
  74. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  75. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  76. data/spec/dummy/config/initializers/session_store.rb +8 -0
  77. data/spec/dummy/config/initializers/wrap_parameters.rb +10 -0
  78. data/spec/dummy/config/locales/en.yml +5 -0
  79. data/spec/dummy/config/routes.rb +4 -0
  80. data/spec/dummy/log/development.log +211 -0
  81. data/spec/dummy/log/test.log +105012 -0
  82. data/spec/dummy/public/404.html +26 -0
  83. data/spec/dummy/public/422.html +26 -0
  84. data/spec/dummy/public/500.html +25 -0
  85. data/spec/dummy/public/favicon.ico +0 -0
  86. data/spec/dummy/script/rails +6 -0
  87. data/spec/factories/dataset_factories.rb +12 -0
  88. data/spec/factories/property_factories.rb +13 -0
  89. data/spec/factories/resource_factories.rb +37 -0
  90. data/spec/features/running_a_sparql_query_spec.rb +324 -0
  91. data/spec/features/uri_dereferencing_flow_spec.rb +61 -0
  92. data/spec/features/uri_dereferencing_spec.rb +89 -0
  93. data/spec/features/viewing_a_def_spec.rb +45 -0
  94. data/spec/features/viewing_a_doc_spec.rb +124 -0
  95. data/spec/features/viewing_resource_not_in_our_domain_spec.rb +31 -0
  96. data/spec/lib/publish_my_data/sparql_query_spec.rb +495 -0
  97. data/spec/models/publish_my_data/dataset_spec.rb +29 -0
  98. data/spec/models/publish_my_data/resource_spec.rb +23 -0
  99. data/spec/renderers/publish_my_data/renderers_spec.rb +79 -0
  100. data/spec/spec_helper.rb +53 -0
  101. metadata +242 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 Swirrl IT Limited
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # PublishMyData Community Edition.
2
+
3
+ ## Overview
4
+
5
+ PublishMyData is a Rails Engine that adds Linked Data functionality to your Rails app including:
6
+
7
+ - URI dereferencing and displaying resources outside your site domain
8
+ - A SPARQL Endpoint
9
+ - Filterable lists of datasets and resources
10
+
11
+ ## How to use
12
+
13
+ 1. Add it to your Gemfile
14
+
15
+ gem tripod
16
+
17
+ 2. Configure it (in application.rb, or development.rb/production.rb/test.rb)
18
+
19
+ PublishMyData.configure do |config|
20
+ config.sparql_endpoint = 'http://localhost:3030/pmd/sparql'
21
+ config.local_domain = 'pmd.dev'
22
+ config.sparql_timeout_seconds = 30
23
+ config.tripod_cache_store = Tripod::CacheStores::MemcachedCacheStore.new('localhost:11211')
24
+ end
25
+
26
+
27
+ ## Notes
28
+
29
+ - PublishMyData uses [Tripod](http://github.com/Swirrl/tripod) for database access.
30
+ - See the Rails guides for [more details on Rails Engines](http://guides.rubyonrails.org/engines.html).
31
+ - PublishMyData doesn't supply a database. You need to install one. I recommend [Fuseki](http://jena.apache.org/documentation/serving_data/index.html), which runs on port 3030 by default.
32
+ - The views currently supplied by this Rails engine are very rudimentary. Some nicer default views coming soon, but for now you'll probably just want to override them all in your app.
33
+ - Warning: This gem is usable now, but the API is under constant development and flux at the moment
34
+
35
+ ## Licence
36
+
37
+ Uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ begin
5
+ require 'bundler/setup'
6
+ rescue LoadError
7
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
8
+ end
9
+ begin
10
+ require 'rdoc/task'
11
+ rescue LoadError
12
+ require 'rdoc/rdoc'
13
+ require 'rake/rdoctask'
14
+ RDoc::Task = Rake::RDocTask
15
+ end
16
+
17
+ RDoc::Task.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'PublishMyData'
20
+ rdoc.options << '--line-numbers'
21
+ rdoc.rdoc_files.include('README.rdoc')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
26
+ load 'rails/tasks/engine.rake'
27
+
28
+ require 'rspec/core/rake_task'
29
+
30
+ RSpec::Core::RakeTask.new("spec") do |spec|
31
+ spec.pattern = "spec/**/*_spec.rb"
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new('spec:progress') do |spec|
35
+ spec.rspec_opts = %w(--format progress)
36
+ spec.pattern = "spec/**/*_spec.rb"
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,49 @@
1
+ module PublishMyData
2
+ class ApplicationController < ActionController::Base
3
+
4
+ rescue_from Tripod::Errors::ResourceNotFound, :with => :resource_not_found
5
+
6
+ # TODO: handle:
7
+ # 500s, timeouts (503) etc.
8
+
9
+ private
10
+
11
+ def resource_not_found(e)
12
+ respond_to do |format|
13
+ format.html { render(:template => "publish_my_data/errors/not_found", :layout => 'publish_my_data/error', :status => 404) and return false }
14
+ #TODO: ? format.js { render(:template => "publish_my_data/errors/not_found", :status => 200) and return false } # need to return success or the ajax request fails
15
+ format.any { head(:status => 404, :content_type => 'text/plain') and return false }
16
+ end
17
+ end
18
+
19
+ # from the criteria passed in, sets an instance var for @count and return
20
+ # a Kaminari::PaginatableArray, or Array (as appropriate to the format)
21
+ def paginate_resources(criteria)
22
+
23
+ get_pagination_params unless @got_pagination_params
24
+
25
+ @count = criteria.count #this has to happen first, before we modify the criteria with limit/offset
26
+ resources = criteria.limit(@limit).offset(@offset).resources
27
+
28
+ if request.format.html?
29
+ Kaminari.paginate_array(resources.to_a, total_count: @count).page(@page).per(@limit)
30
+ else
31
+ resources # non html versions just need the raw array
32
+ end
33
+ end
34
+
35
+ def get_pagination_params
36
+ default_page_size = 20
37
+
38
+ @per_page = (params[:per_page] || default_page_size).to_i
39
+ @per_page = 10000 if @per_page > 10000
40
+ @page = (params[:page] || 1).to_i
41
+
42
+ @limit = @per_page
43
+ @offset = @limit.to_i * (@page.to_i-1)
44
+
45
+ @got_pagination_params = true
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ require_dependency "publish_my_data/application_controller"
2
+
3
+ module PublishMyData
4
+ class DatasetsController < ApplicationController
5
+
6
+ respond_to :html, :ttl, :rdf, :nt, :json
7
+
8
+ # /datasets/:id (where :id is the dataset 'slug')
9
+ def show
10
+ @dataset = Dataset.find_by_slug(params[:id])
11
+ @types = RdfType.where('?s a ?uri').graph(@dataset.data_graph_uri).resources
12
+
13
+ if request.format.html?
14
+ @type_resource_counts = {}
15
+ @types.each do |t|
16
+ @type_resource_counts[t.uri.to_s] = Resource.where("?uri a <#{t.uri.to_s}>").count
17
+ end
18
+ end
19
+
20
+ respond_with(@dataset)
21
+ end
22
+
23
+ # /datasets?page=2&per_page=10
24
+ # /datasets?theme=foo
25
+ def index
26
+ dataset_criteria = Dataset.all
27
+ dataset_criteria = add_theme_filter(dataset_criteria)
28
+ @datasets = paginate_resources(dataset_criteria)
29
+ respond_with(@datasets)
30
+ end
31
+
32
+ def themes
33
+ # TODO: decide on how the themes will be represented in the metadata.
34
+ # Get a list of themes.
35
+ @themes = ['theme1', 'theme2']
36
+ end
37
+
38
+ private
39
+
40
+ def add_theme_filter(criteria)
41
+ unless params[:theme].blank?
42
+ @theme = params[:theme]
43
+ criteria.where("?uri <#{PMD_DS.theme}> '#{@theme}'")
44
+ end
45
+ criteria
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ #http://accuser.cc/posts/1-rails-3-0-exception-handling
2
+ module PublishMyData
3
+ class ErrorsController < ApplicationController
4
+ def routing
5
+ # just re-raise a tripod not found error. Handled in Application Controller
6
+ raise Tripod::Errors::ResourceNotFound
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module PublishMyData
2
+ class HomeController < ApplicationController
3
+ end
4
+ end
@@ -0,0 +1,103 @@
1
+ require_dependency "publish_my_data/application_controller"
2
+
3
+ module PublishMyData
4
+ class ResourcesController < ApplicationController
5
+
6
+ respond_to :html, :ttl, :rdf, :nt, :json
7
+
8
+ # /resources
9
+ # /resources?type=[http://type-uri]&dataset=[dataset-slug]
10
+ def index
11
+ resource_criteria = Resource.all
12
+
13
+ # TODO: when we get more complicated fitlers, move this out somewhere else.
14
+ resource_criteria = add_type_filter(resource_criteria)
15
+ resource_criteria = add_dataset_filter(resource_criteria)
16
+
17
+ @resources = paginate_resources(resource_criteria)
18
+ respond_with(@resources)
19
+ end
20
+
21
+ # /resource?uri=http://foo.bar
22
+ def show
23
+ uri = params[:uri]
24
+ begin
25
+ # try to look it up
26
+ @resource = Resource.find(uri)
27
+ eager_load_labels()
28
+ respond_with(@resource)
29
+ rescue Tripod::Errors::ResourceNotFound
30
+ # if it's not there
31
+ respond_to do |format|
32
+ format.html { redirect_to uri }
33
+ # This is meant for UI browsing only, really. Just 404 for other mimes.
34
+ format.any { render :nothing => true, :status => 404, :content_type => 'text/plain' }
35
+ end
36
+ end
37
+ end
38
+
39
+ # linked data dereferencing:
40
+ # for id's just redirect to the doc.
41
+ # http://example.com/id/blah
42
+ def id
43
+ respond_to do |format|
44
+ format.any(:html, :rdf, :ttl, :nt, :json) do |format|
45
+ redirect_to "/doc/#{params[:path]}", :status=> 303
46
+ end
47
+ end
48
+ end
49
+
50
+ # http://example.com/doc/blah
51
+ def doc
52
+ uri = Resource.uri_from_host_and_doc_path(request.host, params[:path], params[:format])
53
+ @resource = Resource.find(uri)
54
+ eager_load_labels() if request.format.html?
55
+
56
+ # TODO: special views like ontology, dataset, etc?
57
+ respond_with(@resource) do |format|
58
+ format.html { render :template => 'publish_my_data/resources/show' }
59
+ end
60
+ end
61
+
62
+ # http://example.com/def/blah
63
+ def definition
64
+ uri = 'http://' + request.host + '/def/' + params[:path]
65
+ @resource = Resource.find(uri)
66
+ eager_load_labels() if request.format.html?
67
+
68
+ # TODO: special views like ontology, dataset, etc?
69
+ respond_with(@resource) do |format|
70
+ format.html { render :template => 'publish_my_data/resources/show' }
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ # TODO: move the filter management into an object
77
+ def add_type_filter(criteria)
78
+ unless params[:type_uri].blank?
79
+ @type_filter = params[:type_uri]
80
+ @type = RdfType.find(@type_filter) rescue nil
81
+ criteria.where("?uri a <#{@type_filter}>")
82
+ end
83
+ criteria
84
+ end
85
+
86
+ def add_dataset_filter(criteria)
87
+ unless params[:dataset].blank?
88
+ @dataset_filter = params[:dataset]
89
+ @dataset = Dataset.find_by_slug(@dataset_filter) rescue nil
90
+ criteria.graph(Dataset.data_graph_uri(@dataset_filter))
91
+ end
92
+ criteria
93
+ end
94
+
95
+ def eager_load_labels
96
+ @resource.eager_load_predicate_triples!
97
+ @resource.eager_load_object_triples!
98
+ end
99
+
100
+ end
101
+
102
+
103
+ end
@@ -0,0 +1,50 @@
1
+ require_dependency "publish_my_data/application_controller"
2
+
3
+ module PublishMyData
4
+ class SparqlController < ApplicationController
5
+
6
+ rescue_from PublishMyData::SparqlQueryResultTooLargeException, :with => :show_response_too_large_message
7
+ rescue_from PublishMyData::SparqlQueryExecutionException, :with => :show_sparql_execution_message
8
+
9
+ respond_to :html, :csv, :text, :nt, :ttl, :xml, :rdf, :json
10
+
11
+ def endpoint
12
+ @query_text = params[:query]
13
+
14
+ unless @query_text.blank?
15
+ @sparql_query = PublishMyData::SparqlQuery.new(@query_text, request.format.to_sym)
16
+
17
+ if @sparql_query.allow_pagination?
18
+ get_pagination_params
19
+ @sparql_query_result = @sparql_query.paginate(@page, @per_page)
20
+ @more_pages = @sparql_query.as_pagination_query(@page, @per_page, 1).count > @per_page if request.format.html?
21
+ else
22
+ @sparql_query_result = @sparql_query.execute
23
+ end
24
+
25
+ respond_with(@sparql_query_result)
26
+ end
27
+
28
+ end
29
+
30
+ private
31
+
32
+ def respond_with_error
33
+ respond_to do |format|
34
+ format.html { render 'endpoint' }
35
+ format.any { head :status => 400 }
36
+ end
37
+ end
38
+
39
+ def show_response_too_large_message(e)
40
+ @error_message = "The results for this query are too large to return."
41
+ respond_with_error
42
+ end
43
+
44
+ def show_sparql_execution_message(e)
45
+ @error_message = "There was a syntax error in your query: #{e.message}"
46
+ respond_with_error
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ module PublishMyData
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,28 @@
1
+ module PublishMyData
2
+ module ResourcesHelper
3
+
4
+ # uses eager loaded data to get the uri or label for a term
5
+ def resource_uri_or_label(term)
6
+
7
+ if term.uri?
8
+ res = @resource.get_related_resource(term, PublishMyData::Resource)
9
+ if res
10
+ link_to((res.label || res.uri.to_s), resource_path_from_uri(res.uri))
11
+ else
12
+ link_to term.to_s, resource_path_from_uri(term)
13
+ end
14
+ else
15
+ term.to_s
16
+ end
17
+ end
18
+
19
+ def resource_path_from_uri(uri)
20
+ resource = Resource.new(uri)
21
+ if resource.local?
22
+ uri.to_s
23
+ else
24
+ show_resource_path(:uri => uri.to_s)
25
+ end
26
+ end
27
+ end
28
+ end