roadforest 0.0.3 → 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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/examples/file-management.rb +7 -9
  3. data/lib/roadforest/application/dispatcher.rb +44 -31
  4. data/lib/roadforest/application/parameters.rb +5 -4
  5. data/lib/roadforest/application/path-provider.rb +14 -1
  6. data/lib/roadforest/application/route-adapter.rb +15 -4
  7. data/lib/roadforest/application/services-host.rb +41 -7
  8. data/lib/roadforest/application.rb +4 -8
  9. data/lib/roadforest/authorization.rb +231 -0
  10. data/lib/roadforest/blob-model.rb +2 -11
  11. data/lib/roadforest/content-handling/engine.rb +12 -6
  12. data/lib/roadforest/content-handling/handler-wrap.rb +45 -0
  13. data/lib/roadforest/content-handling/media-type.rb +20 -12
  14. data/lib/roadforest/content-handling/type-handler.rb +76 -0
  15. data/lib/roadforest/content-handling/type-handlers/jsonld.rb +2 -146
  16. data/lib/roadforest/content-handling/type-handlers/rdf-handler.rb +38 -0
  17. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/document-environment.rb +34 -0
  18. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/object-environment.rb +62 -0
  19. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/property-environment.rb +46 -0
  20. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/render-engine.rb +574 -0
  21. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/render-environment.rb +144 -0
  22. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/subject-environment.rb +80 -0
  23. data/lib/roadforest/content-handling/type-handlers/rdfa-writer.rb +163 -0
  24. data/lib/roadforest/content-handling/type-handlers/rdfa.rb +175 -0
  25. data/lib/roadforest/content-handling/type-handlers/rdfpost.rb +297 -0
  26. data/lib/roadforest/debug.rb +10 -0
  27. data/lib/roadforest/http/graph-response.rb +3 -7
  28. data/lib/roadforest/http/graph-transfer.rb +28 -106
  29. data/lib/roadforest/http/keychain.rb +79 -0
  30. data/lib/roadforest/http/message.rb +9 -1
  31. data/lib/roadforest/http/user-agent.rb +115 -0
  32. data/lib/roadforest/http.rb +8 -0
  33. data/lib/roadforest/model.rb +48 -3
  34. data/lib/roadforest/rdf/graph-focus.rb +5 -3
  35. data/lib/roadforest/rdf/graph-store.rb +4 -2
  36. data/lib/roadforest/rdf/normalization.rb +6 -1
  37. data/lib/roadforest/remote-host.rb +22 -7
  38. data/lib/roadforest/resource/rdf/read-only.rb +15 -1
  39. data/lib/roadforest/templates/base/doc.haml +13 -0
  40. data/lib/roadforest/templates/base/property_value.haml +12 -0
  41. data/lib/roadforest/templates/base/property_values.haml +6 -0
  42. data/lib/roadforest/templates/base/subject.haml +4 -0
  43. data/lib/roadforest/templates/distiller/doc.haml +20 -0
  44. data/lib/roadforest/templates/distiller/nil-object.haml +1 -0
  45. data/lib/roadforest/templates/distiller/property_value.haml +7 -0
  46. data/lib/roadforest/templates/distiller/property_values.haml +7 -0
  47. data/lib/roadforest/templates/distiller/subject.haml +5 -0
  48. data/lib/roadforest/templates/min/doc.haml +10 -0
  49. data/lib/roadforest/templates/min/property_values.haml +7 -0
  50. data/lib/roadforest/templates/min/subject.haml +2 -0
  51. data/lib/roadforest/templates/nil-object.haml +0 -0
  52. data/lib/roadforest/templates/node-object.haml +1 -0
  53. data/lib/roadforest/templates/object.haml +1 -0
  54. data/lib/roadforest/templates/uri-object.haml +1 -0
  55. data/lib/roadforest/templates/xml-literal-object.haml +1 -0
  56. data/lib/roadforest/utility/class-registry.rb +4 -0
  57. data/spec/client.rb +119 -77
  58. data/spec/{excon-adapater.rb → excon-adapter.rb} +4 -0
  59. data/spec/full-integration.rb +6 -2
  60. data/spec/graph-store.rb +1 -1
  61. data/spec/media-types.rb +29 -2
  62. metadata +102 -125
