roadforest 0.0.1 → 0.0.2

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.
Files changed (40) hide show
  1. data/examples/file-management.rb +2 -1
  2. data/lib/roadforest/application/dispatcher.rb +12 -2
  3. data/lib/roadforest/application/services-host.rb +1 -1
  4. data/lib/roadforest/application.rb +12 -5
  5. data/lib/roadforest/blob-model.rb +7 -1
  6. data/lib/roadforest/content-handling/engine.rb +4 -1
  7. data/lib/roadforest/content-handling/type-handlers/jsonld.rb +25 -17
  8. data/lib/roadforest/http/adapters/excon.rb +1 -1
  9. data/lib/roadforest/http/graph-response.rb +18 -4
  10. data/lib/roadforest/http/graph-transfer.rb +52 -8
  11. data/lib/roadforest/http/message.rb +10 -1
  12. data/lib/roadforest/model.rb +17 -4
  13. data/lib/roadforest/rdf/context-fascade.rb +80 -5
  14. data/lib/roadforest/rdf/etagging.rb +53 -0
  15. data/lib/roadforest/rdf/focus-list.rb +47 -5
  16. data/lib/roadforest/rdf/graph-copier.rb +4 -5
  17. data/lib/roadforest/rdf/graph-focus.rb +38 -14
  18. data/lib/roadforest/rdf/graph-reading.rb +102 -47
  19. data/lib/roadforest/rdf/graph-store.rb +12 -8
  20. data/lib/roadforest/rdf/investigation.rb +0 -1
  21. data/lib/roadforest/rdf/normalization.rb +37 -4
  22. data/lib/roadforest/rdf/resource-pattern.rb +1 -0
  23. data/lib/roadforest/rdf/source-rigor/credence-annealer.rb +2 -0
  24. data/lib/roadforest/rdf/source-rigor/http-investigator.rb +12 -14
  25. data/lib/roadforest/rdf/update-focus.rb +7 -62
  26. data/lib/roadforest/remote-host.rb +21 -10
  27. data/lib/roadforest/resource/rdf/read-only.rb +4 -0
  28. data/lib/roadforest/server.rb +22 -0
  29. data/lib/roadforest/test-support/dispatcher-facade.rb +1 -1
  30. data/lib/roadforest/test-support/http-client.rb +8 -0
  31. data/spec/client.rb +20 -2
  32. data/spec/credence-annealer.rb +1 -1
  33. data/spec/excon-adapater.rb +30 -0
  34. data/spec/focus-list.rb +34 -0
  35. data/spec/form-parsing.rb +1 -0
  36. data/spec/full-integration.rb +193 -0
  37. data/spec/rdf-normalization.rb +17 -0
  38. data/spec/update-focus.rb +37 -0
  39. metadata +22 -17
  40. data/lib/roadforest/rdf/focus-wrapping.rb +0 -30
@@ -1,19 +1,61 @@
1
- require 'roadforest/rdf/focus-wrapping'
2
- require 'roadforest/rdf/normalization'
1
+ require 'rdf'
2
+
3
+ require 'roadforest/rdf/resource-query'
4
+ require 'roadforest/rdf/resource-pattern'
5
+
3
6
  module RoadForest::RDF
4
7
  class FocusList < ::RDF::List
5
- include Normalization
6
8
 
7
- attr_accessor :root_url, :base_node, :source_rigor
9
+ attr_accessor :root_url, :base_node
10
+
11
+ #XXX Can delete?
12
+ def source_rigor
13
+ graph.rigor
14
+ end
15
+
16
+ alias car first
17
+ alias cdr rest
8
18
 
9
19
  def first
10
- base_node.unwrap_value(super)
20
+ at(0)
11
21
  end
12
22
 
13
23
  def each
24
+ return to_enum unless block_given?
14
25
  super do |value|
15
26
  yield base_node.unwrap_value(value)
16
27
  end
17
28
  end
