roadforest 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/file-management.rb +98 -0
- data/lib/roadforest/application/dispatcher.rb +54 -0
- data/lib/roadforest/application/parameters.rb +39 -0
- data/lib/roadforest/application/path-provider.rb +18 -0
- data/lib/roadforest/application/route-adapter.rb +24 -0
- data/lib/roadforest/application/services-host.rb +10 -0
- data/lib/roadforest/application.rb +42 -0
- data/lib/roadforest/blob-model.rb +56 -0
- data/lib/roadforest/content-handling/engine.rb +113 -0
- data/lib/roadforest/content-handling/media-type.rb +222 -0
- data/lib/roadforest/content-handling/type-handlers/jsonld.rb +172 -0
- data/lib/roadforest/http/adapters/excon.rb +47 -0
- data/lib/roadforest/http/graph-response.rb +20 -0
- data/lib/roadforest/http/graph-transfer.rb +112 -0
- data/lib/roadforest/http/message.rb +91 -0
- data/lib/roadforest/model.rb +151 -0
- data/lib/roadforest/models.rb +2 -0
- data/lib/roadforest/rdf/context-fascade.rb +25 -0
- data/lib/roadforest/rdf/document.rb +23 -0
- data/lib/roadforest/rdf/focus-list.rb +19 -0
- data/lib/roadforest/rdf/focus-wrapping.rb +30 -0
- data/lib/roadforest/rdf/graph-copier.rb +16 -0
- data/lib/roadforest/rdf/graph-focus.rb +95 -0
- data/lib/roadforest/rdf/graph-reading.rb +145 -0
- data/lib/roadforest/rdf/graph-store.rb +217 -0
- data/lib/roadforest/rdf/investigation.rb +90 -0
- data/lib/roadforest/rdf/normalization.rb +150 -0
- data/lib/roadforest/rdf/parcel.rb +47 -0
- data/lib/roadforest/rdf/post-focus.rb +35 -0
- data/lib/roadforest/rdf/resource-pattern.rb +60 -0
- data/lib/roadforest/rdf/resource-query.rb +58 -0
- data/lib/roadforest/rdf/source-rigor/credence/any.rb +9 -0
- data/lib/roadforest/rdf/source-rigor/credence/none-if-role-absent.rb +19 -0
- data/lib/roadforest/rdf/source-rigor/credence/role-if-available.rb +19 -0
- data/lib/roadforest/rdf/source-rigor/credence-annealer.rb +22 -0
- data/lib/roadforest/rdf/source-rigor/credence.rb +29 -0
- data/lib/roadforest/rdf/source-rigor/http-investigator.rb +20 -0
- data/lib/roadforest/rdf/source-rigor/investigator.rb +17 -0
- data/lib/roadforest/rdf/source-rigor/null-investigator.rb +10 -0
- data/lib/roadforest/rdf/source-rigor.rb +44 -0
- data/lib/roadforest/rdf/update-focus.rb +73 -0
- data/lib/roadforest/rdf/vocabulary.rb +11 -0
- data/lib/roadforest/rdf.rb +6 -0
- data/lib/roadforest/remote-host.rb +96 -0
- data/lib/roadforest/resource/handlers.rb +43 -0
- data/lib/roadforest/resource/http/form-parsing.rb +81 -0
- data/lib/roadforest/resource/rdf/leaf-item.rb +21 -0
- data/lib/roadforest/resource/rdf/list.rb +19 -0
- data/lib/roadforest/resource/rdf/parent-item.rb +26 -0
- data/lib/roadforest/resource/rdf/read-only.rb +100 -0
- data/lib/roadforest/resource/rdf.rb +4 -0
- data/lib/roadforest/resource/role/has-children.rb +22 -0
- data/lib/roadforest/resource/role/writable.rb +43 -0
- data/lib/roadforest/server.rb +3 -0
- data/lib/roadforest/test-support/dispatcher-facade.rb +77 -0
- data/lib/roadforest/test-support/http-client.rb +151 -0
- data/lib/roadforest/test-support/matchers.rb +67 -0
- data/lib/roadforest/test-support/remote-host.rb +23 -0
- data/lib/roadforest/test-support/trace-formatter.rb +140 -0
- data/lib/roadforest/test-support.rb +2 -0
- data/lib/roadforest/utility/class-registry.rb +49 -0
- data/lib/roadforest.rb +2 -0
- data/spec/client.rb +152 -0
- data/spec/credence-annealer.rb +44 -0
- data/spec/graph-copier.rb +87 -0
- data/spec/graph-store.rb +142 -0
- data/spec/media-types.rb +14 -0
- data/spec/rdf-parcel.rb +158 -0
- data/spec/update-focus.rb +117 -0
- data/spec_support/gem_test_suite.rb +0 -0
- metadata +241 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
require 'roadforest/rdf/context-fascade'
|
3
|
+
require 'roadforest/rdf/focus-wrapping'
|
4
|
+
require 'roadforest/rdf/graph-reading'
|
5
|
+
|
6
|
+
module RoadForest::RDF
|
7
|
+
class GraphCollection
|
8
|
+
include Enumerable
|
9
|
+
end
|
10
|
+
|
11
|
+
class MultivaluedProperty < GraphCollection
|
12
|
+
attr_reader :graph, :subject, :property
|
13
|
+
def initialize(graph, subject, property)
|
14
|
+
@graph, @subject, @propery = graph, subject, property
|
15
|
+
end
|
16
|
+
|
17
|
+
def values
|
18
|
+
query_value(graph, subject, property)
|
19
|
+
end
|
20
|
+
|
21
|
+
def each
|
22
|
+
if block_given?
|
23
|
+
other
|
24
|
+
values.each do |value|
|
25
|
+
yield unwrap_value(value)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
values.each
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def add(value)
|
33
|
+
add_statement(subject, property, value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module GraphWriting
|
38
|
+
def normalize_triple(property, value, extra=nil)
|
39
|
+
if not extra.nil?
|
40
|
+
property = [property, value]
|
41
|
+
value = extra
|
42
|
+
end
|
43
|
+
return normalize_property(property), normalize_term(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def set(property, value, extra=nil)
|
47
|
+
property, value = normalize_triple(property, value, extra)
|
48
|
+
|
49
|
+
delete(property)
|
50
|
+
add(property, value)
|
51
|
+
return value
|
52
|
+
end
|
53
|
+
alias_method :[]=, :set
|
54
|
+
|
55
|
+
def add(property, value, extra=nil)
|
56
|
+
property, value = normalize_triple(property, value, extra)
|
57
|
+
|
58
|
+
target_graph.insert([subject, property, value])
|
59
|
+
return value
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete(property, extra=nil)
|
63
|
+
target_graph.delete([subject, normalize_property(property, extra), :value])
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_node(property, url=nil)
|
67
|
+
node = wrap_node(set(property, normalize_resource(url) || RDF::Node.new))
|
68
|
+
yield node if block_given?
|
69
|
+
node
|
70
|
+
end
|
71
|
+
alias node_at set_node
|
72
|
+
|
73
|
+
def add_node(property, url=nil)
|
74
|
+
node = wrap_node(add(property, normalize_resource(url) || RDF::Node.new))
|
75
|
+
yield node if block_given?
|
76
|
+
node
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_list(property, extra=nil)
|
80
|
+
list = ::RDF::List.new(nil, target_graph)
|
81
|
+
target_graph.insert([subject, normalize_property(property, extra), list.subject])
|
82
|
+
yield list if block_given?
|
83
|
+
return list
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class GraphFocus < GraphReading
|
88
|
+
include GraphWriting
|
89
|
+
|
90
|
+
def target_graph
|
91
|
+
graph
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'roadforest/rdf/focus-list'
|
2
|
+
require 'roadforest/rdf/normalization'
|
3
|
+
require 'roadforest/rdf/focus-wrapping'
|
4
|
+
require 'roadforest/rdf/resource-query'
|
5
|
+
|
6
|
+
module RoadForest::RDF
|
7
|
+
class GraphReading
|
8
|
+
include Normalization
|
9
|
+
include FocusWrapping
|
10
|
+
|
11
|
+
attr_accessor :graph, :subject, :root_url, :source_rigor
|
12
|
+
alias rdf subject
|
13
|
+
|
14
|
+
def initialize(subject = nil, graph = nil, rigor = nil)
|
15
|
+
@graph = nil
|
16
|
+
@subject = nil
|
17
|
+
@root_url = nil
|
18
|
+
@source_rigor = nil
|
19
|
+
self.subject = subject unless subject.nil?
|
20
|
+
self.graph = graph unless graph.nil?
|
21
|
+
self.source_rigor = rigor unless rigor.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
"#<#{self.class.name}:0x#{"%x" % object_id} (#{subject.to_s}) #{forward_properties.inspect}>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def dup
|
29
|
+
other = self.class.new
|
30
|
+
other.graph = graph
|
31
|
+
other.subject = subject
|
32
|
+
other.root_url = root_url
|
33
|
+
other.source_rigor = source_rigor
|
34
|
+
other
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_context
|
38
|
+
normalize_context(subject)
|
39
|
+
end
|
40
|
+
|
41
|
+
def root_url=(*value) #XXX curies?
|
42
|
+
@root_url = normalize_resource(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def subject=(*value)
|
46
|
+
@subject = normalize_resource(value)
|
47
|
+
case @subject
|
48
|
+
when ::RDF::URI
|
49
|
+
@root_url ||= @subject
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_query
|
54
|
+
ResourceQuery.new([], {}) do |query|
|
55
|
+
query.subject_context = @root_url
|
56
|
+
query.source_rigor = @source_rigor
|
57
|
+
yield query
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def forward_properties
|
62
|
+
query_properties( build_query{|q| q.pattern([ normalize_resource(subject), :property, :value ])} )
|
63
|
+
end
|
64
|
+
|
65
|
+
def reverse_properties
|
66
|
+
query_properties( build_query{|q| q.pattern([ :value, :property, normalize_resource(subject)])} )
|
67
|
+
end
|
68
|
+
|
69
|
+
def get(prefix, property = nil)
|
70
|
+
return single_or_enum(forward_query_value( prefix, property))
|
71
|
+
end
|
72
|
+
alias_method :[], :get
|
73
|
+
|
74
|
+
def first(prefix, property = nil)
|
75
|
+
return forward_query_value( prefix, property ).first
|
76
|
+
end
|
77
|
+
|
78
|
+
def all(prefix, property = nil)
|
79
|
+
return forward_query_value( prefix, property )
|
80
|
+
end
|
81
|
+
|
82
|
+
#XXX Maybe rev should return a decorator, so it looks like:
|
83
|
+
#focus.rev.get(...) or focus.rev.all(...)
|
84
|
+
def rev(prefix, property = nil)
|
85
|
+
return single_or_enum(reverse_query_value( prefix, property))
|
86
|
+
end
|
87
|
+
|
88
|
+
def rev_first(prefix, property = nil)
|
89
|
+
return reverse_query_value(prefix, property).first
|
90
|
+
end
|
91
|
+
|
92
|
+
def rev_all(prefix, property = nil)
|
93
|
+
return reverse_query_value(prefix, property)
|
94
|
+
end
|
95
|
+
|
96
|
+
def as_list
|
97
|
+
graph = ContextFascade.new(@graph, @root_url, @source_rigor)
|
98
|
+
list = FocusList.new(@subject, graph)
|
99
|
+
list.base_node = self
|
100
|
+
list.source_rigor = source_rigor
|
101
|
+
list
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
|
106
|
+
def reverse_query_value(prefix, property=nil)
|
107
|
+
query_value(build_query{|q|
|
108
|
+
q.pattern([ :value, normalize_property(prefix, property), normalize_resource(subject)])
|
109
|
+
})
|
110
|
+
end
|
111
|
+
|
112
|
+
def forward_query_value(prefix, property=nil)
|
113
|
+
query_value(build_query{|q|
|
114
|
+
q.pattern([ normalize_resource(subject), normalize_property(prefix, property), :value])
|
115
|
+
})
|
116
|
+
end
|
117
|
+
|
118
|
+
def query_value(query)
|
119
|
+
solutions = query.execute(graph)
|
120
|
+
solutions.map do |solution|
|
121
|
+
unwrap_value(solution.value)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
def single_or_enum(values)
|
125
|
+
case values.length
|
126
|
+
when 0
|
127
|
+
return nil
|
128
|
+
when 1
|
129
|
+
return values.first
|
130
|
+
else
|
131
|
+
return values.enum_for(:each)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def query_properties(query)
|
136
|
+
Hash[query.execute(graph).map do |solution|
|
137
|
+
prop = solution.property
|
138
|
+
if qname = prop.qname
|
139
|
+
prop = qname
|
140
|
+
end
|
141
|
+
[prop, solution.value]
|
142
|
+
end]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
require 'roadforest/rdf/graph-focus'
|
3
|
+
require 'roadforest/rdf/vocabulary'
|
4
|
+
require 'roadforest/rdf/normalization'
|
5
|
+
|
6
|
+
require 'roadforest/rdf/resource-query'
|
7
|
+
require 'roadforest/rdf/resource-pattern'
|
8
|
+
|
9
|
+
module RoadForest::RDF
|
10
|
+
class GraphStore
|
11
|
+
include Normalization
|
12
|
+
|
13
|
+
#The interface supported by ::RDF::Graph
|
14
|
+
include ::RDF::Countable
|
15
|
+
include ::RDF::Durable
|
16
|
+
include ::RDF::Enumerable
|
17
|
+
include ::RDF::Mutable
|
18
|
+
include ::RDF::Queryable
|
19
|
+
include ::RDF::Resource
|
20
|
+
|
21
|
+
attr_reader :repository, :current_impulse, :local_context_node
|
22
|
+
attr_accessor :debug_io
|
23
|
+
|
24
|
+
def initialize(repo = nil)
|
25
|
+
@repository = repo || RDF::Repository.new
|
26
|
+
@local_context_node = RDF::Node.new(:local)
|
27
|
+
@debug_io = nil
|
28
|
+
next_impulse
|
29
|
+
yield self if block_given?
|
30
|
+
end
|
31
|
+
|
32
|
+
def next_impulse
|
33
|
+
return if !@current_impulse.nil? and raw_quiet_impulse?
|
34
|
+
#mark ended?
|
35
|
+
#chain impulses?
|
36
|
+
@current_impulse = RDF::Node.new
|
37
|
+
repository.insert(normalize_statement(@current_impulse, [:rdf, 'type'], [:rf, 'Impulse'], nil))
|
38
|
+
repository.insert(normalize_statement(@current_impulse, [:rf, 'begunAt'], Time.now, nil))
|
39
|
+
end
|
40
|
+
|
41
|
+
def quiet_impulse?
|
42
|
+
raw_quiet_impulse?
|
43
|
+
end
|
44
|
+
|
45
|
+
def raw_quiet_impulse?
|
46
|
+
repository.query([nil, nil, @current_impulse, false]).to_a.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
#repo cleanup - expired graphs
|
50
|
+
|
51
|
+
def reader_for(content_type, repository)
|
52
|
+
RDF::Reader.for(content_type)
|
53
|
+
end
|
54
|
+
|
55
|
+
def debug(message)
|
56
|
+
return if @debug_io.nil?
|
57
|
+
@debug_io.puts(message)
|
58
|
+
end
|
59
|
+
|
60
|
+
def repository_dump(format = :turtle)
|
61
|
+
repository.dump(format)
|
62
|
+
end
|
63
|
+
alias graph_dump repository_dump
|
64
|
+
|
65
|
+
def delete_statements(pattern)
|
66
|
+
repository.delete(pattern)
|
67
|
+
end
|
68
|
+
|
69
|
+
def named_graph(context)
|
70
|
+
::RDF::Graph.new(context, :data => repository)
|
71
|
+
end
|
72
|
+
|
73
|
+
def named_list(context, values = nil)
|
74
|
+
::RDF::List.new(nil, named_graph(context), values)
|
75
|
+
end
|
76
|
+
|
77
|
+
def create_list(values = nil)
|
78
|
+
named_list(local_context_node, values)
|
79
|
+
end
|
80
|
+
|
81
|
+
def insert_document(document)
|
82
|
+
#puts; puts "#{__FILE__}:#{__LINE__} => #{(document).inspect}"
|
83
|
+
#puts document.body_string
|
84
|
+
reader = RDF::Reader.for(:content_type => document.content_type) do
|
85
|
+
sample = document.body.read(1000)
|
86
|
+
document.body.rewind
|
87
|
+
sample
|
88
|
+
end.new(document.body, :base_uri => document.root_url) #consider :processor_graph
|
89
|
+
insert_reader(document.source, reader)
|
90
|
+
end
|
91
|
+
|
92
|
+
def insert_reader(context, reader)
|
93
|
+
#puts; puts "#{__FILE__}:#{__LINE__} => #{(context).inspect}"
|
94
|
+
context = normalize_context(context)
|
95
|
+
delete_statements(:context => context)
|
96
|
+
reader.each_statement do |statement|
|
97
|
+
statement.context = context
|
98
|
+
record_statement(statement)
|
99
|
+
end
|
100
|
+
#puts; puts "#{__FILE__}:#{__LINE__} => \n#{(graph_dump(:nquads))}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def insert_graph(context, graph)
|
104
|
+
context = normalize_context(context)
|
105
|
+
delete_statements(:context => context)
|
106
|
+
graph.each_statement do |statement|
|
107
|
+
statement.context = context
|
108
|
+
record_statement(statement)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_statement(*args)
|
113
|
+
case args.length
|
114
|
+
when 1
|
115
|
+
subject, predicate, object, context = *args.first
|
116
|
+
when 2
|
117
|
+
triple, context = *args
|
118
|
+
subject, predicate, object = *triple
|
119
|
+
when 3
|
120
|
+
subject, predicate, object = *args
|
121
|
+
context = nil
|
122
|
+
when 4
|
123
|
+
subject, predicate, object, context = *args
|
124
|
+
else
|
125
|
+
raise ArgumentError, "insert_statement needs some variation of subject, predicate, object, [context]"
|
126
|
+
end
|
127
|
+
context ||= local_context_node
|
128
|
+
|
129
|
+
record_statement(normalize_statement(subject, predicate, object, context))
|
130
|
+
end
|
131
|
+
|
132
|
+
def insert_statement(statement)
|
133
|
+
repository.insert(statement)
|
134
|
+
|
135
|
+
repository.delete([statement.context, expand_curie([:rf, "impulse"]), nil])
|
136
|
+
repository.insert(normalize_statement(statement.context, [:rf, "impulse"], current_impulse, nil))
|
137
|
+
end
|
138
|
+
alias record_statement insert_statement
|
139
|
+
|
140
|
+
def delete_statement(statement)
|
141
|
+
repository.query(statement) do |statement|
|
142
|
+
next if statement.context.nil?
|
143
|
+
repository.delete(statement)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def replace(original, statement)
|
148
|
+
unless original == statement
|
149
|
+
repository.delete(original)
|
150
|
+
repository.insert(statement)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def each_statement(context=nil, &block)
|
155
|
+
query = {}
|
156
|
+
unless context.nil?
|
157
|
+
query[:context] = context
|
158
|
+
end
|
159
|
+
|
160
|
+
@repository.query(query) do |statement|
|
161
|
+
yield statement
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def durable?
|
166
|
+
@repository.durable?
|
167
|
+
end
|
168
|
+
|
169
|
+
#XXX Credence? Default context?
|
170
|
+
def each(&block)
|
171
|
+
if @repository.respond_to?(:query)
|
172
|
+
@repository.query(:context => false, &block)
|
173
|
+
elsif @repository.respond_to?(:each)
|
174
|
+
@repository.each(&block)
|
175
|
+
else
|
176
|
+
@repository.to_a.each(&block)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
#XXX Needed, maybe, if we need to handle constant patterns
|
181
|
+
#def include?(statement)
|
182
|
+
#end
|
183
|
+
|
184
|
+
def context_variable
|
185
|
+
@context_variable ||= RDF::Query::Variable.new(:context)
|
186
|
+
end
|
187
|
+
|
188
|
+
def query_execute(query, &block)
|
189
|
+
#XXX Weird edge case of GM getting queried with a vanilla RDF::Query...
|
190
|
+
#needs tests, thought
|
191
|
+
query = ResourceQuery.from(query)
|
192
|
+
query.execute(self).filter do |solution|
|
193
|
+
solution.respond_to?(:context) and not solution.context.nil?
|
194
|
+
end.each(&block)
|
195
|
+
end
|
196
|
+
|
197
|
+
def query_pattern(pattern, &block)
|
198
|
+
case pattern
|
199
|
+
when ResourcePattern
|
200
|
+
pattern.execute(@repository, {}, :context_roles => {:local => local_context_node}) do |statement|
|
201
|
+
next if statement.context.nil?
|
202
|
+
yield statement if block_given?
|
203
|
+
end
|
204
|
+
else
|
205
|
+
pattern.execute(@repository, {}) do |statement|
|
206
|
+
next if statement.context.nil?
|
207
|
+
yield statement if block_given?
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def unnamed_graph
|
213
|
+
::RDF::Graph.new(nil, :data => @repository)
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'roadforest/rdf'
|
2
|
+
|
3
|
+
module RoadForest::RDF
|
4
|
+
class Investigation
|
5
|
+
attr_accessor :context_roles, :queryable, :results, :source_rigor
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@results = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def http_client
|
12
|
+
queryable.http_client
|
13
|
+
end
|
14
|
+
|
15
|
+
def found_results?
|
16
|
+
!@results.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
def investigators
|
20
|
+
source_rigor.investigators
|
21
|
+
end
|
22
|
+
|
23
|
+
def credence_policies
|
24
|
+
source_rigor.credence_policies
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_request(method, url, graph=nil)
|
28
|
+
source_rigor.graph_transfer.make_request(method, url, graph)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def insert_graph(context, graph)
|
33
|
+
queryable.insert_graph(context, graph)
|
34
|
+
end
|
35
|
+
|
36
|
+
def result
|
37
|
+
investigators.each do |investigator|
|
38
|
+
self.results = []
|
39
|
+
yield(results)
|
40
|
+
|
41
|
+
contexts = result_contexts
|
42
|
+
|
43
|
+
catch :not_credible do
|
44
|
+
credence_policies.each do |policy|
|
45
|
+
contexts = policy.credible(contexts, self)
|
46
|
+
if contexts.empty?
|
47
|
+
throw :not_credible
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return results_for_context(contexts.first)
|
51
|
+
end
|
52
|
+
|
53
|
+
self.results = nil
|
54
|
+
investigator.pursue(self)
|
55
|
+
|
56
|
+
if found_results?
|
57
|
+
return results
|
58
|
+
end
|
59
|
+
end
|
60
|
+
raise NoCredibleResults
|
61
|
+
end
|
62
|
+
|
63
|
+
def result_contexts
|
64
|
+
(results.map(&:context) +
|
65
|
+
context_roles.values.find_all do |context|
|
66
|
+
not context_metadata(context).empty?
|
67
|
+
end).uniq
|
68
|
+
end
|
69
|
+
|
70
|
+
def context_metadata(context)
|
71
|
+
query = RDF::Query.new do |query|
|
72
|
+
query.pattern [context, :property, :value]
|
73
|
+
end
|
74
|
+
query.execute(queryable.unnamed_graph).select(:property, :value)
|
75
|
+
end
|
76
|
+
|
77
|
+
def results_for_context(context)
|
78
|
+
results.find_all{|item| item.context == context}
|
79
|
+
end
|
80
|
+
|
81
|
+
#XXX Do we need the nil result if context_metadata is empty?
|
82
|
+
def empty_for_context(context)
|
83
|
+
if context_metadata(context).empty? #We've never checked
|
84
|
+
nil
|
85
|
+
else
|
86
|
+
empty_result
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
|
3
|
+
module RoadForest::RDF
|
4
|
+
module Normalization
|
5
|
+
Vocabs = {}
|
6
|
+
Vocabs["rdf"] = RDF
|
7
|
+
|
8
|
+
def normalize_statement(subject, predicate, object, context)
|
9
|
+
subject = normalize_resource(subject) || RDF::Node.new
|
10
|
+
predicate = normalize_uri(predicate)
|
11
|
+
object = normalize_term(object) || RDF::Node.new
|
12
|
+
context = normalize_resource(context)
|
13
|
+
|
14
|
+
RDF::Statement.new(subject, predicate, object, :context => context)
|
15
|
+
end
|
16
|
+
|
17
|
+
def normalize_tuple(tuple)
|
18
|
+
subject, predicate, object, context = *tuple
|
19
|
+
[ normalize_resource(subject) || RDF::Node.new, normalize_uri(predicate), normalize_term(object) || RDF::Node.new, normalize_resource(context) ]
|
20
|
+
end
|
21
|
+
|
22
|
+
def normalize_resource(from)
|
23
|
+
from = expand_curie(from)
|
24
|
+
case from
|
25
|
+
when nil
|
26
|
+
when RDF::Resource
|
27
|
+
when /^_:/
|
28
|
+
from = RDF::Resource.new(from)
|
29
|
+
when String, RDF::URI, Addressable::URI
|
30
|
+
from = interned_uri(from)
|
31
|
+
when Symbol
|
32
|
+
from = RDF::Node.new(from)
|
33
|
+
else
|
34
|
+
from = RDF::Resource.new(from)
|
35
|
+
end
|
36
|
+
return from
|
37
|
+
end
|
38
|
+
|
39
|
+
def normalize_context(from)
|
40
|
+
case from
|
41
|
+
when Array
|
42
|
+
from = expand_curie(from)
|
43
|
+
when RDF::URI, Addressable::URI, String
|
44
|
+
from = uri(from)
|
45
|
+
else
|
46
|
+
return nil
|
47
|
+
end
|
48
|
+
from.fragment = nil
|
49
|
+
return RDF::URI.intern(from.to_s)
|
50
|
+
end
|
51
|
+
|
52
|
+
def normalize_uri(from)
|
53
|
+
from = expand_curie(from)
|
54
|
+
case from
|
55
|
+
when nil
|
56
|
+
when RDF::URI
|
57
|
+
else
|
58
|
+
from = interned_uri(from)
|
59
|
+
end
|
60
|
+
return from
|
61
|
+
end
|
62
|
+
|
63
|
+
def normalize_term(object)
|
64
|
+
if Array === object
|
65
|
+
RDF::Resource.new(expand_curie(object))
|
66
|
+
else
|
67
|
+
object
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def literal(object)
|
72
|
+
RDF::Literal.new(object)
|
73
|
+
end
|
74
|
+
|
75
|
+
def expand_curie_pair(prefix, property)
|
76
|
+
vocab = Vocabs.fetch(prefix) do
|
77
|
+
vocab = RDF::Vocabulary.find do |vocab|
|
78
|
+
vocab.__prefix__.to_s == prefix
|
79
|
+
end
|
80
|
+
#p k => vocab #ok
|
81
|
+
if vocab.nil?
|
82
|
+
raise "Don't know a vocabulary for prefix #{prefix.inspect} in CURIE #{prefix}:#{property}"
|
83
|
+
end
|
84
|
+
Vocabs[prefix] = vocab
|
85
|
+
vocab
|
86
|
+
end
|
87
|
+
vocab[property]
|
88
|
+
end
|
89
|
+
|
90
|
+
def expand_curie(from)
|
91
|
+
case from
|
92
|
+
when Array
|
93
|
+
case from.length
|
94
|
+
when 2
|
95
|
+
prefix, property = *from
|
96
|
+
return interned_uri(expand_curie_pair(prefix.to_s, property.to_s))
|
97
|
+
when 1
|
98
|
+
return expand_curie(from.first)
|
99
|
+
else
|
100
|
+
return from
|
101
|
+
end
|
102
|
+
else
|
103
|
+
return from
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def normalize_property(prefix, property = nil)
|
108
|
+
if property.nil?
|
109
|
+
property = prefix
|
110
|
+
|
111
|
+
case property
|
112
|
+
when Array
|
113
|
+
normalize_property(*property)
|
114
|
+
when String
|
115
|
+
RDF::URI.intern(property)
|
116
|
+
else
|
117
|
+
property
|
118
|
+
end
|
119
|
+
else
|
120
|
+
expand_curie([prefix, property])
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def root_url
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def interned_uri(value)
|
129
|
+
|
130
|
+
RDF::URI.intern(uri(value))
|
131
|
+
end
|
132
|
+
|
133
|
+
def uri(value)
|
134
|
+
if root_url
|
135
|
+
value = root_url.join(value)
|
136
|
+
else
|
137
|
+
value = RDF::URI.new(value)
|
138
|
+
end
|
139
|
+
|
140
|
+
if !value.query.nil? and value.query.empty?
|
141
|
+
value.query = nil
|
142
|
+
end
|
143
|
+
value.validate!
|
144
|
+
value.canonicalize!
|
145
|
+
|
146
|
+
value
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|