roadforest 0.0.2 → 0.0.3

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.
@@ -56,7 +56,7 @@ module FileManagementExample
56
56
  end
57
57
 
58
58
  def add_child(graph)
59
- services.logger.debug(graph.source_graph.dump(:nquads))
59
+ services.logger.debug(graph.access_manager.source_graph.dump(:nquads))
60
60
  new_file = FileRecord.new(graph.first(:lc, "name"), false)
61
61
  services.file_records << new_file
62
62
  end
@@ -65,6 +65,12 @@ module FileManagementExample
65
65
  graph.add_list(:lc, "needs") do |list|
66
66
  services.file_records.each do |record|
67
67
  if !record.resolved
68
+ # need = copy_from(:need, '*' => record.name)
69
+ # list.add_node(need.url) do |node|
70
+ # need.target = node
71
+ # need[:lc, :name]
72
+ # need[:lc, :digest]
73
+ # end
68
74
  list << path_for(:need, '*' => record.name)
69
75
  end
70
76
  end
@@ -3,7 +3,6 @@ module RoadForest
3
3
  class Application < Webmachine::Application; end
4
4
  end
5
5
 
6
- require 'roadforest/resource/handlers'
7
6
  require 'roadforest/application/dispatcher'
8
7
  require 'roadforest/application/path-provider'
9
8
  require 'roadforest/application/services-host'
@@ -14,7 +13,6 @@ require 'roadforest/rdf/normalization'
14
13
  module RoadForest
15
14
  class Application
16
15
  include RDF::Normalization
17
- include Resource::Handlers
18
16
 
19
17
  def initialize(canonical_host, services = nil, configuration = nil, dispatcher = nil)
20
18
  @canonical_host = normalize_resource(canonical_host)
@@ -1,8 +1,8 @@
1
1
  require 'webmachine'
2
+ require 'roadforest/application/route-adapter'
2
3
 
3
4
  module RoadForest
4
5
  class Dispatcher < Webmachine::Dispatcher
5
- include Resource::Handlers
6
6
  def initialize(services)
7
7
  super(method(:create_resource))
8
8
  @services = services
@@ -11,6 +11,25 @@ module RoadForest
11
11
  end
12
12
  attr_accessor :services, :trace_by_default
13
13
 
14
+ def bundle(resource_class, &block)
15
+ Application::RouteAdapter.new(resource_class, &block)
16
+ end
17
+
18
+ def bundle_typed_resource(resource_type, model_class, route_name)
19
+ resource_class = Resource.get(resource_type)
20
+ bundle(resource_class) do |resource, request, response|
21
+ resource.model = model_class.new(route_name, resource.params, services)
22
+ end
23
+ end
24
+
25
+ def bundle_traced_resource(resource_type, model_class, route_name)
26
+ resource_class = Resource.get(resource_type)
27
+ bundle(resource_class) do |resource, request, response|
28
+ resource.model = model_class.new(route_name, resource.params, services)
29
+ resource.trace = true
30
+ end
31
+ end
32
+
14
33
  def resource_route(resource, name, path_spec, bindings)
15
34
  route = Route.new(path_spec, resource, bindings || {})
16
35
  yield route if block_given?
@@ -133,9 +133,9 @@ module RoadForest
133
133
  end
134
134
 
135
135
  def start_focus(graph, resource_url=nil)
136
- focus = RDF::GraphFocus.new
137
- focus.graph = graph
138
- focus.subject = resource_url || my_url
136
+ access = RDF::WriteManager.new
137
+ access.source_graph = graph
138
+ focus = RDF::GraphFocus.new(access, resource_url || my_url)
139
139
 
140
140
  yield focus if block_given?
141
141
  return focus
@@ -158,7 +158,7 @@ module RoadForest
158
158
  graph = ::RDF::Graph.new
159
159
  focus = start_focus(graph, my_url)
160
160
  fill_graph(focus)
161
- self.response_data = focus.graph
161
+ self.response_data = graph
162
162
  end
163
163
  end
164
164
  end
