agraph 0.1.0 → 0.1.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.
data/Rakefile CHANGED
@@ -9,8 +9,8 @@ task :default => :spec
9
9
 
10
10
  specification = Gem::Specification.new do |specification|
11
11
  specification.name = "agraph"
12
- specification.version = "0.1.0"
13
- specification.date = "2010-04-05"
12
+ specification.version = "0.1.1"
13
+ specification.date = "2010-07-05"
14
14
  specification.email = "b.phifty@gmail.com"
15
15
  specification.homepage = "http://github.com/phifty/agraph"
16
16
  specification.summary = "Client for the AllegroGraph 4.x graph database."
@@ -46,4 +46,4 @@ namespace :spec do
46
46
  task.spec_files = FileList["spec/integration/**/*_spec.rb"]
47
47
  end
48
48
 
49
- end
49
+ end
data/lib/allegro_graph.rb CHANGED
@@ -1,5 +1,14 @@
1
- require File.join(File.dirname(__FILE__), "allegro_graph", "server")
2
- require File.join(File.dirname(__FILE__), "allegro_graph", "catalog")
3
- require File.join(File.dirname(__FILE__), "allegro_graph", "repository")
4
- require File.join(File.dirname(__FILE__), "allegro_graph", "session")
5
- require File.join(File.dirname(__FILE__), "allegro_graph", "federation")
1
+
2
+ module AllegroGraph
3
+
4
+ autoload :Transport, File.join(File.dirname(__FILE__), "allegro_graph", "transport")
5
+ autoload :ExtendedTransport, File.join(File.dirname(__FILE__), "allegro_graph", "extended_transport")
6
+ autoload :Server, File.join(File.dirname(__FILE__), "allegro_graph", "server")
7
+ autoload :Catalog, File.join(File.dirname(__FILE__), "allegro_graph", "catalog")
8
+ autoload :Resource, File.join(File.dirname(__FILE__), "allegro_graph", "resource")
9
+ autoload :Repository, File.join(File.dirname(__FILE__), "allegro_graph", "repository")
10
+ autoload :Session, File.join(File.dirname(__FILE__), "allegro_graph", "session")
11
+ autoload :Proxy, File.join(File.dirname(__FILE__), "allegro_graph", "proxy")
12
+ autoload :Utility, File.join(File.dirname(__FILE__), "allegro_graph", "utility")
13
+
14
+ end
@@ -1,4 +1,3 @@
1
- require File.join(File.dirname(__FILE__), "repository")
2
1
 
3
2
  module AllegroGraph
4
3
 
