rdf-agraph 0.3.0

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.
@@ -0,0 +1,29 @@
1
+ class RDF::AllegroGraph::Query
2
+ # A literal value which can be passed as an argument to a Prolog functor.
3
+ #
4
+ # @see @FunctorExpression
5
+ class PrologLiteral
6
+ # Constract a new Prolog literal.
7
+ #
8
+ # @param [Object] value A Ruby value.
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ # Serialize this literal as a string. We need to be careful about
14
+ # security here: Our callers might try to pass in untrustworthy values
15
+ # without thinking through the consequences, and we want to limit the
16
+ # damage. We assume that all symbols are trustworthy.
17
+ #
18
+ # @return [String]
19
+ def to_s
20
+ case @value
21
+ when Symbol, Numeric
22
+ @value.to_s
23
+ else
24
+ err = "Don't know how to serialize #{@value.inspect} securely"
25
+ raise ArgumentError.new(err)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,124 @@
1
+ module RDF::AllegroGraph
2
+
3
+ # A query with AllegroGraph-specific extensions.
4
+ #
5
+ # Note that many of of the more exotic features of this class can only be
6
+ # used when running Prolog queries against a Session object. This
7
+ # requires both elevated AllegroGraph privileges and dedicated back-end
8
+ # session resources on the server, so plan accordingly.
9
+ #
10
+ # The Functors module contains a wide variety of functors which may be
11
+ # used when building a Prolog query.
12
+ #
13
+ # @see AbstractRepository#build_query
14
+ # @see Functors
15
+ class Query < RDF::Query
16
+ autoload :PrologLiteral, 'rdf/allegro_graph/query/prolog_literal'
17
+ autoload :FunctorExpression, 'rdf/allegro_graph/query/functor_expression'
18
+
19
+ # Include our APIs.
20
+ include Functors::SnaFunctors
21
+
22
+ # Create a new query.
23
+ # @private
24
+ def initialize(repository, &block)
25
+ @repository = repository
26
+ super(&block)
27
+ end
28
+
29
+ # Run this query against the associated repository. This method exists
30
+ # solely to make the following API pleasant to use:
31
+ #
32
+ # repo.build_query do |q|
33
+ # q.pattern [:s, :p, :o]
34
+ # end.run do |solution|
35
+ # puts solution
36
+ # end
37
+ #
38
+ # Note that this function returns an Enumerator, not an array, because
39
+ # RDF.rb is committed to streaming results gradually. If you want to
40
+ # treat the result as an array, call 'to_a' explicitly:
41
+ #
42
+ # solutions = repo.build_query do |q|
43
+ # q.pattern [:s, :p, :o]
44
+ # end.run.to_a
45
+ #
46
+ # If you forget to do this, you will run a new query each time you
47
+ # attempt to iterate over the solutions!
48
+ #
49
+ # @overload run
50
+ # @return [Enumerator<RDF::Query::Solution>]
51
+ #
52
+ # @overload run
53
+ # @yield solution
54
+ # @yieldparam [RDF::Query::Solution]
55
+ # @yieldreturn [void]
56
+ # @return [void]
57
+ #
58
+ # @see Repository#query
59
+ # @note This function returns a single-use Enumerator! If you want to
60
+ # to treat the results as an array, call `to_a` on it, or you will
61
+ # re-run the query against the server repeatedly. This curious
62
+ # decision is made for consistency with RDF.rb.
63
+ def run(&block)
64
+ @repository.query(self, &block)
65
+ end
66
+
67
+ # Add a functor expression to this query. Functors can only be used
68
+ # in Prolog queries.
69
+ #
70
+ # @param [String] name
71
+ # @param [Array<Symbol,RDF::Value,value>] arguments
72
+ # The arguments to the functor, which may be either variables,
73
+ # RDF::Value objects, or Ruby values that we can convert to literals.
74
+ # @return [void]
75
+ def functor(name, *arguments)
76
+ # TODO: Don't abuse duck-typing quite so much.
77
+ patterns <<
78
+ RDF::AllegroGraph::Query::FunctorExpression.new(name, *arguments)
79
+ end
80
+
81
+ # Does this query contain Prolog-specific functors that we can't
82
+ # represent as SPARQL?
83
+ #
84
+ # @return [Boolean]
85
+ def requires_prolog?
86
+ !patterns.all? {|p| p.kind_of?(RDF::Query::Pattern) }
87
+ end
88
+
89
+ # Convert this query to AllegoGraph Prolog notation.
90
+ #
91
+ # @param [RDF::AllegroGraph::Repository] repository
92
+ # @return [String]
93
+ # @private
94
+ def to_prolog(repository)
95
+ variables = []
96
+ functors = []
97
+ patterns.each do |p|
98
+ # Extract any new variables we see in the query.
99
+ p.variables.each {|_,v| variables << v unless variables.include?(v) }
100
+ functors << convert_to_functor(p).to_prolog(repository)
101
+ end
102
+ "(select (#{variables.join(" ")})\n #{functors.join("\n ")})"
103
+ end
104
+
105
+ protected
106
+
107
+ # Convert patterns to functors (and leave functors unchanged).
108
+ #
109
+ # @param [RDF::Query::Pattern,FunctorExpression] pattern_or_functor
110
+ # @return [FunctorExpression]
111
+ # @private
112
+ def convert_to_functor(pattern_or_functor)
113
+ case pattern_or_functor
114
+ when FunctorExpression then pattern_or_functor
115
+ else
116
+ p = pattern_or_functor
117
+ if p.optional? || p.context
118
+ raise ArgumentError.new("Can't translate #{p} to Prolog functor")
119
+ end
120
+ FunctorExpression.new('q-', p.subject, p.predicate, p.object)
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,81 @@
1
+ require 'pathname'
2
+
3
+ module RDF::AllegroGraph
4
+ # An AllegroGraph RDF repository.
5
+ #
6
+ # Note that this class does not interoperate well with the Unix `fork`
7
+ # command if you're using blank nodes. See README.md for details.
8
+ class Repository < AbstractRepository
9
+ # Create a new AllegroGraph repository adapter.
10
+ #
11
+ # @overload initialize(options)
12
+ # @param [Hash{Symbol => Object}] options
13
+ # @option options [Server] :server The server hosting the repository.
14
+ # @option options [String] :id The name of the repository.
15
+ # @option options [Boolean] :create Create the repository if necessary?
16
+ #
17
+ # @overload initialize(url, options)
18
+ # @param [String] url The URL of the repository.
19
+ # @param [Hash{Symbol => Object}] options
20
+ # @option options [Boolean] :create Create the repository if necessary?
21
+ def initialize(url_or_options, options={})
22
+ case url_or_options
23
+ when String
24
+ # TODO: Clean this up.
25
+ url = URI.parse(url_or_options)
26
+ path = Pathname.new(url.path)
27
+ url.path = path.parent.parent.to_s
28
+ server = Server.new(url.to_s).server
29
+ id = path.basename
30
+ else
31
+ server = url_or_options[:server].server
32
+ id = url_or_options[:id]
33
+ options = url_or_options
34
+ end
35
+ super(::AllegroGraph::Repository.new(server, id))
36
+ @repo.create_if_missing! if options[:create]
37
+ end
38
+
39
+ # Delete this repository if it exists.
40
+ #
41
+ # @return [void]
42
+ def delete!
43
+ @repo.delete!
44
+ end
45
+
46
+ # Create a new, persistent AllegroGraph session. If called without a
47
+ # block, simply returns the new session (and expects the caller to
48
+ # close it). If called with a block, automatically commits or rolls
49
+ # back the transaction, and closes the session.
50
+ #
51
+ # @overload session
52
+ # @return [Session] The newly created session. It's a good idea to
53
+ # close this manually; doing so frees up server resources.
54
+ # @see Session#commit
55
+ # @see Session#rollback
56
+ # @see Session#close
57
+ #
58
+ # @overload session
59
+ # @yield session
60
+ # @yieldparam [Session] session
61
+ # @yieldreturn [Object]
62
+ # @return [Object] The result returned from the block.
63
+ def session
64
+ if block_given?
65
+ session = Session.new(@repo)
66
+ begin
67
+ result = yield session
68
+ session.commit
69
+ result
70
+ rescue => e
71
+ session.rollback
72
+ raise
73
+ ensure
74
+ session.close
75
+ end
76
+ else
77
+ Session.new(@repo)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,93 @@
1
+ module RDF::AllegroGraph
2
+ # An AllegroGraph server containing several repositories. We attempt to
3
+ # mimic the public API of RDF::Sesame::Server for the sake of
4
+ # convenience, though we do not implement several internal methods, and
5
+ # we generally attempt to raise errors when we can't connect to the
6
+ # server, unlike RDF::Sesame::Server, which just returns default values.
7
+ #
8
+ # @see RDF::Sesame::Server
9
+ class Server
10
+ attr_reader :server # @private
11
+
12
+ # Create a new Server object.
13
+ #
14
+ # @param [String] url The Sesame URL of the AllegroGraph server.
15
+ def initialize(url="http://localhost:10035")
16
+ parsed = URI.parse(url)
17
+ options = {
18
+ :host => parsed.host, :post => parsed.port,
19
+ :username => parsed.user, :password => parsed.password
20
+ }
21
+ @server = AllegroGraph::Server.new(options)
22
+
23
+ unless parsed.path.nil? || parsed.path.empty? || parsed.path == "/"
24
+ err = "AllegroGraph URLs with paths not supported: #{url}"
25
+ raise ArgumentError.new(err)
26
+ end
27
+ end
28
+
29
+ # Get the protocol version supported by this server.
30
+ #
31
+ # @return [Integer]
32
+ def protocol
33
+ @server.request_http(:get, path(:protocol),
34
+ :expected_status_code => 200).to_i
35
+ end
36
+ alias_method :protocol_version, :protocol
37
+
38
+ # Return a hash table of all repositories on this server.
39
+ #
40
+ # @return [Hash<String,Repository>]
41
+ def repositories
42
+ result = {}
43
+ @server.request_json(:get, path(:repositories),
44
+ :expected_status_code => 200).each do |repo|
45
+ result[repo['id']] = Repository.new(:server => self, :id => repo['id'])
46
+ end
47
+ result
48
+ end
49
+
50
+ # Return true if the specified repository exists on the server.
51
+ #
52
+ # @param [String] id The name of the repository.
53
+ # @return [Boolean]
54
+ def has_repository?(id)
55
+ repositories.has_key?(id)
56
+ end
57
+
58
+ # Iterate over all repositories.
59
+ #
60
+ # @yield repository
61
+ # @yieldparam [Repository] repository
62
+ # @yieldreturn [void]
63
+ # @return [void]
64
+ def each_repository(&block)
65
+ repositories.values.each(&block)
66
+ end
67
+ alias_method :each, :each_repository
68
+
69
+ # Look up a specific repository by name, and optionally create it.
70
+ #
71
+ # @param [String] id The name of the repository.
72
+ # @param [Hash] options
73
+ # @option options [Boolean] :create
74
+ # If true, and the repository does not exist, create it.
75
+ # @return [Repository,nil]
76
+ # The repository, if it exists or was created, or nil otherwise.
77
+ def repository(id, options={})
78
+ result = repositories[id]
79
+ if result.nil? && options[:create]
80
+ result = Repository.new(:server => self, :id => id, :create => true)
81
+ end
82
+ result
83
+ end
84
+ alias_method :[], :repository
85
+
86
+ protected
87
+
88
+ # Generate a path to a resource on the server.
89
+ def path(relativate_path) # @private
90
+ "/#{relativate_path}"
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,78 @@
1
+ module RDF::AllegroGraph
2
+
3
+ # A persistent AllegroGraph session. This takes up more server resources
4
+ # than a normal stateless repository connection, but it allows access to
5
+ # advanced AllegroGraph features.
6
+ #
7
+ # Note that this class does not interoperate well with the Unix `fork`
8
+ # command if you're using blank nodes. See README.md for details.
9
+ #
10
+ # @see Repository#session
11
+ class Session < AbstractRepository
12
+ # Create a new session. This parameter takes an
13
+ # ::AllegroGraph::Repository object as an argument, so we've not going
14
+ # to document it publically.
15
+ #
16
+ # @private
17
+ def initialize(agraph_repo)
18
+ super(::AllegroGraph::Session.create(agraph_repo))
19
+ @last_unique_id = 0
20
+ end
21
+
22
+ # Explicitly close the current session and release all server resources.
23
+ # This function does _not_ commit any outstanding transactions.
24
+ #
25
+ # @return [void]
26
+ # @see #commit
27
+ # @see #rollback
28
+ def close
29
+ @repo.request_http(:post, path('session/close'),
30
+ :expected_status_code => 204)
31
+ end
32
+
33
+ # Commit the current changes to the main repository.
34
+ #
35
+ # @return [void]
36
+ # @see #rollback
37
+ def commit
38
+ @repo.commit
39
+ end
40
+
41
+ # Roll back the changes made since the last commit.
42
+ #
43
+ # @return [void]
44
+ # @see #commit
45
+ def rollback
46
+ @repo.rollback
47
+ end
48
+
49
+ # Define an SNA generator.
50
+ #
51
+ # @param [Hash] options
52
+ # @option options [RDF::Resource,Array<RDF::Resource>] :object_of
53
+ # Follow links defined by specified predicates.
54
+ # @option options [RDF::Resource,Array<RDF::Resource>] :subject_of
55
+ # Follow links defined by specified predicates, but from the object
56
+ # to the subject.
57
+ # @option options [RDF::Resource,Array<RDF::Resource>] :undirected
58
+ # Follow links defined by specified predicates in both directions.
59
+ # @return [Query::PrologLiteral]
60
+ # A value which may be used in Prolog queries.
61
+ #
62
+ # @see Query#ego_group_member
63
+ def generator(options)
64
+ id = unique_id
65
+ generator = SnaGenerator.new(self, options)
66
+ @repo.request_json(:put, path("snaGenerators/#{id}"),
67
+ :parameters => generator.to_params,
68
+ :expected_status_code => 204)
69
+ Query::PrologLiteral.new(id.to_sym)
70
+ end
71
+
72
+ protected
73
+
74
+ def unique_id
75
+ "id#{@last_unique_id += 1}"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,37 @@
1
+ module RDF::AllegroGraph
2
+ # Internal helper class for defining SNA generators.
3
+ #
4
+ # @private
5
+ class SnaGenerator
6
+ attr_reader :options
7
+
8
+ def initialize(repository, options)
9
+ @repository = repository
10
+ @options = options
11
+ end
12
+
13
+ def to_params
14
+ params = {}
15
+ params.merge!(option_to_hash(:objectOf, :object_of))
16
+ params.merge!(option_to_hash(:subjectOf, :subject_of))
17
+ params.merge!(option_to_hash(:undirected, :undirected))
18
+ params
19
+ end
20
+
21
+ protected
22
+
23
+ def option_to_hash(param_name, option_name)
24
+ if @options.has_key?(option_name)
25
+ value = @options[option_name]
26
+ case value
27
+ when Array
28
+ { param_name => value.map {|v| @repository.serialize(v) } }
29
+ else
30
+ { param_name => @repository.serialize(value) }
31
+ end
32
+ else
33
+ {}
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ require 'rdf'
2
+ require 'agraph'
3
+ require 'enumerator'
4
+
5
+ # AllegroGraph integration for RDF.rb.
6
+ module RDF::AllegroGraph
7
+ autoload :Query, 'rdf/allegro_graph/query'
8
+ autoload :Server, 'rdf/allegro_graph/server'
9
+ autoload :AbstractRepository, 'rdf/allegro_graph/abstract_repository'
10
+ autoload :Repository, 'rdf/allegro_graph/repository'
11
+ autoload :SnaGenerator, 'rdf/allegro_graph/sna_generator'
12
+ autoload :Functors, 'rdf/allegro_graph/functors'
13
+ autoload :Session, 'rdf/allegro_graph/session'
14
+ end
data/lib/rdf-agraph.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'rdf/allegro_graph'
2
+
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdf-agraph
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
+ platform: ruby
12
+ authors:
13
+ - Eric Kidd
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-18 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rdf
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 17
30
+ segments:
31
+ - 0
32
+ - 3
33
+ - 1
34
+ version: 0.3.1
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: agraph
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 19
46
+ segments:
47
+ - 0
48
+ - 1
49
+ - 4
50
+ version: 0.1.4
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: json
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 9
62
+ segments:
63
+ - 0
64
+ - 5
65
+ - 1
66
+ version: 0.5.1
67
+ type: :runtime
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdf-spec
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ hash: 17
78
+ segments:
79
+ - 0
80
+ - 3
81
+ - 1
82
+ version: 0.3.1
83
+ type: :development
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: yard
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 7
94
+ segments:
95
+ - 0
96
+ - 6
97
+ - 0
98
+ version: 0.6.0
99
+ type: :development
100
+ version_requirements: *id005
101
+ - !ruby/object:Gem::Dependency
102
+ name: BlueCloth
103
+ prerelease: false
104
+ requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 21
110
+ segments:
111
+ - 1
112
+ - 0
113
+ - 1
114
+ version: 1.0.1
115
+ type: :development
116
+ version_requirements: *id006
117
+ - !ruby/object:Gem::Dependency
118
+ name: rspec
119
+ prerelease: false
120
+ requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ hash: 27
126
+ segments:
127
+ - 2
128
+ - 5
129
+ - 0
130
+ version: 2.5.0
131
+ type: :development
132
+ version_requirements: *id007
133
+ - !ruby/object:Gem::Dependency
134
+ name: rcov
135
+ prerelease: false
136
+ requirement: &id008 !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ hash: 41
142
+ segments:
143
+ - 0
144
+ - 9
145
+ - 9
146
+ version: 0.9.9
147
+ type: :development
148
+ version_requirements: *id008
149
+ - !ruby/object:Gem::Dependency
150
+ name: rake
151
+ prerelease: false
152
+ requirement: &id009 !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ hash: 49
158
+ segments:
159
+ - 0
160
+ - 8
161
+ - 7
162
+ version: 0.8.7
163
+ type: :development
164
+ version_requirements: *id009
165
+ description: An AllegroGraph adapter for use with RDF.rb.
166
+ email: rdf-agraph@kiddsoftware.com
167
+ executables: []
168
+
169
+ extensions: []
170
+
171
+ extra_rdoc_files: []
172
+
173
+ files:
174
+ - AUTHORS
175
+ - README.md
176
+ - UNLICENSE
177
+ - VERSION
178
+ - lib/rdf-agraph.rb
179
+ - lib/rdf/allegro_graph.rb
180
+ - lib/rdf/allegro_graph/server.rb
181
+ - lib/rdf/allegro_graph/functors.rb
182
+ - lib/rdf/allegro_graph/functors/sna_functors.rb
183
+ - lib/rdf/allegro_graph/repository.rb
184
+ - lib/rdf/allegro_graph/query.rb
185
+ - lib/rdf/allegro_graph/abstract_repository.rb
186
+ - lib/rdf/allegro_graph/query/functor_expression.rb
187
+ - lib/rdf/allegro_graph/query/prolog_literal.rb
188
+ - lib/rdf/allegro_graph/sna_generator.rb
189
+ - lib/rdf/allegro_graph/session.rb
190
+ has_rdoc: false
191
+ homepage: http://rdf-agraph.rubyforge.org/
192
+ licenses:
193
+ - Public Domain
194
+ post_install_message:
195
+ rdoc_options: []
196
+
197
+ require_paths:
198
+ - lib
199
+ required_ruby_version: !ruby/object:Gem::Requirement
200
+ none: false
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ hash: 57
205
+ segments:
206
+ - 1
207
+ - 8
208
+ - 7
209
+ version: 1.8.7
210
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
+ none: false
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ hash: 3
216
+ segments:
217
+ - 0
218
+ version: "0"
219
+ requirements: []
220
+
221
+ rubyforge_project: rdf-agraph
222
+ rubygems_version: 1.5.2
223
+ signing_key:
224
+ specification_version: 3
225
+ summary: AllegroGraph adapter for RDF.rb
226
+ test_files: []
227
+