@@ -2,19 +2,16 @@ require 'rdf'
2
2
  require 'roadforest/rdf/resource-query'
3
3
  require 'roadforest/rdf/resource-pattern'
4
4
  require 'roadforest/rdf/normalization'
5
+ require 'roadforest/rdf/parcel'
5
6
 
6
7
  module RoadForest::RDF
7
- class ContextFascade
8
+ class ReadOnlyManager
8
9
  include ::RDF::Countable
9
10
  include ::RDF::Enumerable
10
11
  include ::RDF::Queryable
11
12
  include Normalization
12
13
 
13
- attr_accessor :resource, :rigor, :source_graph, :target_graph, :copied_contexts
14
-
15
- def initialize
16
- @copied_contexts = {}
17
- end
14
+ attr_accessor :resource, :rigor, :source_graph
18
15
 
19
16
  def resource=(resource)
20
17
  @resource = normalize_context(resource)
@@ -24,33 +21,14 @@ module RoadForest::RDF
24
21
  other = self.class.allocate
25
22
  other.resource = self.resource
26
23
  other.rigor = self.rigor
27
-
28
- other.copied_contexts = self.copied_contexts
29
24
  other.source_graph = self.source_graph
30
- other.target_graph = self.target_graph
25
+
31
26
  return other
32
27
  end
33
28
 
34
- def parceller
35
- @parceller ||=
36
- begin
37
- parceller = Parcel.new
38
- parceller.graph = source_graph
39
- parceller
40
- end
41
- end
29
+ alias origin_graph source_graph
30
+ alias destination_graph source_graph
42
31
 
43
- def copy_context
44
- return if copied_contexts[resource]
45
- return if target_graph.nil? or source_graph == target_graph
46
- parceller.graph_for(resource).each_statement do |statement|
47
- statement.context = resource
48
- target_graph << statement
49
- end
50
- copied_contexts[resource] = true
51
- end
52
-
53
- #superfluous?
54
32
  def build_query
55
33
  ResourceQuery.new([], {}) do |query|
56
34
  query.subject_context = resource
@@ -59,6 +37,10 @@ module RoadForest::RDF
59
37
  end
60
38
  end
61
39
 
40
+ def relevant_prefixes
41
+ relevant_prefixes_for_graph(origin_graph)
42
+ end
43
+
62
44
  def query_execute(query, &block)
63
45
  query = ResourceQuery.from(query, resource, rigor)
64
46
  execute_search(query, &block)
@@ -69,32 +51,104 @@ module RoadForest::RDF
69
51
  execute_search(pattern, &block)
70
52
  end
71
53
 
72
- def execute_search(search, &block)
73
- if target_graph != source_graph and not target_graph.nil?
74
- enum = search.execute(target_graph)
75
- if enum.any?{ true }
76
- enum.each(&block)
77
- return enum
78
- end
79
- end
80
- search.execute(source_graph, &block)
54
+ def each(&block)
55
+ origin_graph.each(&block)
81
56
  end
82
57
 
83
- def each(&block)
84
- source_graph.each(&block)
58
+ def execute_search(search, &block)
59
+ search.execute(origin_graph, &block)
85
60
  end
61
+ end
86
62
 
63
+ class WriteManager < ReadOnlyManager
87
64
  def insert(statement)
88
- copy_context
89
65
  statement[3] = resource
90
- target_graph.insert(statement)
66
+ destination_graph.insert(statement)
91
67
  end
92
68
 
93
69
  def delete(statement)
94
70
  statement = RDF::Query::Pattern.from(statement)
95
71
  statement.context = resource