29
+
30
+ def append(value)
31
+ value = case value
32
+ when nil then RDF.nil
33
+ when RDF::Value then value
34
+ when Array then RDF::List.new(nil, graph, value)
35
+ else value
36
+ end
37
+
38
+ if empty?
39
+ new_subject = subject
40
+ graph.insert([new_subject, RDF.type, RDF.List])
41
+ else
42
+ old_subject, new_subject = last_subject, RDF::Node.new
43
+ graph.delete([old_subject, RDF.rest, RDF.nil])
44
+ graph.insert([old_subject, RDF.rest, new_subject])
45
+ end
46
+
47
+ graph.insert([new_subject, RDF.first, value.is_a?(RDF::List) ? value.subject : value])
48
+ graph.insert([new_subject, RDF.rest, RDF.nil])
49
+
50
+ self
51
+ end
52
+ alias << append
53
+
54
+ def append_node(subject=nil)
55
+ base_node.create_node(subject) do |node|
56
+ append(node.subject)
57
+ yield node if block_given?
58
+ end
59
+ end
18
60
  end
19
61
  end
@@ -3,13 +3,12 @@ require 'roadforest/rdf/graph-focus'
3
3
 
4
4
  module RoadForest
5
5
  module RDF
6
- class GraphCopier < GraphFocus
7
- attr_accessor :source_graph, :subject
8
-
9
- alias target_graph graph
6
+ class GraphCopier < GraphWriting
7
+ attr_accessor :target_graph
10
8
 
11
9
  def initialize
12
- @graph = ::RDF::Graph.new
10
+ super
11
+ @target_graph = ::RDF::Graph.new
13
12
  end
14
13
  end
15
14
  end
@@ -1,6 +1,5 @@
1
1
  require 'rdf'
2
2
  require 'roadforest/rdf/context-fascade'
3
- require 'roadforest/rdf/focus-wrapping'
4
3
  require 'roadforest/rdf/graph-reading'
5
4
 
6
5
  module RoadForest::RDF
@@ -34,7 +33,7 @@ module RoadForest::RDF
34
33
  end
35
34
  end
36
35
 
37
- module GraphWriting
36
+ class GraphWriting < GraphReading
38
37
  def normalize_triple(property, value, extra=nil)
39
38
  if not extra.nil?
40
39
  property = [property, value]
@@ -55,41 +54,66 @@ module RoadForest::RDF
55
54
  def add(property, value, extra=nil)
56
55
  property, value = normalize_triple(property, value, extra)
57
56
 
58
- target_graph.insert([subject, property, value])
57
+ access_manager.insert([subject, property, value])
59
58
  return value
60
59
  end
61
60
 
62
61
  def delete(property, extra=nil)
63
- target_graph.delete([subject, normalize_property(property, extra), :value])
62
+ access_manager.delete(:subject => subject, :predicate => normalize_property(property, extra))
63
+ end
64
+
65
+ def find_or_add(property, url=nil, &block)
66
+ value = first(property)
67
+ if value.nil?
68
+ value = add_node(property, url, &block)
69
+ else
70
+ yield value if block_given?
71
+ end
72
+ value
64
73
  end
65
74
 
66
75
  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
76
+ create_node(url) do |node|
77
+ set(property, node.subject)
78
+ yield node if block_given?
79
+ end
70
80
  end
71
81
  alias node_at set_node
72
82
 
73
83
  def add_node(property, url=nil)
74
- node = wrap_node(add(property, normalize_resource(url) || RDF::Node.new))
84
+ create_node(url) do |node|
85
+ add(property, node.subject)
86
+ yield node if block_given?
87
+ end
88
+ end
89
+
90
+ #Create a subject node without relationship to the rest of the graph
91
+ def create_node(url=nil)
92
+ node = wrap_node(normalize_resource(url))
75
93
  yield node if block_given?
76
94
  node
77
95
  end
78
96
 
79
97
  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])
98
+ list = FocusList.new(nil, access_manager)
99
+ access_manager.insert([subject, normalize_property(property, extra), list.subject])
82
100
  yield list if block_given?
83
101
  return list
84
102
  end
85
103
  end
86
104
 
87
- class GraphFocus < GraphReading
88
- include GraphWriting
89
-
105
+ class GraphFocus < GraphWriting
90
106
  def target_graph
