roadforest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/examples/file-management.rb +98 -0
  2. data/lib/roadforest/application/dispatcher.rb +54 -0
  3. data/lib/roadforest/application/parameters.rb +39 -0
  4. data/lib/roadforest/application/path-provider.rb +18 -0
  5. data/lib/roadforest/application/route-adapter.rb +24 -0
  6. data/lib/roadforest/application/services-host.rb +10 -0
  7. data/lib/roadforest/application.rb +42 -0
  8. data/lib/roadforest/blob-model.rb +56 -0
  9. data/lib/roadforest/content-handling/engine.rb +113 -0
  10. data/lib/roadforest/content-handling/media-type.rb +222 -0
  11. data/lib/roadforest/content-handling/type-handlers/jsonld.rb +172 -0
  12. data/lib/roadforest/http/adapters/excon.rb +47 -0
  13. data/lib/roadforest/http/graph-response.rb +20 -0
  14. data/lib/roadforest/http/graph-transfer.rb +112 -0
  15. data/lib/roadforest/http/message.rb +91 -0
  16. data/lib/roadforest/model.rb +151 -0
  17. data/lib/roadforest/models.rb +2 -0
  18. data/lib/roadforest/rdf/context-fascade.rb +25 -0
  19. data/lib/roadforest/rdf/document.rb +23 -0
  20. data/lib/roadforest/rdf/focus-list.rb +19 -0
  21. data/lib/roadforest/rdf/focus-wrapping.rb +30 -0
  22. data/lib/roadforest/rdf/graph-copier.rb +16 -0
  23. data/lib/roadforest/rdf/graph-focus.rb +95 -0
  24. data/lib/roadforest/rdf/graph-reading.rb +145 -0
  25. data/lib/roadforest/rdf/graph-store.rb +217 -0
  26. data/lib/roadforest/rdf/investigation.rb +90 -0
  27. data/lib/roadforest/rdf/normalization.rb +150 -0
  28. data/lib/roadforest/rdf/parcel.rb +47 -0
  29. data/lib/roadforest/rdf/post-focus.rb +35 -0
  30. data/lib/roadforest/rdf/resource-pattern.rb +60 -0
  31. data/lib/roadforest/rdf/resource-query.rb +58 -0
  32. data/lib/roadforest/rdf/source-rigor/credence/any.rb +9 -0
  33. data/lib/roadforest/rdf/source-rigor/credence/none-if-role-absent.rb +19 -0
  34. data/lib/roadforest/rdf/source-rigor/credence/role-if-available.rb +19 -0
  35. data/lib/roadforest/rdf/source-rigor/credence-annealer.rb +22 -0
  36. data/lib/roadforest/rdf/source-rigor/credence.rb +29 -0
  37. data/lib/roadforest/rdf/source-rigor/http-investigator.rb +20 -0
  38. data/lib/roadforest/rdf/source-rigor/investigator.rb +17 -0
  39. data/lib/roadforest/rdf/source-rigor/null-investigator.rb +10 -0
  40. data/lib/roadforest/rdf/source-rigor.rb +44 -0
  41. data/lib/roadforest/rdf/update-focus.rb +73 -0
  42. data/lib/roadforest/rdf/vocabulary.rb +11 -0
  43. data/lib/roadforest/rdf.rb +6 -0
  44. data/lib/roadforest/remote-host.rb +96 -0
  45. data/lib/roadforest/resource/handlers.rb +43 -0
  46. data/lib/roadforest/resource/http/form-parsing.rb +81 -0
  47. data/lib/roadforest/resource/rdf/leaf-item.rb +21 -0
  48. data/lib/roadforest/resource/rdf/list.rb +19 -0
  49. data/lib/roadforest/resource/rdf/parent-item.rb +26 -0
  50. data/lib/roadforest/resource/rdf/read-only.rb +100 -0
  51. data/lib/roadforest/resource/rdf.rb +4 -0
  52. data/lib/roadforest/resource/role/has-children.rb +22 -0
  53. data/lib/roadforest/resource/role/writable.rb +43 -0
  54. data/lib/roadforest/server.rb +3 -0
  55. data/lib/roadforest/test-support/dispatcher-facade.rb +77 -0
  56. data/lib/roadforest/test-support/http-client.rb +151 -0
  57. data/lib/roadforest/test-support/matchers.rb +67 -0
  58. data/lib/roadforest/test-support/remote-host.rb +23 -0
  59. data/lib/roadforest/test-support/trace-formatter.rb +140 -0
  60. data/lib/roadforest/test-support.rb +2 -0
  61. data/lib/roadforest/utility/class-registry.rb +49 -0
  62. data/lib/roadforest.rb +2 -0
  63. data/spec/client.rb +152 -0
  64. data/spec/credence-annealer.rb +44 -0
  65. data/spec/graph-copier.rb +87 -0
  66. data/spec/graph-store.rb +142 -0
  67. data/spec/media-types.rb +14 -0
  68. data/spec/rdf-parcel.rb +158 -0
  69. data/spec/update-focus.rb +117 -0
  70. data/spec_support/gem_test_suite.rb +0 -0
  71. metadata +241 -0