@@ -0,0 +1,115 @@
1
+ require 'roadforest/http'
2
+ require 'roadforest/http/keychain'
3
+
4
+ module RoadForest
5
+ module HTTP
6
+ class UserAgent
7
+ def initialize(http_client)
8
+ @http_client = http_client
9
+ @trace = nil
10
+ @cache = Hash.new do |cache, url|
11
+ cache[url] = {}
12
+ end
13
+ end
14
+
15
+ attr_accessor :http_client, :trace
16
+ attr_reader :cache
17
+
18
+ def make_request(method, url, headers = nil, body=nil, retry_limit=5)
19
+ headers ||= {}
20
+
21
+ method = method.to_s.upcase
22
+
23
+ validate(method, url, headers, body)
24
+
25
+ request = setup_request(method, url, headers, body)
26
+
27
+ response = send_request(request, retry_limit)
28
+
29
+ cache_response(url, response)
30
+
31
+ return response
32
+ end
33
+
34
+ def setup_request(method, url, headers, body)
35
+ request = Request.new(method, url)
36
+ request.headers.merge!(headers)
37
+ request.body = body
38
+ add_authorization(request)
39
+ add_cache_headers(request)
40
+ request
41
+ end
42
+
43
+ def send_request(request, retry_limit=5)
44
+ #Check expires headers on received
45
+
46
+ trace_message(request)
47
+ response = http_client.do_request(request)
48
+ trace_message(response)
49
+ case response.status
50
+ when 304 #Not Modified
51
+ response = cache.fetch(request.url).fetch(response.etag)
52
+ trace_message(response)
53
+ return response
54
+ when 401
55
+ #XXX What if challenge matches existing Auth header? i.e. current
56
+ #creds are wrong?
57
+ request.headers["Authorization"] = keychain.challenge_response(url, response.headers["WWW-Authenticate"])
58
+ raise Retryable
59
+ end
60
+ return response
61
+ rescue Retryable
62
+ raise unless (retry_limit -= 1) > 0
63
+ retry
64
+ end
65
+
66
+ def trace_message(message)
67
+ return unless @trace
68
+ @trace = $stderr unless @trace.respond_to?(:puts)
69
+ @trace.puts message.inspect
70
+ end
71
+
72
+ def keychain
73
+ @keychain ||= Keychain.new
74
+ end
75
+
76
+ def cache_response(url, response)
77
+ return if response.etag.nil?
78
+ return if response.etag.empty?
79
+ #XXX large bodies
80
+ cache[url][response.etag] = response
81
+ end
82
+
83
+ def validate(method, url, headers, body)
84
+ case method
85
+ when "GET", "HEAD", "DELETE"
86
+ raise "Method #{method} requires an empty body" unless body.nil?
87
+ when "POST", "PATCH", "PUT"
88
+ raise "Method #{method} requires a body" if body.nil?
89
+ #when "OPTION", "TRACE" #Need to put verbs where they go
90
+ else
91
+ raise "Unrecognized method: #{method}"
92
+ end
93
+ end
94
+
95
+ def add_authorization(request)
96
+ request.headers["Authorization"] = keychain.preemptive_response(request.url)
97
+ end
98
+
99
+ def add_cache_headers(request)
100
+ case request.method
101
+ when "GET"
102
+ return unless cache.has_key?(request.url)
103
+ cached = cache[request.url]
104
+ return if cached.empty?
105
+ request.headers["If-None-Match"] = cached.keys.join(", ")
106
+ when "POST", "PUT"
107
+ return unless cache.has_key?(request.url)
108
+ cached = cache[request.url]
109
+ return if cached.empty?
110
+ request.headers["If-Match"] = cached.keys.join(", ")
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,8 @@
1
+ module RoadForest
2
+ module HTTP
3
+ class Retryable < StandardError; end
4
+ end
5
+ end
6
+
7
+ require 'roadforest/http/message'
8
+ require 'roadforest/http/graph-response'
@@ -1,4 +1,8 @@
1
1
  require 'roadforest/rdf/graph-store'
2
+ require 'roadforest/rdf/etagging'
3
+ require 'roadforest/rdf/access-manager'
4
+ require 'roadforest/rdf/graph-focus'
5
+
2
6
  module RoadForest
3
7
  class ProcessingSequenceError < StandardError
4
8
  end
@@ -15,7 +19,34 @@ module RoadForest
15
19
  attr_reader :response_values
16
20
 
17
21
  def path_for(route_name = nil, params = nil)
