roadforest 0.0.3 → 0.1

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