72
+ destination_graph.delete(statement)
73
+ end
74
+ end
75
+
76
+ class PostManager < WriteManager
77
+ end
78
+
79
+ class SplitManager < WriteManager
80
+ attr_accessor :target_graph
81
+
82
+ alias destination_graph target_graph
83
+
84
+ def dup
85
+ other = super
86
+ other.target_graph = self.target_graph
87
+ return other
88
+ end
89
+
90
+ def relevant_prefixes
91
+ super.merge(relevant_prefixes_for_graph(destination_graph))
92
+ end
93
+ end
94
+
95
+ class UpdateManager < SplitManager
96
+ def initialize
97
+ @copied_contexts = {}
98
+ end
99
+
100
+ attr_accessor :copied_contexts
101
+
102
+ def dup
103
+ other = super
104
+ other.copied_contexts = self.copied_contexts
105
+ return other
106
+ end
107
+
108
+ def execute_search(search, &block)
109
+ enum = search.execute(destination_graph)
110
+ if enum.any?{ true }
111
+ enum.each(&block)
112
+ return enum
113
+ end
114
+ search.execute(origin_graph, &block)
115
+ end
116
+
117
+ def insert(statement)
118
+ copy_context
119
+ super
120
+ end
121
+
122
+ def delete(statement)
96
123
  copy_context
97
- target_graph.delete(statement)
124
+ super
125
+ end
126
+
127
+ def parceller
128
+ @parceller ||=
129
+ begin
130
+ parceller = Parcel.new
131
+ parceller.graph = source_graph
132
+ parceller
133
+ end
134
+ end
135
+
136
+ def copy_context
137
+ return if copied_contexts[resource]
138
+ parceller.graph_for(resource).each_statement do |statement|
139
+ statement.context = resource
140
+ destination_graph << statement
141
+ end
142
+ copied_contexts[resource] = true
143
+ end
144
+ end
145
+
146
+ class CopyManager < SplitManager
147
+ def execute_search(search, &block)
148
+ super(search) do |statement|
149
+ destination_graph.insert(statement)
150
+ yield statement
151
+ end
98
152
  end
99
153
  end
100
154
  end
@@ -37,7 +37,7 @@ module RoadForest::RDF
37
37
 
38
38
  if empty?
39
39
  new_subject = subject
40
- graph.insert([new_subject, RDF.type, RDF.List])
40
+ #graph.insert([new_subject, RDF.type, RDF.List])
41
41
  else
42
42
  old_subject, new_subject = last_subject, RDF::Node.new
43
43
  graph.delete([old_subject, RDF.rest, RDF.nil])
@@ -3,12 +3,17 @@ require 'roadforest/rdf/graph-focus'
3
3
 
4
4
  module RoadForest
5
5
  module RDF
6
- class GraphCopier < GraphWriting
7
- attr_accessor :target_graph
8
-
9
- def initialize
6
+ class GraphCopier < GraphFocus
7
+ def query_value(query)
8
+ #This isn't the most efficient way to do this (the query essentially
9
+ #happens twice) but the intended use of GC is to copy small numbers of
10
+ #patterns between small graphs, so the n is small
11
+ query.patterns.each do |pattern|
12
+ pattern.execute(@access_manager) do |statement|
13
+ @access_manager.insert(statement)
14
+ end
15
+ end
10
16
  super
11
- @target_graph = ::RDF::Graph.new
12
17
  end
13
18
  end
14
19
  end
@@ -1,39 +1,94 @@
1
1
  require 'rdf'
2
- require 'roadforest/rdf/context-fascade'
3
- require 'roadforest/rdf/graph-reading'
2
+ require 'rdf/model/node'
3
+ require 'roadforest/rdf'
4
+ require 'roadforest/rdf/focus-list'
5
+ require 'roadforest/rdf/normalization'
6
+ require 'roadforest/rdf/resource-query'
7
+ require 'roadforest/rdf/access-manager'
8
+
4
9
 
5
10
  module RoadForest::RDF