@@ -0,0 +1,84 @@
1
+ require 'json'
2
+
3
+ module AllegroGraph
4
+
5
+ # Extended transport layer for http transfers. Basic authorization and JSON transfers are supported.
6
+ class ExtendedTransport < Transport
7
+
8
+ # The UnexpectedStatusCodeError is raised if the :expected_status_code option is given to
9
+ # the :request method and the responded status code is different from the expected one.
10
+ class UnexpectedStatusCodeError < StandardError
11
+
12
+ attr_reader :status_code
13
+ attr_reader :message
14
+
15
+ def initialize(status_code, message)
16
+ @status_code, @message = status_code, message
17
+ end
18
+
19
+ def to_s
20
+ "#{super} received status code #{self.status_code}" + (@message ? " [#{@message}]" : "")
21
+ end
22
+
23
+ end
24
+
25
+ attr_reader :expected_status_code
26
+ attr_reader :auth_type
27
+ attr_reader :username
28
+ attr_reader :password
29
+
30
+ def initialize(http_method, url, options = { })
31
+ super http_method, url, options
32
+ @expected_status_code = options[:expected_status_code]
33
+ @auth_type = options[:auth_type]
34
+ @username = options[:username]
35
+ @password = options[:password]
36
+ end
37
+
38
+ def perform
39
+ initialize_headers
40
+ super
41
+ check_status_code
42
+ parse_response
43
+ end
44
+
45
+ private
46
+
47
+ def initialize_headers
48
+ @headers["Accept"] = "application/json"
49
+ end
50
+
51
+ def initialize_request
52
+ super
53
+ if @auth_type == :basic
54
+ @request.basic_auth @username, @password
55
+ elsif !@auth_type.nil?
56
+ raise NotImplementedError, "the given auth_type [#{@auth_type}] is not implemented"
57
+ end
58
+ end
59
+
60
+ def initialize_request_body
61
+ super
62
+ if @body
63
+ @request.body = @body.to_json
64
+ @request["Content-Type"] = "application/json"
65
+ end
66
+ end
67
+
68
+ def check_status_code
69
+ return unless @expected_status_code
70
+ response_code = @response.code
71
+ response_body = @response.body
72
+ raise UnexpectedStatusCodeError.new(response_code.to_i, response_body) if @expected_status_code.to_s != response_code
73
+ end
74
+
75
+ def parse_response
76
+ body = @response.body
77
+ @response = body.nil? ? nil : JSON.parse(body)
78
+ rescue JSON::ParserError
79
+ @response = body.to_s
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module AllegroGraph
3
+
4
+ module Proxy
5
+
6
+ autoload :Statements, File.join(File.dirname(__FILE__), "proxy", "statements")
7
+ autoload :Query, File.join(File.dirname(__FILE__), "proxy", "query")
8
+ autoload :Geometric, File.join(File.dirname(__FILE__), "proxy", "geometric")
9
+ autoload :Mapping, File.join(File.dirname(__FILE__), "proxy", "mapping")
10
+
11
+ end
12
+
13
+ end
@@ -1,4 +1,3 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "utility", "parameter_mapper"))
2
1
 
3
2
  module AllegroGraph
4
3
 
@@ -1,33 +1,19 @@
1
- require File.join(File.dirname(__FILE__), "server")
2
- require File.join(File.dirname(__FILE__), "session")
3
- require File.join(File.dirname(__FILE__), "proxy", "statements")
4
- require File.join(File.dirname(__FILE__), "proxy", "query")
5
- require File.join(File.dirname(__FILE__), "proxy", "geometric")
6
- require File.join(File.dirname(__FILE__), "proxy", "mapping")
7
1
 
8
2
  module AllegroGraph
9
3
 
10
4
  # The Repository class wrap the corresponding resource on the AllegroGraph server. A repository acts as a scope for
11
5
  # statements. Simple management methods are provided.
12
- class Repository
6
+ class Repository < Resource
13
7
 
14
8
  attr_reader :server
15
9
  attr_reader :catalog
16
10
  attr_accessor :name
17
11
 
18
- attr_reader :statements
19
- attr_reader :query
20
- attr_reader :geometric
21
- attr_reader :mapping
22
-
23
- def initialize(server_or_catalog, name, options = { })
24
- @catalog = server_or_catalog.is_a?(AllegroGraph::Server) ? server_or_catalog.root_catalog : server_or_catalog
25
- @server = @catalog.server
26
- @name = name
27
- @statements = Proxy::Statements.new self
28
- @query = Proxy::Query.new self
29
- @geometric = Proxy::Geometric.new self
30
- @mapping = Proxy::Mapping.new self
12
+ def initialize(server_or_catalog, name)
13
+ super
14
+ @catalog = server_or_catalog.is_a?(AllegroGraph::Server) ? server_or_catalog.root_catalog : server_or_catalog
15
+ @server = @catalog.server
16
+ @name = name
31
17
  end
32
18
 
33
19
  def ==(other)
@@ -0,0 +1,22 @@
1
+
2
+ module AllegroGraph
3
+
4
+ # The Resource class acts as a base for statement resources. It provide proxy classes that provide methods
5
+ # to manipulate that statements.
6
+ class Resource
7
+
8
+ attr_reader :statements
9
+ attr_reader :query
10
+ attr_reader :geometric
11
+ attr_reader :mapping
12
+
13
+ def initialize(*arguments)
14
+ @statements = Proxy::Statements.new self
15
+ @query = Proxy::Query.new self
16
+ @geometric = Proxy::Geometric.new self
17
+ @mapping = Proxy::Mapping.new self
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -1,6 +1,3 @@
1
- require File.join(File.dirname(__FILE__), "transport")
2
- require File.join(File.dirname(__FILE__), "catalog")
3
- require File.join(File.dirname(__FILE__), "federation")
4
1
 