91
- graph
107
+ @access_manager.target_graph
108
+ end
109
+
110
+ def source_graph=(graph)
111
+ @access_manager.source_graph = graph
112
+ @access_manager.target_graph = graph
92
113
  end
114
+ alias target_graph= source_graph=
93
115
 
116
+ alias graph source_graph
117
+ alias graph= source_graph=
94
118
  end
95
119
  end
@@ -1,69 +1,113 @@
1
1
  require 'roadforest/rdf/focus-list'
2
2
  require 'roadforest/rdf/normalization'
3
- require 'roadforest/rdf/focus-wrapping'
4
3
  require 'roadforest/rdf/resource-query'
4
+ require 'rdf/model/node'
5
+ require 'roadforest/rdf'
6
+
5
7
 
6
8
  module RoadForest::RDF
7
9
  class GraphReading
10
+ #XXX Any changes to this class heirarchy or to ContextFascade should start
11
+ #with a refactor like:
12
+ # Reduce this to the single-node API ([] []=)
13
+ # Change the ContextFascade into a family of classes (RO, RW, Update)
8
14
  include Normalization
9
- include FocusWrapping
10
15
 
11
- attr_accessor :graph, :subject, :root_url, :source_rigor
16
+ #attr_accessor :source_graph, :target_graph, :subject, :root_url,
17
+ #:source_rigor
18
+
19
+ attr_accessor :subject, :access_manager
20
+
12
21
  alias rdf subject
13
22
 
14
23
  def initialize(subject = nil, graph = nil, rigor = nil)
15
- @graph = nil
16
- @subject = nil
17
- @root_url = nil
18
- @source_rigor = nil
24
+ @access_manager = ContextFascade.new
25
+ @access_manager.rigor = rigor
26
+ self.target_graph = graph
27
+ self.source_graph = graph
28
+
19
29
  self.subject = subject unless subject.nil?
20
- self.graph = graph unless graph.nil?
21
- self.source_rigor = rigor unless rigor.nil?
22
30
  end
23
31
 
24
- def inspect
25
- "#<#{self.class.name}:0x#{"%x" % object_id} (#{subject.to_s}) #{forward_properties.inspect}>"
32
+ def source_graph
33
+ @access_manager.source_graph
26
34
  end
27
35
 
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
36
+ def source_graph=(graph)
37
+ @access_manager.source_graph = graph
35
38
  end
36
39
 
37
- def to_context
38
- normalize_context(subject)
40
+ def target_graph
41
+ nil
39
42
  end
40
43
 
41
- def root_url=(*value) #XXX curies?
42
- @root_url = normalize_resource(value)
44
+ def target_graph=(graph)
45
+ @access_manager.target_graph = nil
46
+ end
47
+
48
+ def source_rigor
49
+ @access_manager.rigor
50
+ end
51
+
52
+ def source_rigor=(rigor)
53
+ @access_manager.rigor = rigor
54
+ end
55
+
56
+ def root_url
57
+ @access_manager.resource
43
58
  end
44
59
 
45
60
  def subject=(*value)
46
61
  @subject = normalize_resource(value)
47
62
  case @subject
48
63
  when ::RDF::URI
49
- @root_url ||= @subject
64
+ @access_manager.resource = @subject
50
65
  end
51
66
  end
52
67
 
53
- def build_query
54
- ResourceQuery.new([], {}) do |query|
55
- query.subject_context = @root_url
56
- query.source_rigor = @source_rigor
57
- yield query
68
+ def inspect
69
+ "#<#{self.class.name}:0x#{"%x" % object_id} (#{subject.to_s}) #{forward_properties.inspect}>"
70
+ end
71
+ alias to_s inspect
72
+
73
+ def dup
74
+ other = self.class.new
75
+ other.access_manager = access_manager.dup
76
+ other.subject = subject
77
+ other
78
+ end
79
+
80
+ def wrap_node(value)
81
+ next_step = dup
82
+ if ::RDF::Node === value
83
+ next_step.root_url = self.root_url
84
+ else
85
+ next_step.root_url = normalize_context(value)
58
86
  end
87
+ next_step.subject = value
88
+ next_step
59
89
  end
60
90
 