6
- class GraphCollection
7
- include Enumerable
11
+ class NullFocus < ::BasicObject
12
+ def initialize(focus, pattern, callsite)
13
+ @focus, @pattern, @callsite = focus, pattern, callsite
14
+ end
15
+
16
+ def __callsite__
17
+ @callsite
18
+ end
19
+
20
+ def subject
21
+ @focus.subject
22
+ end
23
+
24
+ def nil?
25
+ true
26
+ end
27
+
28
+ def blank?
29
+ true
30
+ end
31
+
32
+ def empty?
33
+ true
34
+ end
35
+
36
+ def length
37
+ 0
38
+ end
39
+ alias count length
40
+ alias size length
41
+
42
+ def method_missing(method, *args, &block)
43
+ ::Kernel.raise ::NoMethodError, "No method '#{method}' on NullFocus. " +
44
+ "NullFocus returned because there were no results at \n#{@focus.subject}\n for \n#{@pattern.inspect}\n" +
45
+ "Search was attempted at #{@callsite[0]}"
46
+ end
8
47
  end
9
48
 
10
- class MultivaluedProperty < GraphCollection
11
- attr_reader :graph, :subject, :property
12
- def initialize(graph, subject, property)
13
- @graph, @subject, @propery = graph, subject, property
49
+ class GraphFocus
50
+ #XXX Any changes to this class heirarchy or to ContextFascade should start
51
+ #with a refactor like:
52
+ # Reduce this to the single-node API ([] []=)
53
+ # Change the ContextFascade into a family of classes (RO, RW, Update)
54
+ include Normalization
55
+
56
+ #attr_accessor :source_graph, :target_graph, :subject, :root_url,
57
+ #:source_rigor
58
+
59
+ attr_accessor :subject, :access_manager
60
+
61
+ alias rdf subject
62
+
63
+ def initialize(access_manager, subject = nil)
64
+ @access_manager = access_manager
65
+ self.subject = subject unless subject.nil?
14
66
  end
15
67
 
16
- def values
17
- query_value(graph, subject, property)
68
+ def root_url
69
+ @access_manager.resource
18
70
  end
19
71
 
20
- def each
21
- if block_given?
22
- other
23
- values.each do |value|
24
- yield unwrap_value(value)
25
- end
26
- else
27
- values.each
72
+ def subject=(*value)
73
+ @subject = normalize_resource(value)
74
+ case @subject
75
+ when ::RDF::URI
76
+ @access_manager.resource = @subject
28
77
  end
29
78
  end
30
79
 
31
- def add(value)
32
- add_statement(subject, property, value)
80
+ def inspect
81
+ "#<#{self.class.name}:0x#{"%x" % object_id} (#{subject.to_s}) #{forward_properties.inspect}>"
82
+ end
83
+ alias to_s inspect
84
+
85
+ def dup
86
+ other = self.class.new(access_manager.dup)
87
+ other.subject = subject
88
+ other
33
89
  end
34
- end
35
90
 
36
- class GraphWriting < GraphReading
91
+ ### Begin old GraphFocus
37
92
  def normalize_triple(property, value, extra=nil)
38
93
  if not extra.nil?
39
94
  property = [property, value]
@@ -71,6 +126,7 @@ module RoadForest::RDF
71
126
  end
72
127
  value
73
128
  end
129
+ alias first_or_add find_or_add
74
130
 
75
131
  def set_node(property, url=nil)
76
132
  create_node(url) do |node|
@@ -100,20 +156,154 @@ module RoadForest::RDF
100
156
  yield list if block_given?
101
157
  return list
102
158
  end
103
- end
159
+ #### End of old GraphFocus
160
+
161
+ def wrap_node(value)
162
+ next_step = dup
163
+ if ::RDF::Node === value
164
+ next_step.root_url = self.root_url
165
+ else
166
+ next_step.root_url = normalize_context(value)
167
+ end
168
+ next_step.subject = value
169
+ next_step
170
+ end
171
+
172
+ def unwrap_value(value)
173
+ return nil if value.nil?
174
+ if value.respond_to? :object
175
+ value.object
176
+ else
177
+ wrap_node(value)
178
+ end
179
+ end
180
+
181
+ def to_context
182
+ normalize_context(subject)
183
+ end
184
+
185
+ def root_url=(*value) #XXX curies?
186
+ @root_url = normalize_resource(value)
187
+ end
104
188
 
105
- class GraphFocus < GraphWriting
106
- def target_graph
107
- @access_manager.target_graph
189
+ #XXX This probably wants to be handled completely in the MediaType handler
190
+ def relevant_prefixes
191
+ access_manager.relevant_prefixes
108
192
  end