5
2
  module AllegroGraph
6
3
 
@@ -48,11 +45,6 @@ module AllegroGraph
48
45
  result
49
46
  end
50
47
 
51
- def federations
52
- federations = self.request :get, "/federated", :expected_status_code => 200
53
- federations.map { |federation| Federation.new self, federation["id"] }
54
- end
55
-
56
48
  def url
57
49
  "http://#{@host}:#{@port}"
58
50
  end
@@ -1,32 +1,18 @@
1
- require File.join(File.dirname(__FILE__), "transport")
2
- require File.join(File.dirname(__FILE__), "proxy", "statements")
3
- require File.join(File.dirname(__FILE__), "proxy", "query")
4
- require File.join(File.dirname(__FILE__), "proxy", "geometric")
5
- require File.join(File.dirname(__FILE__), "proxy", "mapping")
6
1
 
7
2
  module AllegroGraph
8
3
 
9
4
  # The Session class wrap the corresponding resource on the AllegroGraph server.
10
- class Session
5
+ class Session < Resource
11
6
 
12
7
  attr_reader :url
13
8
  attr_reader :username
14
9
  attr_reader :password
15
10
 
16
- attr_reader :statements
17
- attr_reader :query
18
- attr_reader :geometric
19
- attr_reader :mapping
20
-
21
11
  def initialize(options = { })
12
+ super
22
13
  @url = options[:url]
23
14
  @username = options[:username]
24
15
  @password = options[:password]
25
-
26
- @statements = Proxy::Statements.new self
27
- @query = Proxy::Query.new self
28
- @geometric = Proxy::Geometric.new self
29
- @mapping = Proxy::Mapping.new self
30
16
  end
31
17
 
32
18
  def path
@@ -1,7 +1,6 @@
1
1
  require 'uri'
2
2
  require 'cgi'
3
3
  require 'net/http'
4
- require 'json'
5
4
 
6
5
  module AllegroGraph
7
6
 
@@ -98,83 +97,4 @@ module AllegroGraph
98
97
 
99
98
  end
100
99
 
101
- # Extended transport layer for http transfers. Basic authorization and JSON transfers are supported.
102
- class ExtendedTransport < Transport
103
-
104
- # The UnexpectedStatusCodeError is raised if the :expected_status_code option is given to
105
- # the :request method and the responded status code is different from the expected one.
106
- class UnexpectedStatusCodeError < StandardError
107
-
108
- attr_reader :status_code
109
- attr_reader :message
110
-
111
- def initialize(status_code, message)
112
- @status_code, @message = status_code, message
113
- end
114
-
115
- def to_s
116
- "#{super} received status code #{self.status_code}" + (@message ? " [#{@message}]" : "")
117
- end
118
-
119
- end
120
-
121
- attr_reader :expected_status_code
122
- attr_reader :auth_type
123
- attr_reader :username
124
- attr_reader :password
125
-
126
- def initialize(http_method, url, options = { })
127
- super http_method, url, options
128
- @expected_status_code = options[:expected_status_code]
129
- @auth_type = options[:auth_type]
130
- @username = options[:username]
131
- @password = options[:password]
132
- end
133
-
134
- def perform
135
- initialize_headers
136
- super
137
- check_status_code
138
- parse_response
139
- end
140
-
141
- private
142
-
143
- def initialize_headers
144
- @headers["Accept"] = "application/json"
145
- end
146
-
147
- def initialize_request
148
- super
149
- if @auth_type == :basic
150
- @request.basic_auth @username, @password
151
- elsif !@auth_type.nil?
152
- raise NotImplementedError, "the given auth_type [#{@auth_type}] is not implemented"
153
- end
154
- end
155
-
156
- def initialize_request_body
157
- super
158
- if @body
159
- @request.body = @body.to_json
160
- @request["Content-Type"] = "application/json"
161
- end
162
- end
163
-
164
- def check_status_code
165
- return unless @expected_status_code
166
- response_code = @response.code
167
- response_body = @response.body
168
- raise UnexpectedStatusCodeError.new(response_code.to_i, response_body) if @expected_status_code.to_s != response_code
169
- end
170
-
171
- def parse_response
172
- body = @response.body
173
- @response = body.nil? ? nil : JSON.parse(body)
174
- rescue JSON::ParserError
175
- @response = body.to_s
176
- end
177
-
178
- end
179
-
180
100
  end