61
- def forward_properties
62
- query_properties( build_query{|q| q.pattern([ normalize_resource(subject), :property, :value ])} )
91
+ def unwrap_value(value)
92
+ return nil if value.nil?
93
+ if value.respond_to? :object
94
+ value.object
95
+ else
96
+ wrap_node(value)
97
+ end
63
98
  end
64
99
 
65
- def reverse_properties
66
- query_properties( build_query{|q| q.pattern([ :value, :property, normalize_resource(subject)])} )
100
+ def to_context
101
+ normalize_context(subject)
102
+ end
103
+
104
+ def root_url=(*value) #XXX curies?
105
+ @root_url = normalize_resource(value)
106
+ end
107
+
108
+ #XXX This probably wants to be handled completely in the MediaType handler
109
+ def relevant_prefixes
110
+ relevant_prefixes_for_graph(source_graph)
67
111
  end
68
112
 
69
113
  def get(prefix, property = nil)
@@ -94,15 +138,32 @@ module RoadForest::RDF
94
138
  end
95
139
 
96
140
  def as_list
97
- graph = ContextFascade.new(@graph, @root_url, @source_rigor)
98
- list = FocusList.new(@subject, graph)
141
+ list = FocusList.new(subject, access_manager)
99
142
  list.base_node = self
100
- list.source_rigor = source_rigor
101
143
  list
102
144
  end
103
145
 
146
+ def forward_properties
147
+ query_properties( build_query{|q| q.pattern([ normalize_resource(subject), :property, :value ])} )
148
+ end
149
+
150
+ def reverse_properties
151
+ query_properties( build_query{|q| q.pattern([ :value, :property, normalize_resource(subject)])} )
152
+ end
153
+
104
154
  protected
105
155
 
156
+ def single_or_enum(values)
157
+ case values.length
158
+ when 0
159
+ return nil
160
+ when 1
161
+ return values.first
162
+ else
163
+ return values.enum_for(:each)
164
+ end
165
+ end
166
+
106
167
  def reverse_query_value(prefix, property=nil)
107
168
  query_value(build_query{|q|
108
169
  q.pattern([ :value, normalize_property(prefix, property), normalize_resource(subject)])
@@ -115,25 +176,19 @@ module RoadForest::RDF
115
176
  })
116
177
  end
117
178
 
179
+ def build_query(&block)
180
+ access_manager.build_query(&block)
181
+ end
182
+
118
183
  def query_value(query)
119
- solutions = query.execute(graph)
184
+ solutions = query.execute(access_manager)
120
185
  solutions.map do |solution|
121
186
  unwrap_value(solution.value)
122
187
  end
123
188
  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
189
 
135
190
  def query_properties(query)