18
- services.router.path_for(route_name, (params || self.params).to_hash)
22
+ services.router.path_for(route_name, params || self.params)
23
+ end
24
+
25
+ def url_for(route_name, params = nil)
26
+ Addressable::URI.parse(canonical_host.to_s).join(path_for(route_name, params))
27
+ end
28
+
29
+ def model_for(route_name = nil, params = nil)
30
+ services.router.model_for(route_name, params || self.params)
31
+ end
32
+
33
+ def required_grants(method)
34
+ services.authz.build_grants do |grants|
35
+ grants.add(:admin)
36
+ end
37
+ end
38
+
39
+ def authorization(method, header)
40
+ required = required_grants(method)
41
+ if required.empty?
42
+ :public
43
+ else
44
+ services.authz.authorization(header, required_grants(method))
45
+ end
46
+ end
47
+
48
+ def authentication_challenge
49
+ services.authz.challenge(:realm => "Roadforest")
19
50
  end
20
51
 
21
52
  def canonical_host
@@ -23,7 +54,7 @@ module RoadForest
23
54
  end
24
55
 
25
56
  def canonical_uri
26
- Addressable::URI.parse(canonical_host.to_s).join(my_path)
57
+ url_for(route_name, params)
27
58
  end
28
59
 
29
60
  def type_handling
@@ -104,7 +135,6 @@ module RoadForest
104
135
 
105
136
  end
106
137
 
107
- require 'roadforest/rdf/etagging'
108
138
  class RDFModel < Model
109
139
  include RDF::Etagging
110
140
 
@@ -141,6 +171,21 @@ module RoadForest
141
171
  return focus
142
172
  end
143
173
 
174
+ def copy_model(node, route_name, params=nil)
175
+ params ||= {}
176
+
177
+ url = url_for(route_name, params)
178
+ source_model = model_for(route_name, params)
179
+
180
+ access = RDF::CopyManager.new
181
+ access.source_graph = source_model.current_graph
182
+ access.target_graph = node.access_manager.destination_graph
183
+ copier = RDF::GraphFocus.new(access, url)
184
+
185
+ yield copier if block_given?
186
+ copier
187
+ end
188
+
144
189
  def etag
145
190
  @etag ||= etag_from(etag_graph)
146
191
  end
@@ -78,7 +78,7 @@ module RoadForest::RDF
78
78
  end
79
79
 
80
80
  def inspect
81
- "#<#{self.class.name}:0x#{"%x" % object_id} (#{subject.to_s}) #{forward_properties.inspect}>"
81
+ "#<#{self.class.name}:0x#{"%x" % object_id} s:(#{subject.to_s}) p->o:#{forward_properties.inspect}>" #ok
82
82
  end
83
83
  alias to_s inspect
84
84
 
@@ -151,7 +151,7 @@ module RoadForest::RDF
151
151
  end
152
152
 
153
153
  def add_list(property, extra=nil)
154
- list = FocusList.new(nil, access_manager)
154
+ list = FocusList.new(::RDF::Node.new, access_manager)
155
155
  access_manager.insert([subject, normalize_property(property, extra), list.subject])
156
156
  yield list if block_given?
157
157
  return list
@@ -171,8 +171,10 @@ module RoadForest::RDF
171
171
 
172
172
  def unwrap_value(value)
173
173
  return nil if value.nil?
174
- if value.respond_to? :object
174
+ if RDF::Literal === value
175
175
  value.object
176
+ elsif value == RDF.nil
177
+ nil
176
178
  else
177
179
  wrap_node(value)
178
180
  end
@@ -1,4 +1,5 @@
1
1
  require 'rdf'
2
+ require 'roadforest/debug'
2
3
  require 'roadforest/rdf/vocabulary'
3
4
  require 'roadforest/rdf/normalization'
4
5
 
@@ -51,8 +52,9 @@ module RoadForest::RDF
51
52
  end
52
53
 
53
54
  def debug(message)
54
- return if @debug_io.nil?
55
- @debug_io.puts(message)
55
+ io = @debug_io || RoadForest.debug_io
56
+ return if io.nil?
57
+ io.puts(message)
56
58
  end
57
59
 
58
60
  def repository_dump(format = :turtle)
@@ -1,3 +1,4 @@
1
+ require 'addressable/uri'
1
2
  require 'rdf'
2
3
 
3
4
  module RoadForest::RDF
@@ -118,7 +119,11 @@ module RoadForest::RDF
118
119
  end
119
120
  vocab
120
121
  end
121
- vocab[property]
122
+ begin
123
+ vocab[property]
124
+ rescue KeyError
125
+ raise KeyError, "No property #{property} in #{vocab.inspect} - (try: #{vocab.methods(false).sort.inspect})"
126
+ end
122
127
  end
123
128
 
124
129
  def expand_curie(from)
@@ -1,8 +1,11 @@
1
1
  require 'roadforest/rdf/source-rigor'