@@ -0,0 +1,10 @@
1
+
2
+ module AllegroGraph
3
+
4
+ module Utility
5
+
6
+ autoload :ParameterMapper, File.join(File.dirname(__FILE__), "utility", "parameter_mapper")
7
+
8
+ end
9
+
10
+ end
@@ -52,33 +52,6 @@
52
52
  :response:
53
53
  :code: "201"
54
54
  :body: ""
55
- -
56
- :http_method: "get"
57
- :url: "http://localhost:10035/federated"
58
- :response:
59
- :code: "200"
60
- :body:
61
- -
62
- "uri": "http://localhost:10035/federated/test_federation"
63
- "id": "test_federation"
64
- "title": "test_federation"
65
- "readable": true
66
- "writable": false
67
- -
68
- :http_method: "put"
69
- :url: "http://localhost:10035/federated/test_federation"
70
- :parameters:
71
- :repo: [ "test_repository" ]
72
- :url: [ "http://username:password@server:10035/repositories/another" ]
73
- :response:
74
- :code: "204"
75
- :body: ""
76
- -
77
- :http_method: "delete"
78
- :url: "http://localhost:10035/federated/test_federation"
79
- :response:
80
- :code: "204"
81
- :body: ""
82
55
  -
83
56
  :http_method: "get"
84
57
  :url: "http://localhost:10035/catalogs/test_catalog/repositories"