@@ -0,0 +1,172 @@
1
+ #@require 'rdf/rdfa' #XXX Otherwise json-ld grabs RDFa documents. Awaiting fix
2
+ #upstream
3
+ require 'json/ld'
4
+
5
+ module RoadForest
6
+ module MediaType
7
+ module Handlers
8
+ module Wrap
9
+ class Wrapper
10
+ def initialize(type, handler)
11
+ @type = type
12
+ @handler = handler
13
+ end
14
+ attr_reader :type, :handler
15
+
16
+ def local_to_network(network)
17
+ @handler.local_to_network(network)
18
+ end
19
+ alias from_graph local_to_network
20
+
21
+ def network_to_local(source)
22
+ @handler.network_to_local(source)
23
+ end
24
+ alias to_graph network_to_local
25
+ end
26
+
27
+ class Render < Wrapper
28
+ def call(resource)
29
+ @handler.render_for(resource)
30
+ end
31
+
32
+ def content_type_header
33
+ @type.content_type_header
34
+ end
35
+ end
36
+
37
+ class Parse < Wrapper
38
+ def call(resource)
39
+ @handler.parse_for(resource)
40
+ end
41
+
42
+ def add_child(resource)
43
+ @handler.add_child_to(resource)
44
+ end
45
+ end
46
+ end
47
+
48
+ class Handler
49
+ def network_to_local(network)
50
+ return network
51
+ end
52
+
53
+ def local_to_network(local)
54
+ return local
55
+ end
56
+
57
+ def parse_for(resource)
58
+ source = resource.request_body
59
+ input_data = network_to_local(source)
60
+ model = resource.model
61
+
62
+ update_model(model, input_data)
63
+
64
+ renderer = model.type_handling.choose_renderer(resource.request_accept_header)
65
+ body = renderer.local_to_network(model.response_data)
66
+
67
+ build_response(resource)
68
+ end
69
+
70
+ def render_for(resource)
71
+ model = resource.model
72
+ output_data = get_output(model)
73
+ local_to_network(output_data)
74
+ end
75
+
76
+ def add_child_to(resource)
77
+ model = resource.model
78
+ source = resource.request_body
79
+ input_data = network_to_local(source)
80
+
81
+ child_for_model(resource.model, input_data)
82
+
83
+ build_response(resource)
84
+ end
85
+
86
+ def build_response(resource)
87
+ model = resource.model
88
+
89
+ renderer = model.type_handling.choose_renderer(resource.request_accept_header)
90
+ body = renderer.local_to_network(model.response_data)
91
+
92
+ resource.response_content_type = renderer.content_type_header
93
+ resource.response_body = body
94
+ if model.response_location
95
+ resource.redirect_to(model.response_location)
96
+ end
97
+ end
98
+
99
+ def child_for_model(model, data)
100
+ model.add_child(data)
101
+ model.processed
102
+ end
103
+
104
+ def update_model(model, input_data)
105
+ result = model.update(input_data)
106
+ model.response_data = result
107
+ model.processed
108
+ result
109
+ end
110
+
111
+ def get_output(model)
112
+ result = model.retrieve
113
+ model.response_data = result
114
+ model.processed
115
+ result
116
+ end
117
+ end
118
+
119
+ require 'roadforest/rdf/normalization'
120
+ class RDFHandler < Handler
121
+ include RDF::Normalization
122
+
123
+ def get_output(model)
124
+ graph = super
125
+ root_uri = model.canonical_uri
126
+
127
+ graph.each_statement do |statement|
128
+ original = statement.dup
129
+ if ::RDF::URI === statement.subject and statement.subject.relative?
130
+ statement.subject = normalize_resource(root_uri.join(statement.subject))
131
+ end
132
+
133
+ if ::RDF::URI === statement.object and statement.object.relative?
134
+ statement.object = normalize_resource(root_uri.join(statement.object))
135
+ end
136
+
137
+ if statement != original
138
+ graph.delete(original)
139
+ graph.insert(statement)
140
+ end
141
+ end
142
+ graph
143
+ end
144
+
145
+ def child_for_model(model, data)
146
+ model.add_graph_child(data)
147
+ model.processed
148
+ end
149
+ end
150
+
151
+ #application/ld+json
152
+ class JSONLD < RDFHandler
153
+ def local_to_network(rdf)
154
+ JSON::LD::Writer.buffer do |writer|
155
+ rdf.each_statement do |statement|
156
+ writer << statement
157
+ end
158
+ end
159
+ end
160
+
161
+ def network_to_local(source)
162
+ graph = ::RDF::Graph.new
163
+ reader = JSON::LD::Reader.new(source.to_s)
164
+ reader.each_statement do |statement|
165
+ graph.insert(statement)
166
+ end
167
+ graph
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,47 @@
1
+ require 'addressable/uri'
2
+ require 'excon'
3
+ require 'roadforest/http/message'
4
+ module RoadForest
5
+ module HTTP
6
+ class ExconAdapter
7
+ def initialize(url)
8
+ @root_url = Addressable::URI.parse(url)
9
+ @connections = Hash.new{|h,k| h[k] = build_site_connection(k)}
10
+ @connection_defaults = {}
11
+ end
12
+ attr_reader :connection_defaults
13
+
14
+ def build_site_connection(site)
15
+ Excon.new(site.to_s, @connection_defaults)
16
+ end
17
+
18
+ def site_connection(uri)
19
+ uri = Addressable::URI.parse(uri)
20
+ @connections[uri.normalized_site]
21
+ end
22
+
23
+ def do_request(request)
24
+ uri = @root_url.join(request.url)
25
+
26
+ connection = site_connection(uri)
27
+ excon_response = connection.request(
28
+ :method => request.method,
29
+ :path => uri.path,
30
+ :headers => request.headers,
31
+ :body => request.body
32
+ )
33
+
34
+ response = HTTP::Response.new
35
+ if excon_response.body.is_a? String
36
+ response.body_string = excon_response.body
37
+ else
38
+ response.body = excon_response.body
39
+ end
40
+ response.headers = excon_response.headers
41
+ response.status = excon_response.status
42
+
43
+ return response
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ module RoadForest
2
+ module HTTP
3
+ class GraphResponse
4
+ attr_accessor :graph
5
+ attr_reader :request, :response
6
+
7
+ def initialize(request, response, graph)
8
+ @request, @response, @graph = request, response, graph
9
+ end
10
+
11
+ def url
12
+ request.url
13
+ end
14
+
15
+ def status
16
+ response.status
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,112 @@
1
+ require 'roadforest/http/message'
2
+ require 'roadforest/http/graph-response'
3
+ require 'roadforest/content-handling/engine'
4
+
5
+ module RoadForest
6
+ module HTTP
7
+ class GraphTransfer
8
+ attr_accessor :http_client
9
+ attr_writer :type_handling
10
+
11
+ def initialize
12
+ @type_preferences = Hash.new{|h,k| k.nil? ? "*/*" : h[nil]}
13
+ end
14
+
15
+ def type_handling
16
+ @type_handling ||= ContentHandling::Engine.default
17
+ end
18
+
19
+ def put(url, graph)
20
+ make_request("PUT", url, graph)
21
+ end
22
+
23
+ def get(url)
24
+ make_request("GET", url)
25
+ end
26
+
27
+ def post(url, graph)
28
+ make_request("POST", url, graph)
29
+ end
30
+
31
+ def make_request(method, url, graph=nil)
32
+ method = method.to_s.upcase
33
+
34
+ validate(method, url, graph)
35
+
36
+ request = setup_request(method, url)
37
+
38
+ response = send_request(request, graph)
39
+
40
+ return build_response(request, response)
41
+ end
42
+
43
+ def validate(method, url, graph)
44
+ case method
45
+ when "GET", "HEAD", "DELETE"
46
+ raise "Method #{method} requires an empty body" unless graph.nil?
47
+ when "POST", "PATCH", "PUT"
48
+ raise "Method #{method} requires a body" if graph.nil?
49
+ #when "OPTION", "TRACE" #Need to put verbs where they go
50
+ else
51
+ raise "Unrecognized method: #{method}"
52
+ end
53
+ end
54
+
55
+ def best_type_for(url)
56
+ return @type_preferences[url]
57
+ end
58
+
59
+ def setup_request(method, url)
60
+ request = Request.new(method, url)
61
+ request.headers["Accept"] = type_handling.parsers.types.accept_header
62
+ request
63
+ end
64
+
65
+ def select_renderer(url)
66
+ end
67
+
68
+ def record_accept_header(url, types)
69
+ return if types.nil? or types.empty?
70
+ @type_preferences[nil] = types
71
+ @type_preferences[url] = types
72
+ end
73
+
74
+ def render_graph(graph, request)
75
+ return unless request.needs_body?
76
+
77
+ content_type = best_type_for(request.url)
78
+ renderer = type_handling.choose_renderer(content_type)
79
+ request.headers["Content-Type"] = renderer.content_type_header
80
+ request.body_string = renderer.from_graph(graph)
81
+ end
82
+
83
+ class Retryable < StandardError; end
84
+
85
+ def send_request(request, graph)
86
+ retry_limit ||= 5
87
+ render_graph(graph, request)
88
+
89
+ response = http_client.do_request(request)
90
+ case response.status
91
+ when 415 #Type not accepted
92
+ record_accept_header(request.url, response.headers["Accept"])
93
+ raise Retryable
94
+ end
95
+ return response
96
+ rescue Retryable
97
+ raise unless (retry_limit -= 1) > 0
98
+ retry
99
+ end
100
+
101
+ def parse_response(response)
102
+ parser = type_handling.choose_parser(response.headers["Content-Type"])
103
+ parser.to_graph(response.body_string)
104
+ end
105
+
106
+ def build_response(request, response)
107
+ graph = parse_response(response)
108
+ return GraphResponse.new(request, response, graph)
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,91 @@
1
+
2
+ require 'stringio'
3
+
4
+ module RoadForest
5
+ module HTTP
6
+ class Message
7
+ attr_accessor :headers
8
+
9
+ def initialize
10
+ @body_string = ""
11
+ @headers = {}
12
+ end
13
+
14
+ def body_string=(value)
15
+ @body_string = value
16
+ @body = nil
17
+ end
18
+
19
+ def body=(value)
20
+ @body = value
21
+ @body_string = nil
22
+ end
23
+
24
+ def body
25
+ return @body ||= StringIO.new(body_string||"")
26
+ end
27
+
28
+ def body_string
29
+ @body_string ||=
30
+ begin
31
+ case @body
32
+ when nil
33
+ nil
34
+ when StringIO
35
+ @body.string
36
+ when IO
37
+ @body.rewind
38
+ @body.read
39
+ else
40
+ raise "Unknown class for body: #{@body.class.name}"
41
+ end
42
+ end
43
+ end
44
+
45
+ def inspect
46
+ "#<#{self.class.name}:#{'0x%0xd'%object_id}\n #{inspection_payload.join("\n ")}\n>"
47
+ end
48
+
49
+ def inspection_payload
50
+ old_pos = body.pos
51
+ body.rewind
52
+ [headers.inspect, body.read]
53
+ ensure
54
+ body.pos = old_pos
55
+ end
56
+
57
+ def empty?
58
+ if @body.nil?
59
+ @body_string.nil? || @body_string.empty?
60
+ else
61
+ @body.respond_to?(:size) && @body.size <= 0
62
+ end
63
+ end
64
+ end
65
+
66
+ class Request < Message
67
+ attr_accessor :method, :url
68
+
69
+ def initialize(method, url)
70
+ super()
71
+ @method, @url = method, url
72
+ end
73
+
74
+ def needs_body?
75
+ %w{POST PATCH PUT}.include?(@method)
76
+ end
77
+
78
+ def inspection_payload
79
+ ["#{method} #{url}"] + super
80
+ end
81
+ end
82
+
83
+ class Response < Message
84
+ attr_accessor :status
85
+
86
+ def inspection_payload
87
+ [status] + super
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,151 @@
1
+ require 'roadforest/rdf/graph-store'
2
+ module RoadForest
3
+ class ProcessingSequenceError < StandardError
4
+ end
5
+
6
+ class Model
7
+ def initialize(route_name, params, services)
8
+ @route_name = route_name
9
+ @params = params
10
+ @services = services
11
+ @data = nil
12
+ @response_values = {}
13
+ end
14
+ attr_reader :route_name, :params, :services, :data
15
+
16
+ def path_for(route_name = nil, params = nil)
17
+ services.router.path_for(route_name, (params || self.params).to_hash)
18
+ end
19
+
20
+ def canonical_host
21
+ services.canonical_host
22
+ end
23
+
24
+ def canonical_uri
25
+ Addressable::URI.parse(canonical_host.to_s).join(my_path)
26
+ end
27
+
28
+ def type_handling
29
+ services.type_handling
30
+ end
31
+
32
+ def my_path
33
+ path_for(route_name, params)
34
+ end
35
+
36
+ def my_url
37
+ canonical_uri.to_s
38
+ end
39
+
40
+ def reset
41
+ end
42
+
43
+ def exists?
44
+ !data.nil?
45
+ end
46
+
47
+ def etag
48
+ nil
49
+ end
50
+
51
+ def last_modified
52
+ nil
53
+ end
54
+
55
+ def response_location
56
+ @response_values.fetch(:location) do
57
+ raise ProcessingSequenceError, "Location not available until request processed"
58
+ end
59
+ end
60
+
61
+ def response_location=(location)
62
+ @response_values[:location] = location
63
+ end
64
+
65
+ def response_data
66
+ @response_values.fetch(:data) do
67
+ raise ProcessingSequenceError, "Location not available until request processed"
68
+ end
69
+ end
70
+
71
+ def response_data=(data)
72
+ @response_values[:data] = data
73
+ end
74
+
75
+ def processed
76
+ [:location, :data].each do |key|
77
+ unless @response_values.has_key?(key)
78
+ @response_values[key] = nil
79
+ end
80
+ end
81
+ end
82
+
83
+ def expires
84
+ nil
85
+ end
86
+
87
+ def update(data)
88
+ raise NotImplementedError
89
+ end
90
+
91
+ def add_child(results)
92
+ raise NotImplementedError
93
+ end
94
+
95
+ def retrieve
96
+ raise NotImplementedError
97
+ end
98
+ alias retreive retrieve
99
+
100
+ def delete
101
+ false
102
+ end
103
+
104
+ end
105
+
106
+ class RDFModel < Model
107
+ def update(graph)
108
+ graph_update(start_focus(graph))
109
+ end
110
+
111
+ def graph_update(focus)
112
+ fill_graph(focus)
113
+ end
114
+
115
+ def add_graph_child(graph)
116
+ add_child(start_focus(graph))
117
+ new_graph
118
+ end
119
+
120
+ def add_child(focus)
121
+ new_graph
122
+ end
123
+
124
+ def retrieve
125
+ new_graph
126
+ end
127
+
128
+ def fill_graph(graph)
129
+ end
130
+
131
+ def start_focus(graph, resource_url=nil)
132
+ focus = RDF::GraphFocus.new
133
+ focus.graph = graph
134
+ focus.subject = resource_url || my_url
135
+
136
+ yield focus if block_given?
137
+ return focus
138
+ end
139
+
140
+ def start_graph(resource_url=nil, &block)
141
+ graph = ::RDF::Graph.new
142
+ start_focus(graph, resource_url, &block)
143
+ end
144
+
145
+ def new_graph
146
+ focus = start_graph(my_url)
147
+ fill_graph(focus)
148
+ self.response_data = focus.graph
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,2 @@
1
+ require 'roadforest/model'
2
+ require 'roadforest/blob-model'
@@ -0,0 +1,25 @@
1
+ require 'rdf'
2
+
3
+ module RoadForest::RDF
4
+ class ContextFascade
5
+ include ::RDF::Countable
6
+ include ::RDF::Enumerable
7
+ include ::RDF::Queryable
8
+
9
+ def initialize(store, resource, rigor)
10
+ @store, @resource, @rigor = store, resource, rigor
11
+ end
12
+
13
+ def query_execute(query, &block)
14
+ ResourceQuery.from(query, @resource, @rigor).execute(@store, &block)
15
+ end
16
+
17
+ def query_pattern(pattern, &block)
18
+ ResourcePattern.from(pattern, {:context_roles => {:subject => @resource}, :source_rigor => @rigor}).execute(@store, &block)
19
+ end
20
+
21
+ def each(&block)
22
+ @store.each(&block)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'stringio'
2
+ require 'roadforest'
3
+
4
+ module RoadForest::RDF
5
+ #Wrapper for text to be parsed into RDF
6
+ class Document
7
+ attr_accessor :content_type, :code, :source, :root_url, :body, :body_string
8
+ def initialize
9
+ @content_type = "text/html"
10
+ @code = 200
11
+ @body_string = ""
12
+ end
13
+
14
+ def body_string=(value)
15
+ @body_string = value
16
+ @body = nil
17
+ end
18
+
19
+ def body
20
+ return @body ||= StringIO.new(body_string)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'roadforest/rdf/focus-wrapping'
2
+ require 'roadforest/rdf/normalization'
3
+ module RoadForest::RDF
4
+ class FocusList < ::RDF::List
5
+ include Normalization
6
+
7
+ attr_accessor :root_url, :base_node, :source_rigor
8
+
9
+ def first
10
+ base_node.unwrap_value(super)
11
+ end
12
+
13
+ def each
14
+ super do |value|
15
+ yield base_node.unwrap_value(value)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ require 'rdf/model/node'
2
+
3
+ module RoadForest::RDF
4
+ module FocusWrapping
5
+ def new_focus
6
+ dup
7
+ end
8
+
9
+ def wrap_node(value)
10
+ next_step = new_focus
11
+ if ::RDF::Node === value
12
+ next_step.root_url = self.root_url
13
+ else
14
+ next_step.root_url = normalize_context(value)
15
+ end
16
+ next_step.subject = value
17
+ next_step.graph = graph
18
+ next_step.source_rigor = source_rigor
19
+ next_step
20
+ end
21
+
22
+ def unwrap_value(value)
23
+ if value.respond_to? :object
24
+ value.object
25
+ else
26
+ wrap_node(value)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'rdf'
2
+ require 'roadforest/rdf/graph-focus'
3
+
4
+ module RoadForest
5
+ module RDF
6
+ class GraphCopier < GraphFocus
7
+ attr_accessor :source_graph, :subject
8
+
9
+ alias target_graph graph
10
+
11
+ def initialize
12
+ @graph = ::RDF::Graph.new
13
+ end
14
+ end
15
+ end
16
+ end