gearbox 0.1.0 → 0.1.10
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/Gemfile +5 -3
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/bin/gearbox +9 -0
- data/gearbox.gemspec +134 -0
- data/lib/gearbox.rb +124 -5
- data/lib/gearbox/attribute.rb +128 -0
- data/lib/gearbox/mixins/active_model_implementation.rb +27 -0
- data/lib/gearbox/mixins/resource.rb +20 -4
- data/lib/gearbox/mixins/semantic_accessors.rb +128 -89
- data/lib/gearbox/mixins/subject_methods.rb +88 -0
- data/lib/gearbox/rdf_collection.rb +22 -8
- data/lib/gearbox/types.rb +9 -8
- data/lib/gearbox/vocabulary.rb +149 -0
- data/lib/pry_utilities.rb +71 -0
- data/scratch/4s.rb +335 -0
- data/scratch/DEVELOPMENT_NOTES.md +85 -0
- data/scratch/actionable.md +34 -0
- data/scratch/ccrdf.html-rdfa.nq +100 -0
- data/scratch/foo.rb +17 -0
- data/scratch/index.rdf +7932 -0
- data/scratch/j2.rb +10 -0
- data/scratch/junk.rb +16 -0
- data/scratch/out.rb +67 -0
- data/spec/gearbox/attribute_spec.rb +455 -0
- data/spec/gearbox/mixins/active_model_implementation_spec.rb +18 -0
- data/spec/gearbox/mixins/ad_hoc_properties_spec.rb +44 -44
- data/spec/gearbox/mixins/resource_spec.rb +47 -8
- data/spec/gearbox/mixins/semantic_accessors_spec.rb +72 -43
- data/spec/gearbox/mixins/subject_methods_spec.rb +126 -0
- data/spec/gearbox/rdf_collection_spec.rb +28 -2
- data/spec/gearbox_spec.rb +6 -2
- data/spec/spec_helper.rb +1 -0
- metadata +150 -42
- data/Gemfile.lock +0 -138
- data/lib/examples/audience.rb +0 -24
- data/lib/examples/person.rb +0 -29
- data/lib/examples/reference.rb +0 -38
- data/lib/examples/theme.rb +0 -8
- data/spec/examples/audience_spec.rb +0 -28
- data/spec/examples/person_spec.rb +0 -45
- data/spec/examples/reference_spec.rb +0 -43
- data/spec/examples/theme_spec.rb +0 -137
data/lib/gearbox/types.rb
CHANGED
@@ -14,14 +14,15 @@ module Gearbox
|
|
14
14
|
# No autoloading here--the associations to XSD types are made by the
|
15
15
|
# classes themselves, so we need to explicitly require them or XSD types
|
16
16
|
# will show up as not found.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
require_relative 'types/integer'
|
18
|
+
require_relative 'types/boolean'
|
19
|
+
require_relative 'types/any'
|
20
|
+
require_relative 'types/string'
|
21
|
+
require_relative 'types/float'
|
22
|
+
require_relative 'types/uri'
|
23
|
+
require_relative 'types/decimal'
|
24
|
+
require_relative 'types/native'
|
25
|
+
require_relative 'types/date'
|
25
26
|
|
26
27
|
|
27
28
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Gearbox
|
6
|
+
=begin
|
7
|
+
##
|
8
|
+
# Derived from RDF::Vocabulary
|
9
|
+
# However, I have two new use cases for Gearbox::Vocabulary
|
10
|
+
# * as a single source for an ontology
|
11
|
+
# * as a base_uri in a model
|
12
|
+
|
13
|
+
## Single source Ontology
|
14
|
+
Ontologies have classes and attributes. That means there is some nesting in the vocabulary.
|
15
|
+
We have this
|
16
|
+
|
17
|
+
* /:collection/:item/:sub-collection/:item
|
18
|
+
* concatenating the existing identifier or key with a suitable base URI.
|
19
|
+
* /:collection/:id
|
20
|
+
|
21
|
+
http://www.bbc.co.uk/music/artists/a74b1b7f-71a5-4011-9441-d0b5e4122711
|
22
|
+
http://musicbrainz.org/artist/a74b1b7f-71a5-4011-9441-d0b5e4122711
|
23
|
+
|
24
|
+
<http:www.example.org/category/heavy-metal>
|
25
|
+
rdfs:label "Heavy Metal"
|
26
|
+
|
27
|
+
=end
|
28
|
+
|
29
|
+
|
30
|
+
# But with some patterns in mind from http://patterns.dataincubator.org/book/
|
31
|
+
|
32
|
+
|
33
|
+
class Vocabulary < RDF::Vocabulary
|
34
|
+
|
35
|
+
# =================
|
36
|
+
# = Class Methods =
|
37
|
+
# =================
|
38
|
+
|
39
|
+
class << self
|
40
|
+
|
41
|
+
##
|
42
|
+
# Defines a vocabulary term called `property`.
|
43
|
+
#
|
44
|
+
# @param [Symbol]
|
45
|
+
# @return [void]
|
46
|
+
def property(property, opts={})
|
47
|
+
metaclass = class << self; self; end
|
48
|
+
metaclass.send(:define_method, property) { self.lookup(property) } # class method
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Returns the URI for the term `property` in this vocabulary.
|
53
|
+
#
|
54
|
+
# @param [#to_s] property
|
55
|
+
# @return [RDF::URI]
|
56
|
+
def [](property)
|
57
|
+
RDF::URI.intern([to_s, property.to_s].join(''))
|
58
|
+
end
|
59
|
+
|
60
|
+
def lookup(property)
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
protected
|
66
|
+
def create(uri) # @private
|
67
|
+
@@uri = uri
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def inherited(subclass) # @private
|
72
|
+
@@subclasses << subclass
|
73
|
+
unless @@uri.nil?
|
74
|
+
subclass.send(:private_class_method, :new)
|
75
|
+
@@uris[subclass] = @@uri
|
76
|
+
@@uri = nil
|
77
|
+
end
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def method_missing(property, *args, &block)
|
82
|
+
if args.empty? && @@uris.has_key?(self)
|
83
|
+
self[property]
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# @param [RDF::URI, String, #to_s]
|
93
|
+
def initialize(uri)
|
94
|
+
@uri = case uri
|
95
|
+
when RDF::URI then uri.to_s
|
96
|
+
else RDF::URI.parse(uri.to_s) ? uri.to_s : nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Returns the URI for the term `property` in this vocabulary.
|
102
|
+
#
|
103
|
+
# @param [#to_s] property
|
104
|
+
# @return [URI]
|
105
|
+
def [](property)
|
106
|
+
RDF::URI.intern([to_s, property.to_s].join(''))
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Returns the base URI for this vocabulary.
|
111
|
+
#
|
112
|
+
# @return [URI]
|
113
|
+
def to_uri
|
114
|
+
RDF::URI.intern(to_s)
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Returns a string representation of this vocabulary.
|
119
|
+
#
|
120
|
+
# @return [String]
|
121
|
+
def to_s
|
122
|
+
@uri.to_s
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Returns a developer-friendly representation of this vocabulary.
|
127
|
+
#
|
128
|
+
# @return [String]
|
129
|
+
def inspect
|
130
|
+
sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, to_s)
|
131
|
+
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
|
135
|
+
def method_missing(property, *args, &block)
|
136
|
+
if args.empty?
|
137
|
+
self[property]
|
138
|
+
else
|
139
|
+
raise ArgumentError.new("wrong number of arguments (#{args.size} for 0)")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
@@subclasses = [::RDF] # @private
|
146
|
+
@@uris = {} # @private
|
147
|
+
@@uri = nil # @private
|
148
|
+
end # Vocabulary
|
149
|
+
end # RDF
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Useful for a Pry session.
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
include Gearbox
|
6
|
+
|
7
|
+
class Utilities
|
8
|
+
# Great for writing ad hoc models.
|
9
|
+
# TODO: Make this work for several sessions. (Thread it?)
|
10
|
+
def write_model(name)
|
11
|
+
raise "Directory does not exist" unless File.exist?(model_directory)
|
12
|
+
filename = File.join(model_directory, "#{name}.rb")
|
13
|
+
raise "ENV['EDITOR'] not set" unless ENV['EDITOR']
|
14
|
+
`#{ENV['EDITOR']} #{filename}`
|
15
|
+
load filename
|
16
|
+
end
|
17
|
+
alias :update_model :write_model
|
18
|
+
alias :build_model :write_model
|
19
|
+
|
20
|
+
def load_model(name)
|
21
|
+
raise "Directory does not exist" unless File.exist?(model_directory)
|
22
|
+
filename = File.join(model_directory, "#{name}.rb")
|
23
|
+
load filename
|
24
|
+
end
|
25
|
+
|
26
|
+
def model_directory
|
27
|
+
@model_directory ||= "/tmp"
|
28
|
+
end
|
29
|
+
attr_writer :model_directory
|
30
|
+
|
31
|
+
def tmp_directory
|
32
|
+
@tmp_directory ||= "/tmp"
|
33
|
+
end
|
34
|
+
attr_writer :tmp_directory
|
35
|
+
|
36
|
+
require 'fileutils'
|
37
|
+
# Great for writing descriptions without messing around with quotes and escapes and things
|
38
|
+
# TODO: Make this work for several sessions. (Thread it?)
|
39
|
+
def get_note(type="md")
|
40
|
+
contents = nil
|
41
|
+
begin
|
42
|
+
filename = File.join(tmp_directory, "#{self.object_id}.#{type}")
|
43
|
+
i = 0
|
44
|
+
while File.exist?(filename)
|
45
|
+
filename = File.join(tmp_directory, "#{self.object_id}#{i}.#{type}")
|
46
|
+
i += 1
|
47
|
+
end
|
48
|
+
raise "ENV['EDITOR'] not set" unless ENV['EDITOR']
|
49
|
+
`#{ENV['EDITOR']} #{filename}`
|
50
|
+
contents = File.read(filename)
|
51
|
+
ensure
|
52
|
+
puts "Cleaning up temp file and exiting ..."
|
53
|
+
FileUtils.rm_f(filename)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
@utilities = Utilities.new
|
60
|
+
extend Forwardable
|
61
|
+
def_delegators :@utilities,
|
62
|
+
:write_model,
|
63
|
+
:update_model,
|
64
|
+
:build_model,
|
65
|
+
:model_directory,
|
66
|
+
:model_directory=,
|
67
|
+
:tmp_directory,
|
68
|
+
:tmp_directory=,
|
69
|
+
:get_note,
|
70
|
+
:load_model
|
71
|
+
|
data/scratch/4s.rb
ADDED
@@ -0,0 +1,335 @@
|
|
1
|
+
require 'linkeddata'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
# endpoint = "http://localhost:8000/data/"
|
7
|
+
# stmt = <<-END
|
8
|
+
# INSERT DATA
|
9
|
+
# {
|
10
|
+
# <http://example.org/subject> <http://example.org/predicate> <http://example.org/object>
|
11
|
+
# }
|
12
|
+
# END
|
13
|
+
# response = RestClient.put endpoint, stmt, :content_type => "application/rdf+xml"
|
14
|
+
# graph = 'http://source.data.gov.uk/data/reference/organogram-co/2010-06-30'
|
15
|
+
# binding.pry
|
16
|
+
# response = RestClient.put endpoint + graph, stmt, :content_type => "application/rdf+xml"
|
17
|
+
|
18
|
+
def load_graph
|
19
|
+
|
20
|
+
endpoint = "http://localhost:8000/data/"
|
21
|
+
filename = File.expand_path("../index.rdf", __FILE__)
|
22
|
+
graph = 'http://source.data.gov.uk/data/reference/organogram-co/2010-06-30'
|
23
|
+
response = RestClient.put endpoint + graph, File.read(filename), :content_type => "application/rdf+xml"
|
24
|
+
# response = RestClient.put endpoint, File.read(filename), :content_type => "application/rdf+xml"
|
25
|
+
puts "Response: #{response.code}", response.to_str
|
26
|
+
end
|
27
|
+
|
28
|
+
def count_triples
|
29
|
+
endpoint = "http://localhost:8000/sparql/"
|
30
|
+
# sparql = "SELECT (COUNT(DISTINCT ?s) AS ?count) WHERE { ?s ?p ?o } LIMIT 10"
|
31
|
+
sparql = "SELECT * WHERE { ?s ?p ?o } LIMIT 10"
|
32
|
+
response = RestClient.post endpoint, :query => sparql
|
33
|
+
xml = Nokogiri::XML(response.to_str)
|
34
|
+
end
|
35
|
+
|
36
|
+
def ordered_variables
|
37
|
+
endpoint = "http://localhost:8000/sparql/"
|
38
|
+
sparql = "SELECT (COUNT(DISTINCT ?s) AS ?count) WHERE { ?s ?p ?o } LIMIT 10"
|
39
|
+
# sparql = "SELECT * WHERE { ?s ?p ?o } LIMIT 10"
|
40
|
+
response = RestClient.post endpoint, :query => sparql
|
41
|
+
xml = Nokogiri::XML(response.to_str)
|
42
|
+
found = xml.xpath("//sparql:head/sparql:variable/@name", "sparql" => "http://www.w3.org/2005/sparql-results#").map(&:value)
|
43
|
+
found
|
44
|
+
# xml.xpath("//sparql:head/sparql:variable", "sparql" => "http://www.w3.org/2005/sparql-results#").map {|e| e.attr('name')}
|
45
|
+
end
|
46
|
+
|
47
|
+
# result = ordered_variables
|
48
|
+
|
49
|
+
|
50
|
+
# Examples of SPARQL Update 1.1 for 4Store:
|
51
|
+
# http://4store.org/trac/wiki/SparqlServer
|
52
|
+
|
53
|
+
# endpoint = "http://localhost:8000/sparql/"
|
54
|
+
# You can use sparql-query to query the SPARQL server on the command line.
|
55
|
+
|
56
|
+
|
57
|
+
# Soft limit of about 1000, what is that? triples? seconds?
|
58
|
+
|
59
|
+
class NotImplemented < StandardError; end
|
60
|
+
|
61
|
+
# Geared towards interpreting whatever results we get back from a SPARQL result
|
62
|
+
class SPARQLResult
|
63
|
+
|
64
|
+
SPARQL_NAMESPACE = {'sparql' => 'http://www.w3.org/2005/sparql-results#'} unless defined?(SPARQL_NAMESPACE)
|
65
|
+
attr_reader :result_string
|
66
|
+
|
67
|
+
def initialize(result_string)
|
68
|
+
@result_string = result_string
|
69
|
+
end
|
70
|
+
|
71
|
+
def ask?
|
72
|
+
not xml.xpath('//sparql:boolean', SPARQL_NAMESPACE).empty?
|
73
|
+
end
|
74
|
+
|
75
|
+
def ask_value
|
76
|
+
return nil unless ask?
|
77
|
+
xml.xpath('//sparql:boolean', SPARQL_NAMESPACE).text == 'true'
|
78
|
+
end
|
79
|
+
|
80
|
+
def results
|
81
|
+
return ask_value if ask?
|
82
|
+
@results = Hash.new {|h, k| h[k] = []}
|
83
|
+
xml.xpath('//sparql:result', SPARQL_NAMESPACE).each do |result|
|
84
|
+
result.xpath('./sparql:binding', SPARQL_NAMESPACE).each do |variable_binding|
|
85
|
+
name = variable_binding.attr('name')
|
86
|
+
value = extract_value(variable_binding)
|
87
|
+
@results[name] << value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
@results
|
91
|
+
end
|
92
|
+
|
93
|
+
def result_table
|
94
|
+
return ask_value if ask?
|
95
|
+
keys = head_node.xpath(".//sparql:variable/@name", SPARQL_NAMESPACE).map(&:value)
|
96
|
+
values = []
|
97
|
+
xml.xpath('//sparql:result', SPARQL_NAMESPACE).each do |result|
|
98
|
+
record = []
|
99
|
+
result.xpath('./sparql:binding', SPARQL_NAMESPACE).each do |variable_binding|
|
100
|
+
value = extract_value(variable_binding)
|
101
|
+
record << value
|
102
|
+
end
|
103
|
+
values << record
|
104
|
+
end
|
105
|
+
# puts keys.inspect
|
106
|
+
# values.each {|v| puts v.inspect}
|
107
|
+
values.unshift keys
|
108
|
+
values
|
109
|
+
end
|
110
|
+
|
111
|
+
def inspect
|
112
|
+
# "SPARQLResult: #{result_string[0..50].split(/\n/)[0]}"
|
113
|
+
"SPARQLResult: #{results.keys}"
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def extract_value(variable_binding_node)
|
119
|
+
# Not Implemented: literals, sequences, indices, data types, languages
|
120
|
+
# Need to deal with bnode, uri, or literal. Ignoring all of that for now...
|
121
|
+
variable_binding_node.text
|
122
|
+
end
|
123
|
+
|
124
|
+
def head_node
|
125
|
+
@head_node ||= xml.xpath('//sparql:head', SPARQL_NAMESPACE)
|
126
|
+
end
|
127
|
+
|
128
|
+
def variable_nodes
|
129
|
+
@variable_nodes ||= head_node.xpath('//sparql::variable', SPARQL_NAMESPACE)
|
130
|
+
end
|
131
|
+
|
132
|
+
def xml
|
133
|
+
@xml ||= Nokogiri::XML(result_string)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
# response = RestClient.put endpoint + graph, File.read(filename), :content_type => "application/rdf+xml"
|
139
|
+
|
140
|
+
def exercise_sparql_result
|
141
|
+
endpoint = "http://localhost:8000/sparql/"
|
142
|
+
sparql = "SELECT * WHERE { ?s ?p ?o } LIMIT 10"
|
143
|
+
# sparql = "ASK { ?s ?p ?o }"
|
144
|
+
response = RestClient.post endpoint, :query => sparql
|
145
|
+
s = SPARQLResult.new(response)
|
146
|
+
s.results
|
147
|
+
end
|
148
|
+
|
149
|
+
# puts exercise_sparql_result.inspect
|
150
|
+
|
151
|
+
# TODO: Not dealing with the soft limit yet
|
152
|
+
|
153
|
+
# Need to figure out how to write a finder for a model...
|
154
|
+
# 1) load the data in the graph
|
155
|
+
# 2) write the query
|
156
|
+
# 3) start to figure out the different ways to construct this...
|
157
|
+
def constructing_model_sparql
|
158
|
+
end
|
159
|
+
|
160
|
+
class SPARQLEndpoint
|
161
|
+
|
162
|
+
attr_reader :base_uri
|
163
|
+
|
164
|
+
def initialize(uri="http://localhost:8000")
|
165
|
+
@base_uri = uri
|
166
|
+
end
|
167
|
+
|
168
|
+
attr_writer :select_uri
|
169
|
+
def select_uri
|
170
|
+
@select_uri ||= File.join(base_uri, 'sparql/')
|
171
|
+
end
|
172
|
+
|
173
|
+
attr_writer :update_uri
|
174
|
+
def update_uri
|
175
|
+
@update_uri ||= File.join(base_uri, 'data/')
|
176
|
+
end
|
177
|
+
|
178
|
+
def query(sparql)
|
179
|
+
response = RestClient.post select_uri, :query => sparql
|
180
|
+
SPARQLResult.new(response)
|
181
|
+
end
|
182
|
+
|
183
|
+
def queries
|
184
|
+
registered.keys
|
185
|
+
end
|
186
|
+
|
187
|
+
def memoize_query(name, sparql=nil)
|
188
|
+
return memoized[name] if memoized[name]
|
189
|
+
register_query(name, sparql)
|
190
|
+
memoized[name] ||= query(sparql)
|
191
|
+
end
|
192
|
+
alias :memoize :memoize_query
|
193
|
+
|
194
|
+
def register_query(name, sparql)
|
195
|
+
registered[name] = sparql
|
196
|
+
memoized[name] = nil
|
197
|
+
self.class.send(:define_method, name) do
|
198
|
+
memoized[name] ||= query(registered[name])
|
199
|
+
end
|
200
|
+
true
|
201
|
+
end
|
202
|
+
alias :register :register_query
|
203
|
+
|
204
|
+
def registered
|
205
|
+
@registered ||= {}
|
206
|
+
end
|
207
|
+
|
208
|
+
def memoized
|
209
|
+
@memoized ||= {}
|
210
|
+
end
|
211
|
+
|
212
|
+
def inspect
|
213
|
+
"SPARQLEndpoint: #{base_uri}"
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
# s = SPARQLEndpoint.new
|
219
|
+
# s.register('basic', "SELECT * WHERE { ?s ?p ?o } LIMIT 10")
|
220
|
+
# s.register 'predicates', 'select distinct ?predicate where {?s ?predicate ?o}'
|
221
|
+
# s.register 'notations', 'select distinct ?subject ?notations where {?subject <http://www.w3.org/2004/02/skos/core#notation}'
|
222
|
+
# s.register 'phones', 'select distinct ?phone where {?s <http://xmlns.com/foaf/0.1/phone> ?phone}'
|
223
|
+
# binding.pry
|
224
|
+
|
225
|
+
require 'fileutils'
|
226
|
+
# Note, I haven't come up with a good fallback if ENV['EDITOR'] hasn't been defined yet.
|
227
|
+
# I tried to open vim as a fallback, I ended up in non-terminal mode, had to kill processes manually.
|
228
|
+
# Will need to fork or something: http://workingwithunixprocesses.com/
|
229
|
+
def get_note(type="md")
|
230
|
+
contents = nil
|
231
|
+
begin
|
232
|
+
filename = "/tmp/#{self.object_id}.#{type}"
|
233
|
+
while File.exist?(filename)
|
234
|
+
i ||= 0
|
235
|
+
filename = "/tmp/#{self.object_id}#{i}.#{type}"
|
236
|
+
end
|
237
|
+
`#{ENV['EDITOR']} #{filename}`
|
238
|
+
contents = File.read(filename)
|
239
|
+
ensure
|
240
|
+
puts "Exiting ..."
|
241
|
+
FileUtils.rm_f(filename)
|
242
|
+
end
|
243
|
+
# contents
|
244
|
+
end
|
245
|
+
|
246
|
+
def get_model_contents(subject='http://reference.data.gov.uk/id/department/co/post/44')
|
247
|
+
s = SPARQLEndpoint.new
|
248
|
+
s.register 'model', <<-END
|
249
|
+
SELECT DISTINCT ?predicate ?value
|
250
|
+
WHERE {
|
251
|
+
{<#{subject}> ?predicate ?value}
|
252
|
+
UNION
|
253
|
+
{?value ?predicate <#{subject}>}
|
254
|
+
}
|
255
|
+
END
|
256
|
+
s.model
|
257
|
+
end
|
258
|
+
|
259
|
+
# get_model_contents
|
260
|
+
|
261
|
+
def write_model(name)
|
262
|
+
filename = "/tmp/#{name}.rb"
|
263
|
+
`#{ENV['EDITOR']} #{filename}`
|
264
|
+
load filename
|
265
|
+
end
|
266
|
+
alias :update_model :write_model
|
267
|
+
|
268
|
+
=begin
|
269
|
+
|
270
|
+
The task list says to play with more semantic models: exploratory SPARQL, SPARQL for a single model, discover data structures in other LOD. Basically, I'm trying to figure out how to be familiar with this stuff.
|
271
|
+
=end
|
272
|
+
|
273
|
+
require 'forwardable'
|
274
|
+
|
275
|
+
class Person
|
276
|
+
|
277
|
+
extend Forwardable
|
278
|
+
def_delegators :@endpoint, :white_list, :direct_attributes
|
279
|
+
|
280
|
+
attr_reader :endpoint, :id
|
281
|
+
|
282
|
+
def initialize(id="person178")
|
283
|
+
@id = id
|
284
|
+
@endpoint = SPARQLEndpoint.new
|
285
|
+
@endpoint.register :white_list, white_list_sparql
|
286
|
+
@endpoint.register :direct_attributes, direct_attributes_sparql
|
287
|
+
end
|
288
|
+
|
289
|
+
def inspect
|
290
|
+
"Person: #{URI.split(subject)[-1]}"
|
291
|
+
end
|
292
|
+
|
293
|
+
def predicate_hash
|
294
|
+
@predicate_hash ||= {
|
295
|
+
"?email" => "http://xmlns.com/foaf/0.1/mbox",
|
296
|
+
"?page" => "http://xmlns.com/foaf/0.1/page",
|
297
|
+
"?phone" => "http://xmlns.com/foaf/0.1/phone",
|
298
|
+
"?name" => "http://xmlns.com/foaf/0.1/name"
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
def base_uri
|
303
|
+
"http://source.data.gov.uk/data/reference/organogram-co/2010-10-31#"
|
304
|
+
end
|
305
|
+
|
306
|
+
def subject
|
307
|
+
"#{base_uri}#{id}"
|
308
|
+
end
|
309
|
+
|
310
|
+
def white_list_sparql
|
311
|
+
<<-END
|
312
|
+
SELECT *
|
313
|
+
#{white_list_where_clause}
|
314
|
+
END
|
315
|
+
end
|
316
|
+
|
317
|
+
def white_list_where_clause
|
318
|
+
@white_list_where_clause ||= <<-END
|
319
|
+
WHERE {
|
320
|
+
#{predicate_hash.map {|variable, predicate| "<#{subject}> <#{predicate}> #{variable}"}.join(" .\n")}
|
321
|
+
}
|
322
|
+
END
|
323
|
+
end
|
324
|
+
|
325
|
+
def direct_attributes_sparql
|
326
|
+
@direct_attributes_sparql ||=<<-END
|
327
|
+
SELECT DISTINCT ?predicate ?value
|
328
|
+
WHERE {
|
329
|
+
{<#{subject}> ?predicate ?value}
|
330
|
+
UNION
|
331
|
+
{?value ?predicate <#{subject}>}
|
332
|
+
}
|
333
|
+
END
|
334
|
+
end
|
335
|
+
end
|