@@ -0,0 +1,137 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib", "allegro_graph"))
3
+
4
+ describe "geo-spatial data" do
5
+
6
+ use_real_transport!
7
+
8
+ before :each do
9
+ @server = AllegroGraph::Server.new :username => "test", :password => "test"
10
+ @repository = AllegroGraph::Repository.new @server, "test_repository"
11
+ @repository.create_if_missing!
12
+ @geometric = @repository.geometric
13
+ @statements = @repository.statements
14
+ end
15
+
16
+ describe "types" do
17
+
18
+ it "should provide a cartesian type" do
19
+ result = @geometric.cartesian_type :strip_width => 1.0,
20
+ :x_min => 2.0,
21
+ :y_min => 2.0,
22
+ :x_max => 20.0,
23
+ :y_max => 20.0
24
+ result.should == "<http://franz.com/ns/allegrograph/3.0/geospatial/cartesian/2.0/20.0/2.0/20.0/1.0>"
25
+ end
26
+
27
+ it "should provide a spherical type" do
28
+ result = @geometric.spherical_type :strip_width => 1.0,
29
+ :latitude_min => 2.0,
30
+ :longitude_min => 2.0,
31
+ :latitude_max => 20.0,
32
+ :longitude_max => 20.0
33
+ result.should == "<http://franz.com/ns/allegrograph/3.0/geospatial/spherical/degrees/2.0/20.0/2.0/20.0/1.0>"
34
+ end
35
+
36
+ end
37
+
38
+ describe "creating polygon" do
39
+
40
+ before :each do
41
+ @type = @geometric.cartesian_type :strip_width => 1.0,
42
+ :x_min => 2.0,
43
+ :y_min => 2.0,
44
+ :x_max => 20.0,
45
+ :y_max => 20.0
46
+ @polygon = [ [ 2.0, 2.0 ], [ 11.0, 2.0 ], [ 11.0, 11.0 ], [ 2.0, 11.0 ] ]
47
+ end
48
+
49
+ it "should return true" do
50
+ result = @geometric.create_polygon @polygon, :name => "test_polygon", :type => @type
51
+ result.should be_true
52
+ end
53
+
54
+ end
55
+
56
+ context "in a cartesian system" do
57
+
58
+ before :each do
59
+ @type = @geometric.cartesian_type :strip_width => 1.0,
60
+ :x_min => 2.0,
61
+ :y_min => 2.0,
62
+ :x_max => 20.0,
63
+ :y_max => 20.0
64
+ @statements.create "\"test_subject\"", "\"at\"", "\"+10+10\"^^#{@type}"
65
+ @statements.create "\"another_subject\"", "\"at\"", "\"+15+15\"^^#{@type}"
66
+ end
67
+
68
+ it "should find objects inside a box" do
69
+ result = @statements.find_inside_box :type => @type,
70
+ :predicate => "\"at\"",
71
+ :x_min => 8.0,
72
+ :y_min => 8.0,
73
+ :x_max => 11.0,
74
+ :y_max => 11.0
75
+ result.should include([ "\"test_subject\"", "\"at\"", "\"+10.000000000931323+10.000000000931323\"^^#{@type}"])
76
+ result.should_not include([ "\"another_subject\"", "\"at\"", "\"+15.000000000465661+15.000000000465661\"^^#{@type}"])
77
+ end
78
+
79
+ it "should find objects inside a circle" do
80
+ result = @statements.find_inside_circle :type => @type,
81
+ :predicate => "\"at\"",
82
+ :x => 9.0,
83
+ :y => 9.0,
84
+ :radius => 2.0
85
+ result.should include([ "\"test_subject\"", "\"at\"", "\"+10.000000000931323+10.000000000931323\"^^#{@type}"])
86
+ result.should_not include([ "\"another_subject\"", "\"at\"", "\"+15.000000000465661+15.000000000465661\"^^#{@type}"])
87
+ end
88
+
89
+ context "with a defined polygon" do
90
+
91
+ before :each do
92
+ @type = @geometric.cartesian_type :strip_width => 1,
93
+ :x_min => -100,
94
+ :y_min => -100,
95
+ :x_max => 100,
96
+ :y_max => 100
97
+ @statements.create "\"test_subject\"", "\"at\"", "\"+1+1\"^^#{@type}"
98
+ @geometric.create_polygon [ [ 0, -100 ], [ 0, 100 ], [ 100, 100 ], [ 100, -100 ] ],
99
+ :name => "test_polygon",
100
+ :type => @type
101
+ end
102
+
103
+ it "should find objects inside that polygon" do
104
+ result = @statements.find_inside_polygon :type => @type,
105
+ :predicate => "\"at\"",
106
+ :polygon_name => "test_polygon"
107
+ result.should include([ "\"test_subject\"", "\"at\"", "\"+0.9999999776482582+0.9999999776482582\"^^<http://franz.com/ns/allegrograph/3.0/geospatial/cartesian/-100.0/100.0/-100.0/100.0/1.0>"])
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+
114
+ context "in a spherical system" do
115
+
116
+ before :each do
117
+ @type = @geometric.spherical_type :strip_width => 1.0,
118
+ :latitude_min => 2.0,
119
+ :longitude_min => 2.0,
120
+ :latitude_max => 20.0,
121
+ :longitude_max => 20.0
122
+ @statements.create "\"test_subject\"", "\"at\"", "\"+10.00+010.00\"^^#{@type}"
123
+ end
124
+
125
+ it "should find objects inside a haversine" do
126
+ result = @statements.find_inside_haversine :type => @type,
127
+ :predicate => "\"at\"",
128
+ :latitude => 9.0,
129
+ :longitude => 9.0,
130
+ :radius => 200.0,
131
+ :unit => :km
132
+ result.should include([ "\"test_subject\"", "\"at\"", "\"+100000+0100000\"^^<http://franz.com/ns/allegrograph/3.0/geospatial/spherical/degrees/2.0/20.0/2.0/20.0/1.0>"])
133
+ end
134
+
135
+ end
136
+
137
+ end