136
- Hash[query.execute(graph).map do |solution|
191
+ Hash[query.execute(access_manager).map do |solution|
137
192
  prop = solution.property
138
193
  if qname = prop.qname
139
194
  prop = qname
@@ -25,26 +25,27 @@ module RoadForest::RDF
25
25
  @repository = repo || RDF::Repository.new
26
26
  @local_context_node = RDF::Node.new(:local)
27
27
  @debug_io = nil
28
- next_impulse
28
+ force_impulse
29
29
  yield self if block_given?
30
30
  end
31
31
 
32
- def next_impulse
33
- return if !@current_impulse.nil? and raw_quiet_impulse?
34
- #mark ended?
35
- #chain impulses?
32
+ def force_impulse
36
33
  @current_impulse = RDF::Node.new
37
34
  repository.insert(normalize_statement(@current_impulse, [:rdf, 'type'], [:rf, 'Impulse'], nil))
38
35
  repository.insert(normalize_statement(@current_impulse, [:rf, 'begunAt'], Time.now, nil))
39
36
  end
40
37
 
41
- def quiet_impulse?
42
- raw_quiet_impulse?
38
+ def next_impulse
39
+ return if quiet_impulse?
40
+ force_impulse
41
+ #mark ended?
42
+ #chain impulses?
43
43
  end
44
44
 
45
- def raw_quiet_impulse?
45
+ def quiet_impulse?
46
46
  repository.query([nil, nil, @current_impulse, false]).to_a.empty?
47
47
  end
48
+ alias raw_quiet_impulse? quiet_impulse?
48
49
 
49
50
  #repo cleanup - expired graphs
50
51
 
@@ -130,6 +131,8 @@ module RoadForest::RDF
130
131
  end
131
132
 
132
133
  def insert_statement(statement)
134
+ #puts "\n#{__FILE__}:#{__LINE__} => #{[self.object_id,
135
+ #statement].inspect}"
133
136
  repository.insert(statement)
134
137
 
135
138
  repository.delete([statement.context, expand_curie([:rf, "impulse"]), nil])
@@ -158,6 +161,7 @@ module RoadForest::RDF
158
161
  end
159
162
 
160
163
  @repository.query(query) do |statement|
164
+ next if statement.context.nil?
161
165
  yield statement
162
166
  end
163
167
  end
@@ -28,7 +28,6 @@ module RoadForest::RDF
28
28
  source_rigor.graph_transfer.make_request(method, url, graph)
29
29
  end
30
30
 
31
-
32
31
  def insert_graph(context, graph)
33
32
  queryable.insert_graph(context, graph)
34
33
  end
@@ -9,7 +9,9 @@ module RoadForest::RDF
9
9
  subject = normalize_resource(subject) || RDF::Node.new
10
10
  predicate = normalize_uri(predicate)
11
11
  object = normalize_term(object) || RDF::Node.new
12
- context = normalize_resource(context)
12
+ unless context.nil?
13
+ context = normalize_resource(context)
14
+ end
13
15
 
14
16
  RDF::Statement.new(subject, predicate, object, :context => context)
15
17
  end
@@ -23,6 +25,7 @@ module RoadForest::RDF
23
25
  from = expand_curie(from)
24
26
  case from
25
27
  when nil
28
+ from = RDF::Node.new
26
29
  when RDF::Resource
27
30
  when /^_:/
28
31
  from = RDF::Resource.new(from)
@@ -72,16 +75,47 @@ module RoadForest::RDF
72
75
  RDF::Literal.new(object)
73
76
  end
74
77
 
78
+ def relevant_prefixes_for_graph(graph)
79
+ Hash[ vocabularies_in_graph(graph).map do |prefix|
80
+ vocab = Vocabs[prefix]
81
+ [prefix, vocab.to_uri]
82
+ end]
83
+ end
84
+
85
+ def vocabularies_in_graph(graph)
86
+ patterns = Vocabs.map do |prefix, vocab|
87
+ [%r{^#{vocab.to_uri}}, prefix]
88
+ end
89
+
90
+ vocabs = {}
91
+
92
+ graph.each_statement do |statement|
93
+ statement.to_a.each do |field|
94
+ next unless RDF::URI === field
95
+ field = field.to_s
96
+ patterns.each do |pattern, vocab|
97
+ if pattern =~ field
98
+ vocabs[vocab] = true
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ vocabs.keys
105
+ end
106
+
75
107
  def expand_curie_pair(prefix, property)
76
108
  vocab = Vocabs.fetch(prefix) do
77
109
  vocab = RDF::Vocabulary.find do |vocab|
110
+ unless vocab.__prefix__.is_a? RDF::URI
111
+ Vocabs[vocab.__prefix__.to_s] = vocab
112
+ end
78
113
  vocab.__prefix__.to_s == prefix
79
114
  end
80
115
  #p k => vocab #ok
81
116
  if vocab.nil?
82
117
  raise "Don't know a vocabulary for prefix #{prefix.inspect} in CURIE #{prefix}:#{property}"
83
118
  end
84
- Vocabs[prefix] = vocab
85
119
  vocab
86
120
  end
87
121
  vocab[property]
@@ -126,7 +160,6 @@ module RoadForest::RDF
126
160
  end
127
161
 
128
162
  def interned_uri(value)
129
-
130
163
  RDF::URI.intern(uri(value))
131
164
  end
132
165
 
@@ -140,8 +173,8 @@ module RoadForest::RDF
140
173
  if !value.query.nil? and value.query.empty?
141
174
  value.query = nil
142
175
  end
143
- value.validate!
144
176
  value.canonicalize!
177
+ value.validate!
145
178
 
146
179
  value
147
180
  end
@@ -1,5 +1,6 @@
1
1
  require 'rdf/query/pattern'
2
2
  require 'roadforest/rdf'
3
+ require 'roadforest/rdf/graph-store'
3
4
  require 'roadforest/rdf/investigation'
4
5
 
5
6
  module RoadForest::RDF
@@ -12,6 +12,8 @@ class RoadForest::RDF::SourceRigor
12
12
  def resolve(&block)
13
13
  attempts = @attempts
14
14
 
15
+ @graph.force_impulse
16
+
15
17
  begin
16
18
  raise "Annealing failed after #@attempts attempts" if (attempts -= 1) < 0
17
19
  @graph.next_impulse
@@ -1,20 +1,18 @@
1
1
  require 'roadforest/rdf/source-rigor/investigator'
2
- class RoadForest::RDF::SourceRigor
3
- class HTTPInvestigator < Investigator
4
- register :http
2
+ module RoadForest
3
+ class RDF::SourceRigor
4
+ class HTTPInvestigator < Investigator
5
+ register :http
5
6
 
6
- def pursue(investigation)
7
- response = investigation.make_request("GET", investigation.context_roles[:subject])
8
- case response.status
9
- when (200..299)
10
- investigation.insert_graph(response.url, response.graph)
11
- when (300..399)
12
- #client should follow redirects
13
- when (400..499)
14
- when (500..599)
15
- raise NotCredible #hrm
7
+ def pursue(investigation)
8
+ response = investigation.make_request("GET", investigation.context_roles[:subject])
9
+ case response
10
+ when HTTP::GraphResponse
11
+ investigation.insert_graph(response.url, response.graph)
12
+ when HTTP::UnparseableResponse
13
+ #Do nothing
14
+ end
16
15
  end
17
- rescue NotCredible
18
16
  end
19
17
  end
20
18
  end
@@ -2,72 +2,17 @@ require 'roadforest/rdf/graph-focus'
2
2
  require 'roadforest/rdf/parcel'
3
3
 
4
4
  module RoadForest::RDF
5
- class UpdateFocus < GraphFocus
6
- attr_accessor :target_graph
7
-
8
- alias source_graph= graph=
9
- alias source_graph graph
10
-
11
- def dup
12
- other = super
13
- other.target_graph = target_graph
14
- other
15
- end
16
-
17
- def parceller
18
- @parceller ||=
19
- begin
20
- parceller = Parcel.new
21
- parceller.graph = source_graph
22
- parceller
23
- end
5
+ class UpdateFocus < GraphWriting
6
+ def target_graph
7
+ @access_manager.target_graph
24
8
  end
25
9
 
26
- def copy_context
27
- unless target_graph.has_context?(root_url)
28
- parceller.graph_for(root_url).each_statement do |statement|
29
- statement.context = root_url
30
- target_graph << statement
31
- end
32
- end
33
- end
34
-
35
- def add(property, value, extra=nil)
36
- copy_context
37
- property, value = normalize_triple(property, value, extra)
38
- target_graph.insert([subject, property, value, root_url])
39
- end
40
-
41
- def set(property, value, extra=nil)
42
- copy_context
43
- super
44
- end
45
-
46
- def delete(property, extra=nil)
47
- copy_context
48
- property, value = normalize_triple(property, value, extra)
49
- target_graph.query([subject, property]) do |statement|
50
- target_graph.delete(statement)
51
- end
52
- end
53
-
54
- def query_value(query)
55
- source_result = super
56
- target_result = query.execute(target_graph).map do |solution|
57
- unwrap_value(solution.value)
58
- end
59
-
60
- if target_result.empty?
61
- source_result
62
- else
63
- target_result
64
- end
10
+ def target_graph=(graph)
11
+ @access_manager.target_graph = graph
65
12
  end
66
13
 
67
- def wrap_node(value)
68
- focus = super
69
- focus.target_graph = self.target_graph
70
- focus
14
+ def relevant_prefixes
15
+ super.merge(relevant_prefixes_for_graph(target_graph))
71
16
  end
72
17
  end
73
18
  end