roadforest 0.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 (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,47 @@
1
+ require 'roadforest/rdf'
2
+ require 'roadforest/rdf/normalization'
3
+
4
+ module RoadForest::RDF
5
+ class Parcel
6
+ include Normalization
7
+
8
+ attr_accessor :graph
9
+
10
+ def resources
11
+ resource_hash = {}
12
+ graph.each_subject do |subject|
13
+ next unless RDF::URI === subject
14
+ resource_hash[normalize_context(subject)] = true
15
+ end
16
+ resource_hash.keys
17
+ end
18
+
19
+ def subjects_for_resource(resource)
20
+ resource = normalize_context(resource)
21
+ graph.each_subject.find_all do |subject|
22
+ normalize_context(subject) == resource
23
+ end
24
+ end
25
+
26
+ def graph_for(resource)
27
+ new_graph = RDF::Graph.new
28
+ subjects = {}
29
+ subjects_for_resource(resource).each do |subject|
30
+ subjects[subject] ||= :open
31
+ end
32
+
33
+ until (open_subjects = subjects.keys.find_all{|subject| subjects[subject] == :open }).empty?
34
+ open_subjects.each do |subject|
35
+ subjects[subject] = :closed
36
+ graph.query(:subject => subject) do |statement|
37
+ if RDF::Node === statement.object
38
+ subjects[statement.object] ||= :open
39
+ end
40
+ new_graph << statement
41
+ end
42
+ end
43
+ end
44
+ new_graph
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,35 @@
1
+ require 'roadforest/rdf/graph-focus'
2
+
3
+ module RoadForest::RDF
4
+ class PostFocus < GraphFocus
5
+ def initialize(subject = nil, graph = nil , rigor = nil)
6
+ super(subject, graph, rigor)
7
+ @graphs = {}
8
+ end
9
+ attr_accessor :graphs
10
+
11
+ def dup
12
+ other = super
13
+ other.graphs = graphs
14
+ other
15
+ end
16
+
17
+ def graph_transfer
18
+ source_rigor.graph_transfer
19
+ end
20
+
21
+ def post_to
22
+ graph = ::RDF::Graph.new
23
+ focus = GraphFocus.new(subject, graph, source_rigor) #XXX non-client version
24
+ graphs[subject] = graph
25
+ yield focus if block_given?
26
+ return focus
27
+ end
28
+
29
+ def send_graphs
30
+ @graphs.each_pair do |url, graph|
31
+ graph_transfer.post(url, graph)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,60 @@
1
+ require 'rdf/query/pattern'
2
+ require 'roadforest/rdf'
3
+ require 'roadforest/rdf/investigation'
4
+
5
+ module RoadForest::RDF
6
+ class ResourcePattern < ::RDF::Query::Pattern
7
+ def self.from(pattern, options)
8
+ pattern = case pattern
9
+ when self
10
+ pattern
11
+ when ::RDF::Query::Pattern
12
+ options ||= {}
13
+ self.new(pattern.subject, pattern.predicate, pattern.object, options.merge(:context => pattern.context))
14
+ when Array, ::RDF::Statement
15
+ options ||= {}
16
+ self.new(pattern[0], pattern[1], pattern[2], options.merge(:context => pattern[3]))
17
+ when Hash
18
+ options ||= {}
19
+ self.new(options.merge(pattern))
20
+ else
21
+ raise ArgumentError, "expected RoadForest::RDF::ResourcePattern, RDF::Query::Pattern, RDF::Statement, Hash, or Array, but got #{pattern.inspect}"
22
+ end
23
+
24
+ unless options.nil?
25
+ pattern.context_roles = options[:context_roles]
26
+ pattern.source_rigor = options[:source_rigor]
27
+ end
28
+
29
+ yield pattern if block_given?
30
+
31
+ pattern
32
+ end
33
+
34
+ attr_accessor :context_roles, :source_rigor
35
+
36
+ def execute(queryable, bindings = nil, query_context_roles = nil, &block)
37
+ unless queryable.is_a? RoadForest::RDF::GraphStore
38
+ return super(queryable, bindings || {}, &block)
39
+ end
40
+
41
+ investigation = Investigation.new
42
+ investigation.queryable = queryable
43
+ investigation.context_roles = (query_context_roles || {}).merge(context_roles)
44
+ investigation.source_rigor = source_rigor
45
+
46
+ results = investigation.result do |results|
47
+ super(queryable, bindings || {}) do |statement|
48
+ results << statement
49
+ end
50
+ end
51
+
52
+ results.each(&block) if block_given?
53
+ results
54
+ end
55
+
56
+ def context
57
+ @context ||= ::RDF::Query::Variable.new(:context)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,58 @@
1
+ require 'roadforest/rdf'
2
+ require 'rdf/query'
3
+
4
+ module RoadForest::RDF
5
+ class ResourceQuery < ::RDF::Query
6
+ def initialize(patterns = [], options = {}, &block)
7
+ @subject_context = options[:subject_context]
8
+ @source_rigor = options[:source_rigor]
9
+ super
10
+ patterns = @patterns.dup
11
+ @patterns.clear
12
+ patterns.each do |pattern|
13
+ pattern(pattern)
14
+ end
15
+ end
16
+
17
+ attr_accessor :subject_context, :source_rigor
18
+ attr_accessor :patterns, :variables, :solutions, :options
19
+
20
+ def <<(pattern)
21
+ pattern(pattern)
22
+ end
23
+
24
+ def pattern(pattern, options = nil)
25
+ options = {
26
+ :context_roles => {:subject => subject_context},
27
+ :source_rigor => source_rigor
28
+ }.merge(options || {})
29
+
30
+ @patterns << ResourcePattern.from(pattern, options)
31
+ self
32
+ end
33
+
34
+ def self.from(other, subject_context = nil, source_rigor = nil)
35
+ query = self.new
36
+
37
+ if subject_context.nil? and other.respond_to?(:subject_context)
38
+ query.subject_context = other.subject_context
39
+ else
40
+ query.subject_context = subject_context
41
+ end
42
+
43
+ if source_rigor.nil? and other.respond_to?(:source_rigor)
44
+ query.source_rigor = other.source_rigor
45
+ else
46
+ query.source_rigor = source_rigor
47
+ end
48
+
49
+ other.patterns.each do |pattern|
50
+ query.pattern(pattern)
51
+ end
52
+ query.variables = other.variables
53
+ query.solutions = other.solutions
54
+ query.options = other.options
55
+ return query
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,9 @@
1
+ class RoadForest::RDF::SourceRigor
2
+ module Credence
3
+ class Any
4
+ def credible(contexts, results)
5
+ contexts
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class RoadForest::RDF::SourceRigor
2
+ module Credence
3
+ #Unless we have results for the subject context, nothing is valid
4
+ class NoneIfRoleAbsent
5
+ def initialize(role)
6
+ @role = role
7
+ end
8
+ attr_reader :role
9
+
10
+ def credible(contexts, results)
11
+ if contexts.include?(results.context_roles[role])
12
+ contexts
13
+ else
14
+ []
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ class RoadForest::RDF::SourceRigor
2
+ module Credence
3
+ #If there are any results for the subject context, they're good
4
+ class RoleIfAvailable
5
+ def initialize(role)
6
+ @role = role
7
+ end
8
+ attr_reader :role
9
+
10
+ def credible(contexts, results)
11
+ if contexts.include?(results.context_roles[role])
12
+ [results.context_roles[role]]
13
+ else
14
+ contexts
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require 'roadforest/rdf'
2
+
3
+ class RoadForest::RDF::SourceRigor
4
+ class CredenceAnnealer
5
+ def initialize(graph)
6
+ @graph = graph
7
+ @attempts = 5
8
+ end
9
+
10
+ attr_accessor :attempts
11
+
12
+ def resolve(&block)
13
+ attempts = @attempts
14
+
15
+ begin
16
+ raise "Annealing failed after #@attempts attempts" if (attempts -= 1) < 0
17
+ @graph.next_impulse
18
+ block.call
19
+ end until @graph.quiet_impulse?
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ class RoadForest::RDF::SourceRigor
2
+ module Credence
3
+ require 'roadforest/rdf/source-rigor/credence/role-if-available'
4
+ require 'roadforest/rdf/source-rigor/credence/any'
5
+ require 'roadforest/rdf/source-rigor/credence/none-if-role-absent'
6
+
7
+ def self.policies
8
+ @policies ||= {
9
+ :any => Any.new,
10
+ :may_subject => RoleIfAvailable.new(:subject),
11
+ :must_subject => NoneIfRoleAbsent.new(:subject),
12
+ :may_local => RoleIfAvailable.new(:local),
13
+ :must_local => NoneIfRoleAbsent.new(:local)
14
+ }
15
+ end
16
+
17
+ def self.policy(name)
18
+ if block_given?
19
+ policies[name] ||= yield
20
+ else
21
+ begin
22
+ policies.fetch(name)
23
+ rescue KeyError
24
+ raise "No Credence policy for #{name.inspect} (available named policies are #{policies.keys.inspect})"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ require 'roadforest/rdf/source-rigor/investigator'
2
+ class RoadForest::RDF::SourceRigor
3
+ class HTTPInvestigator < Investigator
4
+ register :http
5
+
6
+ def pursue(investigation)
7
+ response = investigation.make_request("GET", investigation.context_roles[:subject])
8
+ case response.status
9
+ when (200..299)
10
+ investigation.insert_graph(response.url, response.graph)
11
+ when (300..399)
12
+ #client should follow redirects
13
+ when (400..499)
14
+ when (500..599)
15
+ raise NotCredible #hrm
16
+ end
17
+ rescue NotCredible
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ require 'roadforest/utility/class-registry'
2
+
3
+ class RoadForest::RDF::SourceRigor
4
+ class NotCredible < StandardError; end
5
+ class NoCredibleResults < StandardError; end
6
+
7
+ class Investigator
8
+ extend ::RoadForest::Utility::ClassRegistry::Registrar
9
+ def self.registry_purpose; "investigator"; end
10
+
11
+ def pursue(investigation)
12
+ raise NoCredibleResults
13
+ end
14
+ end
15
+ end
16
+ require 'roadforest/rdf/source-rigor/null-investigator'
17
+ require 'roadforest/rdf/source-rigor/http-investigator'
@@ -0,0 +1,10 @@
1
+ require 'roadforest/rdf/source-rigor/investigator'
2
+ class RoadForest::RDF::SourceRigor
3
+ class NullInvestigator < Investigator
4
+ register :null
5
+
6
+ def pursue(investigation)
7
+ investigation.results = []
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,44 @@
1
+ require 'roadforest'
2
+
3
+ module RoadForest::RDF
4
+ class SourceRigor
5
+ require 'roadforest/rdf/source-rigor/investigator'
6
+ require 'roadforest/rdf/source-rigor/credence'
7
+
8
+ class << self
9
+ def simple
10
+ rigor = self.new
11
+ rigor.policy_list(:must_local, :may_local)
12
+ rigor.investigator_list(:null)
13
+ rigor
14
+ end
15
+
16
+ def http
17
+ rigor = self.new
18
+ rigor.policy_list(:may_subject, :any) #XXX
19
+ rigor.investigator_list(:http, :null)
20
+ rigor
21
+ end
22
+ end
23
+
24
+ def initialize
25
+ @investigators = []
26
+ @investigation_limit = 3
27
+ @credence_policies = []
28
+ end
29
+
30
+ attr_accessor :graph_transfer, :investigators, :investigation_limit, :credence_policies
31
+
32
+ def policy_list(*names)
33
+ self.credence_policies = names.map do |name|
34
+ Credence.policy(name)
35
+ end
36
+ end
37
+
38
+ def investigator_list(*names)
39
+ self.investigators = names.map do |name|
40
+ Investigator[name].new
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,73 @@
1
+ require 'roadforest/rdf/graph-focus'
2
+ require 'roadforest/rdf/parcel'
3
+
4
+ module RoadForest::RDF
5
+ class UpdateFocus < GraphFocus
6
+ attr_accessor :target_graph
7
+
8
+ alias source_graph= graph=
9
+ alias source_graph graph
10
+
11
+ def dup
12
+ other = super
13
+ other.target_graph = target_graph
14
+ other
15
+ end
16
+
17
+ def parceller
18
+ @parceller ||=
19
+ begin
20
+ parceller = Parcel.new
21
+ parceller.graph = source_graph
22
+ parceller
23
+ end
24
+ end
25
+
26
+ def copy_context
27
+ unless target_graph.has_context?(root_url)
28
+ parceller.graph_for(root_url).each_statement do |statement|
29
+ statement.context = root_url
30
+ target_graph << statement
31
+ end
32
+ end
33
+ end
34
+
35
+ def add(property, value, extra=nil)
36
+ copy_context
37
+ property, value = normalize_triple(property, value, extra)
38
+ target_graph.insert([subject, property, value, root_url])
39
+ end
40
+
41
+ def set(property, value, extra=nil)
42
+ copy_context
43
+ super
44
+ end
45
+
46
+ def delete(property, extra=nil)
47
+ copy_context
48
+ property, value = normalize_triple(property, value, extra)
49
+ target_graph.query([subject, property]) do |statement|
50
+ target_graph.delete(statement)
51
+ end
52
+ end
53
+
54
+ def query_value(query)
55
+ source_result = super
56
+ target_result = query.execute(target_graph).map do |solution|
57
+ unwrap_value(solution.value)
58
+ end
59
+
60
+ if target_result.empty?
61
+ source_result
62
+ else
63
+ target_result
64
+ end
65
+ end
66
+
67
+ def wrap_node(value)
68
+ focus = super
69
+ focus.target_graph = self.target_graph
70
+ focus
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,11 @@
1
+ require 'roadforest/rdf'
2
+
3
+ module RoadForest::RDF
4
+ module Vocabulary
5
+ class RF < ::RDF::Vocabulary("http://lrdesign.com/rdf/roadforest#")
6
+ property :Impulse
7
+ property :impulse
8
+ property :begunAt
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ require 'rdf'
2
+
3
+ module RoadForest
4
+ module RDF
5
+ end
6
+ end
@@ -0,0 +1,96 @@
1
+ require 'roadforest/rdf/source-rigor'
2
+ require 'roadforest/rdf/source-rigor/credence-annealer'
3
+ require 'roadforest/http/graph-transfer'
4
+ require 'roadforest/http/adapters/excon'
5
+ require 'roadforest/rdf/graph-store'
6
+
7
+ module RoadForest
8
+ class RemoteHost
9
+ include RDF::Normalization
10
+
11
+ def initialize(well_known_url)
12
+ @url = normalize_resource(well_known_url)
13
+ @graph = build_graph_store
14
+ end
15
+
16
+ def build_graph_store
17
+ RDF::GraphStore.new
18
+ end
19
+
20
+ attr_writer :http_client
21
+ def http_client
22
+ @http_client ||= HTTP::ExconAdapter.new(@url)
23
+ end
24
+
25
+ def graph_transfer
26
+ @graph_transfer ||= HTTP::GraphTransfer.new.tap do |transfer|
27
+ transfer.http_client = http_client
28
+ end
29
+ end
30
+
31
+ def source_rigor
32
+ @source_rigor ||=
33
+ begin
34
+ rigor = RDF::SourceRigor.http
35
+ rigor.graph_transfer = graph_transfer
36
+ rigor
37
+ end
38
+ end
39
+
40
+ def render_graph(graph)
41
+ Resource::ContentType::JSONLD.from_graph(graph)
42
+ end
43
+
44
+ def anneal(focus)
45
+ annealer = RDF::SourceRigor::CredenceAnnealer.new(@graph)
46
+ annealer.resolve do
47
+ yield focus
48
+ end
49
+ end
50
+
51
+ def putting(&block)
52
+ require 'roadforest/rdf/update-focus'
53
+ target_graph = ::RDF::Repository.new
54
+ updater = RDF::UpdateFocus.new(@url, @graph, source_rigor)
55
+ updater.target_graph = target_graph
56
+
57
+ anneal(updater, &block)
58
+
59
+ target_graph.each_context do |context|
60
+ graph = ::RDF::Graph.new(context, :data => target_graph)
61
+ graph_transfer.put(context, graph)
62
+ end
63
+ end
64
+
65
+ def posting(&block)
66
+ require 'roadforest/rdf/post-focus'
67
+ poster = RDF::PostFocus.new(@url, @graph, source_rigor)
68
+
69
+ anneal(poster, &block)
70
+
71
+ poster.send_graphs
72
+ end
73
+
74
+ def getting(&block)
75
+ reader = RDF::GraphReading.new(@url, @graph, source_rigor)
76
+
77
+ anneal(reader, &block)
78
+ end
79
+
80
+ def put_file(destination, type, io)
81
+ if destination.respond_to?(:to_context)
82
+ destination = destination.to_context
83
+ elsif destination.respond_to?(:to_s)
84
+ destination = destination.to_s
85
+ end
86
+ request = HTTP::Request.new("PUT", destination)
87
+ request.body = io
88
+ request.headers["Content-Type"] = type
89
+ response = http_client.do_request request
90
+ end
91
+
92
+ #TODO:
93
+ #def deleting
94
+ #def patching
95
+ end
96
+ end
@@ -0,0 +1,43 @@
1
+ require 'roadforest/application/route-adapter'
2
+
3
+ module RoadForest
4
+ module Resource
5
+ module Handlers
6
+ def self.registry
7
+ @registry ||= {}
8
+ end
9
+
10
+ def self.register(handler_type, klass)
11
+ registry[handler_type] = klass
12
+
13
+ method_name = "#{handler_type}_model"
14
+ define_method(method_name) do |model_class|
15
+ if block_given?
16
+ bundle_model(klass, model_class){|model| yield(model)}
17
+ else
18
+ bundle_model(klass, model_class)
19
+ end
20
+ end
21
+ end
22
+
23
+ def bundle(resource_class, &block)
24
+ Application::RouteAdapter.new(resource_class, &block)
25
+ end
26
+
27
+ def bundle_typed_resource(resource_type, model_class, route_name)
28
+ resource_class = Resource::Handlers.registry.fetch(resource_type)
29
+ bundle(resource_class) do |resource, request, response|
30
+ resource.model = model_class.new(route_name, resource.params, services)
31
+ end
32
+ end
33
+
34
+ def bundle_traced_resource(resource_type, model_class, route_name)
35
+ resource_class = Resource::Handlers.registry.fetch(resource_type)
36
+ bundle(resource_class) do |resource, request, response|
37
+ resource.model = model_class.new(route_name, resource.params, services)
38
+ resource.trace = true
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end