2
2
  require 'roadforest/rdf/source-rigor/credence-annealer'
3
3
  require 'roadforest/rdf/graph-store'
4
+ require 'roadforest/http/user-agent'
4
5
  require 'roadforest/http/graph-transfer'
5
6
  require 'roadforest/http/adapters/excon'
7
+ require 'roadforest/rdf/access-manager'
8
+ require 'roadforest/rdf/graph-focus'
6
9
 
7
10
  module RoadForest
8
11
  class RemoteHost
@@ -26,10 +29,20 @@ module RoadForest
26
29
  @http_client ||= HTTP::ExconAdapter.new(url)
27
30
  end
28
31
 
32
+ def trace=(target)
33
+ user_agent.trace = target
34
+ end
35
+
36
+ def user_agent
37
+ @user_agent ||= HTTP::UserAgent.new(http_client)
38
+ end
39
+
29
40
  def graph_transfer
30
- @graph_transfer ||= HTTP::GraphTransfer.new.tap do |transfer|
31
- transfer.http_client = http_client
32
- end
41
+ @graph_transfer ||= HTTP::GraphTransfer.new(user_agent)
42
+ end
43
+
44
+ def add_credentials(username, password)
45
+ user_agent.keychain.add(url, username, password)
33
46
  end
34
47
 
35
48
  def source_rigor
@@ -54,11 +67,13 @@ module RoadForest
54
67
  end
55
68
 
56
69
  def putting(&block)
70
+
57
71
  graph = build_graph_store
58
72
  access = RDF::UpdateManager.new
59
73
  access.rigor = source_rigor
60
74
  access.source_graph = graph
61
75
  updater = RDF::GraphFocus.new(access, url)
76
+
62
77
  annealer = RDF::SourceRigor::CredenceAnnealer.new(graph)
63
78
 
64
79
  annealer.resolve do
@@ -75,11 +90,13 @@ module RoadForest
75
90
 
76
91
  def posting(&block)
77
92
  require 'roadforest/rdf/post-focus'
93
+
78
94
  graph = build_graph_store
79
95
  access = RDF::PostManager.new
80
96
  access.rigor = source_rigor
81
97
  access.source_graph = graph
82
98
  poster = RDF::PostFocus.new(access, url)
99
+
83
100
  graphs = {}
84
101
  poster.graphs = graphs
85
102
 
@@ -91,6 +108,7 @@ module RoadForest
91
108
  end
92
109
 
93
110
  def getting(&block)
111
+
94
112
  graph = build_graph_store
95
113
  access = RDF::ReadOnlyManager.new
96
114
  access.rigor = source_rigor
@@ -106,10 +124,7 @@ module RoadForest
106
124
  elsif destination.respond_to?(:to_s)
107
125
  destination = destination.to_s
108
126
  end
109
- request = HTTP::Request.new("PUT", destination)
110
- request.body = io
111
- request.headers["Content-Type"] = type
112
- response = http_client.do_request request
127
+ response = user_agent.make_request("PUT", destination, {"Content-Type" => type}, io)
113
128
  end
114
129
 
115
130
  #TODO:
@@ -6,7 +6,7 @@ module RoadForest
6
6
  def self.registry_purpose; "resource type"; end
7
7
  extend Utility::ClassRegistry::Registrar
8
8
 
9
- module RDF
9
+ module RDF #XXX This shouldn't be in RDF - resource roles are on the REST side
10
10
  #Used for a resource that presents a read-only representation
11
11
  class ReadOnly < Webmachine::Resource
12
12
  def self.register(method_name)
@@ -84,6 +84,20 @@ module RoadForest
84
84
 
85
85
  def content_types_provided
86
86
  model.type_handling.renderers.type_map
87
+ rescue => ex
88
+ super
89
+ end
90
+
91
+ def is_authorized?(header)
92
+ @authorization = @model.authorization(request.method, header)
93
+ if(@authorization == :public || @authorization == :granted)
94
+ return true
95
+ end
96
+ @model.authentication_challenge
97
+ end
98
+
99
+ #Add cache-control headers here
100
+ def finish_request
87
101
  end
88
102
 
89
103
  def resource_exists?