109
193
 
110
- def source_graph=(graph)
111
- @access_manager.source_graph = graph
112
- @access_manager.target_graph = graph
194
+ def get(prefix, property = nil)
195
+ return maybe_null( prefix, property,
196
+ single_or_enum(forward_query_value( prefix, property))
197
+ )
113
198
  end
114
- alias target_graph= source_graph=
199
+ alias_method :[], :get
115
200
 
116
- alias graph source_graph
117
- alias graph= source_graph=
201
+ def first(prefix, property = nil)
202
+ return maybe_null( prefix, property,
203
+ forward_query_value( prefix, property ).first
204
+ )
205
+ end
206
+
207
+ def all(prefix, property = nil)
208
+ return maybe_null( prefix, property,
209
+ forward_query_value( prefix, property )
210
+ )
211
+ end
212
+
213
+ #XXX Maybe rev should return a decorator, so it looks like:
214
+ #focus.rev.get(...) or focus.rev.all(...)
215
+ def rev(prefix, property = nil)
216
+ return maybe_null( prefix, property,
217
+ single_or_enum(reverse_query_value( prefix, property))
218
+ )
219
+ end
220
+
221
+ def rev_first(prefix, property = nil)
222
+ return maybe_null( prefix, property,
223
+ reverse_query_value(prefix, property).first
224
+ )
225
+ end
226
+
227
+ def rev_all(prefix, property = nil)
228
+ return maybe_null( prefix, property,
229
+ reverse_query_value(prefix, property)
230
+ )
231
+ end
232
+
233
+ def as_list
234
+ list = FocusList.new(subject, access_manager)
235
+ list.base_node = self
236
+ list
237
+ end
238
+
239
+ def forward_properties
240
+ query_properties( build_query{|q| q.pattern([ normalize_resource(subject), :property, :value ])} )
241
+ end
242
+
243
+ def reverse_properties
244
+ query_properties( build_query{|q| q.pattern([ :value, :property, normalize_resource(subject)])} )
245
+ end
246
+
247
+ protected
248
+
249
+ STRIP_TRACE = %r{\A#{File::expand_path("../../..", __FILE__)}}
250
+ def maybe_null(prefix, property, result)
251
+ if not result.nil?
252
+ if result.respond_to? :empty?
253
+ return result unless result.empty?
254
+ else
255
+ return result
256
+ end
257
+ end
258
+ return NullFocus.new(self, normalize_property(prefix, property), caller(0).drop_while{|line| line =~ STRIP_TRACE})
259
+ end
260
+
261
+ def single_or_enum(values)
262
+ case values.length
263
+ when 0
264
+ return nil
265
+ when 1
266
+ return values.first
267
+ else
268
+ return values.enum_for(:each)
269
+ end
270
+ end
271
+
272
+ def reverse_query_value(prefix, property=nil)
273
+ query_value(build_query{|q|
274
+ q.pattern([ :value, normalize_property(prefix, property), normalize_resource(subject)])
275
+ })
276
+ end
277
+
278
+ def forward_query_value(prefix, property=nil)
279
+ query_value(build_query{|q|
280
+ q.pattern([ normalize_resource(subject), normalize_property(prefix, property), :value])
281
+ })
282
+ end
283
+
284
+ def build_query(&block)
285
+ access_manager.build_query(&block)
286
+ end
287
+
288
+ def execute_query(query)
289
+ query.execute(access_manager)
290
+ end
291
+
292
+ def query_value(query)
293
+ solutions = execute_query(query)
294
+ solutions.map do |solution|
295
+ unwrap_value(solution.value)
296
+ end
297
+ end
298
+
299
+ def query_properties(query)
300
+ Hash[execute_query(query).map do |solution|
301
+ prop = solution.property
302
+ if qname = prop.qname
303
+ prop = qname
304
+ end
305
+ [prop, solution.value]
306
+ end]
307
+ end
118
308
  end
119
309
  end