roadforest 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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