@@ -0,0 +1,13 @@
1
+ !!! XML
2
+ !!! 5
3
+ %html{:xmlns => "http://www.w3.org/1999/xhtml", :lang => lang, :prefix => prefix}
4
+ - if base || title
5
+ %head
6
+ - if base
7
+ %base{:href => base}
8
+ - if title
9
+ %title= title
10
+ %body
11
+ - subjects.each do |subject|
12
+ %div{subject.attrs}
13
+ != yield(subject)
@@ -0,0 +1,12 @@
1
+ - if heading_predicates.include?(predicate) && object.literal?
2
+ %h1{object.simple_attrs}= escape_entities(get_value(object.object))
3
+ - else
4
+ %div.property
5
+ %span.label
6
+ = get_predicate_name(predicate)
7
+ - if object.is_subject?
8
+ %div{object.attrs}= yield object
9
+ - elsif object.attrs.empty?
10
+ = yield object
11
+ - else
12
+ %span{object.attrs}<= yield object
@@ -0,0 +1,6 @@
1
+ %div.property
2
+ %span.label
3
+ = get_predicate_name(predicate)
4
+ %ul
5
+ - objects.each do |object|
6
+ %li{object.attrs}<= yield(object)
@@ -0,0 +1,4 @@
1
+ - if typeof
2
+ %span.type!= typeof
3
+ - predicates.each do |predicate|
4
+ != yield(predicate)
@@ -0,0 +1,20 @@
1
+ !!! XML
2
+ !!! 5
3
+ %html{:xmlns => "http://www.w3.org/1999/xhtml", :lang => lang, :prefix => prefix}
4
+ - if base || title
5
+ %head
6
+ - if base
7
+ %base{:href => base}
8
+ - if title
9
+ %title= title
10
+ %link{:rel => "stylesheet", :href => "http://rdf.kellogg-assoc.com/css/distiller.css", :type => "text/css"}
11
+ %script{:src => "https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js", :type => "text/javascript"}
12
+ %script{:src => "http://rdf.kellogg-assoc.com/js/distiller.js", :type => "text/javascript"}
13
+ %body
14
+ - if base
15
+ %p= "RDFa serialization URI base: &lt;#{base}&gt;"
16
+ - subjects.each do |subject|
17
+ %td{subject.attrs}
18
+ != yield(subject)
19
+ %footer
20
+ %p= "Written by <a href='http://rubygems.org/gems/rdf-rdfa'>RDF::RDFa</a> version #{RDF::RDFa::VERSION}"
@@ -0,0 +1,7 @@
1
+ - if heading_predicates.include?(predicate) && object.literal?
2
+ %h1{object.simple_attrs}= escape_entities(get_value(object.object))
3
+ - else
4
+ %tr.property
5
+ %td.label
6
+ = get_predicate_name(predicate)
7
+ %td{object.attrs}<= yield(object)
@@ -0,0 +1,7 @@
1
+ %tr.property
2
+ %td.label
3
+ = get_predicate_name(predicate)
4
+ %td
5
+ %ul
6
+ - objects.each do |object|
7
+ %li{object.attrs}<= yield(object)
@@ -0,0 +1,5 @@
1
+ - if typeof
2
+ %span.type!= typeof
3
+ %table.properties
4
+ - predicates.each do |predicate|
5
+ != yield(predicate)
@@ -0,0 +1,10 @@
1
+ !!! XML
2
+ !!! 5
3
+ %html{:xmlns => "http://www.w3.org/1999/xhtml", :lang => lang, :prefix => prefix}
4
+ - if base
5
+ %head
6
+ %base{:href => base}
7
+ %body
8
+ - subjects.each do |subject|
9
+ %div{subject.attrs}<
10
+ != yield(subject)
@@ -0,0 +1,7 @@
1
+ - objects.each do |object|
2
+ - if object.is_subject?
3
+ %div{object.attrs}!= yield(object)
4
+ - elsif object.attrs.empty?
5
+ != yield(object)
6
+ - else
7
+ %span{object.attrs}!= yield(object)
@@ -0,0 +1,2 @@
1
+ - predicates.each do |predicate|
2
+ != yield(predicate)
File without changes
@@ -0,0 +1 @@
1
+ =get_curie(object)
@@ -0,0 +1 @@
1
+ #{escape_entities(get_value(object))}
@@ -0,0 +1 @@
1
+ %a{:property => get_curie(predicate), :href => object.to_s, :inlist => inlist}= object.to_s
@@ -0,0 +1 @@
1
+ !~ get_value(object)
@@ -46,6 +46,10 @@ module RoadForest
46
46
  @classes[name.to_s] = klass
47
47
  end
48
48
 
49
+ def names
50
+ @classes.keys.select{|key| key.is_a? Symbol}
51
+ end
52
+
49
53
  def get(name)
50
54
  @classes.fetch(name)
51
55
  rescue KeyError