roadforest 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/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
|