active-triples 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +7 -3
- data/CHANGES.md +20 -0
- data/Gemfile +2 -0
- data/README.md +21 -17
- data/lib/active_triples.rb +6 -1
- data/lib/active_triples/configurable.rb +18 -19
- data/lib/active_triples/configuration.rb +72 -0
- data/lib/active_triples/configuration/item.rb +20 -0
- data/lib/active_triples/configuration/item_factory.rb +27 -0
- data/lib/active_triples/configuration/merge_item.rb +14 -0
- data/lib/active_triples/identifiable.rb +3 -3
- data/lib/active_triples/list.rb +6 -4
- data/lib/active_triples/property_builder.rb +10 -2
- data/lib/active_triples/rdf_source.rb +582 -0
- data/lib/active_triples/{term.rb → relation.rb} +40 -15
- data/lib/active_triples/resource.rb +9 -534
- data/lib/active_triples/version.rb +1 -1
- data/spec/active_triples/configurable_spec.rb +18 -2
- data/spec/active_triples/configuration_spec.rb +59 -0
- data/spec/active_triples/identifiable_spec.rb +12 -11
- data/spec/active_triples/list_spec.rb +13 -7
- data/spec/active_triples/nested_attributes_spec.rb +12 -6
- data/spec/active_triples/properties_spec.rb +19 -1
- data/spec/active_triples/rdf_source_spec.rb +5 -0
- data/spec/active_triples/{term_spec.rb → relation_spec.rb} +9 -7
- data/spec/active_triples/repositories_spec.rb +7 -4
- data/spec/active_triples/resource_spec.rb +24 -26
- data/spec/active_triples_spec.rb +9 -0
- data/spec/pragmatic_context_spec.rb +6 -4
- data/spec/spec_helper.rb +1 -0
- metadata +14 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4dc6967bd4ea18668b379926f3504e0c67c5135
|
4
|
+
data.tar.gz: c75e487fcf484d7e1f91a7a919ac9c56c2728c1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d548a15c50003b4625c33283399bd8d101edceec9671658012b1702cead051c7230188afe2a6100feb9bd93c3a08204bbd4395266fec6aebc071863e3e647b28
|
7
|
+
data.tar.gz: c2a1f637cd7a4edf4a9a3eb3fd78fcbf143e964561d6648d674353575a4c5312aee21f8502de003b4ae1a4bbb4c7f13760eabbdfe35d126ef9f312e9efd14775
|
data/.travis.yml
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
anguage: ruby
|
2
2
|
bundler_args: --without debug
|
3
3
|
script: "bundle exec rspec spec"
|
4
|
+
sudo: false
|
5
|
+
cache: bundler
|
4
6
|
rvm:
|
5
|
-
- 1.9.3
|
6
7
|
- 2.0.0
|
7
8
|
- 2.1.0
|
8
9
|
- 2.1.1
|
9
|
-
-
|
10
|
+
- 2.2.1
|
11
|
+
- ruby-head
|
12
|
+
- jruby
|
13
|
+
- rbx-2
|
10
14
|
matrix:
|
11
15
|
allow_failures:
|
12
|
-
- rvm: jruby
|
16
|
+
- rvm: jruby
|
data/CHANGES.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
0.7.0
|
2
|
+
-----
|
3
|
+
|
4
|
+
__ATTN: This release withdraws support for Ruby 1.9__
|
5
|
+
|
6
|
+
- Removes `#solrize` which was a badly named holdever from the
|
7
|
+
ActiveFedroa days.
|
8
|
+
- Fixes a bug on properties defined without a predicate. They are now
|
9
|
+
rejected.
|
10
|
+
- Disallows setting properties on the `ActiveTriples::Resource` base
|
11
|
+
class directly. This kind of property setting is unintended and
|
12
|
+
resulted in unexpected behavior.
|
13
|
+
- Introduces `ActiveTriples::RDFSource` as a mixin module for which
|
14
|
+
forms the basis of `Resource`.
|
15
|
+
- Use of this module is now preferred to single inheritance of the
|
16
|
+
`Resource` base class.
|
17
|
+
- `Resource` will remain indefinitely as the generic model.
|
18
|
+
- Renamed `Term` to `Relation`. `Term` is deprecated for removal in
|
19
|
+
the next minor release.
|
20
|
+
- Allow configuration of multiple `rdf:type`s.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -5,7 +5,7 @@ Description
|
|
5
5
|
[![Coverage Status](https://coveralls.io/repos/ActiveTriples/ActiveTriples/badge.png?branch=master)](https://coveralls.io/r/ActiveTriples/ActiveTriples?branch=master)
|
6
6
|
[![Gem Version](https://badge.fury.io/rb/active-triples.svg)](http://badge.fury.io/rb/active-triples)
|
7
7
|
|
8
|
-
An ActiveModel-like interface for RDF data. Models graphs as
|
8
|
+
An ActiveModel-like interface for RDF data. Models graphs as RDFSources with property/attribute configuration, accessors, and other methods to support Linked Data in a Ruby/Rails enviornment. See [RDF Concepts and Abstract Syntax](http://www.w3.org/TR/2014/REC-rdf11-concepts-20140225/#change-over-time) for an informal definition of an RDF Source.
|
9
9
|
|
10
10
|
This library was extracted from work on [ActiveFedora](https://github.com/projecthydra/active_fedora). It is closely related to (and borrows some syntax from) [Spira](https://github.com/ruby-rdf/spira), but does some important things differently.
|
11
11
|
|
@@ -16,14 +16,15 @@ Add `gem "active-triples"` to your Gemfile and run `bundle`.
|
|
16
16
|
|
17
17
|
Or install manually with `gem install active-triples`.
|
18
18
|
|
19
|
-
Defining
|
20
|
-
|
19
|
+
Defining RDFSource Models
|
20
|
+
-------------------------
|
21
21
|
|
22
|
-
The core
|
22
|
+
The core module of `ActiveTriples` is `ActiveTriples::RDFSource`. You can use this module as a mixin to create ActiveModel-like classes that represent an RDF resource as a stateful entity represented by an `RDF::Graph`. `RDFSource` implements the `RDF::Resource` interface, as well as `RDF::Queryable`, `RDF::Enumerable`, and `RDF::Mutable`. This means you can manipulate them by adding or deleting statements, query, serialize, and load arbitrary RDF.
|
23
23
|
|
24
24
|
|
25
25
|
```ruby
|
26
|
-
class Thing
|
26
|
+
class Thing
|
27
|
+
include ActiveTriples::RDFSource
|
27
28
|
configure :type => RDF::OWL.Thing, :base_uri => 'http://example.org/things#'
|
28
29
|
property :title, :predicate => RDF::DC.title
|
29
30
|
property :description, :predicate => RDF::DC.description
|
@@ -34,12 +35,13 @@ obj.title = 'Resource'
|
|
34
35
|
obj.description = 'A resource.'
|
35
36
|
obj.dump :ntriples # => "<http://example.org/things#123> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Thing> .\n<http://example.org/things#123> <http://purl.org/dc/terms/title> \"Resource\" .\n<http://example.org/things#123> <http://purl.org/dc/terms/description> \"A resource.\" .\n"
|
36
37
|
```
|
37
|
-
URI and bnode values are built out as Resources when accessed
|
38
|
+
URI and bnode values are built out as generic Resources when accessed. A more specific model class can be configured on individual properties.
|
38
39
|
|
39
40
|
```ruby
|
40
41
|
Thing.property :creator, :predicate => RDF::DC.creator, :class_name => 'Person'
|
41
42
|
|
42
|
-
class Person
|
43
|
+
class Person
|
44
|
+
include ActiveTriples::RDFSource
|
43
45
|
configure :type => RDF::FOAF.Person, :base_uri => 'http://example.org/people#'
|
44
46
|
property :name, :predicate => RDF::FOAF.name
|
45
47
|
end
|
@@ -56,24 +58,24 @@ obj_2.dump :ntriples # => "<http://example.org/things#2> <http://www.w3.org/1999
|
|
56
58
|
Open Model
|
57
59
|
-----------
|
58
60
|
|
59
|
-
|
61
|
+
An RDFSource lets you handle data as a graph, independent of whether it is defined in the model. This is important for working in a Linked Data context, where you will want access to data you may not have known about when your models were written.
|
60
62
|
|
61
63
|
```ruby
|
62
64
|
related = Thing.new
|
63
65
|
|
64
66
|
related << RDF::Statement(related, RDF::DC.relation, obj)
|
65
67
|
related << RDF::Statement(related, RDF::DC.subject, 'ActiveTriples')
|
66
|
-
|
68
|
+
|
67
69
|
related.query(:subject => related, :predicate => RDF::DC.relation).each_statement {|s,p,o| puts o}
|
68
70
|
# => http://example.org/things#123
|
69
71
|
related.query(:subject => subject, :predicate => RDF::DC.relation).each_statement {|s,p,o| puts o}
|
70
72
|
# => http://example.org/things#123
|
71
73
|
```
|
72
74
|
|
73
|
-
Any operation you can run against an RDF::Graph works with
|
75
|
+
Any operation you can run against an RDF::Graph works with RDFSources, too. Or you can use generic setters and getters with URI predicates:
|
74
76
|
|
75
77
|
```ruby
|
76
|
-
related.set_value(RDF::DC.relation, obj)
|
78
|
+
related.set_value(RDF::DC.relation, obj)
|
77
79
|
related.set_value(RDF::DC.subject, 'ActiveTriples')
|
78
80
|
|
79
81
|
related.get_values(RDF::DC.relation) # => [#<Thing:0x3f949c6a2294(default)>]
|
@@ -81,7 +83,7 @@ related.get_values(RDF::DC.subject) # => ["ActiveTriples"]
|
|
81
83
|
```
|
82
84
|
|
83
85
|
Some convienience methods provide support for handling data from web sources:
|
84
|
-
* `fetch` loads data from the
|
86
|
+
* `fetch` loads data from the RDFSource's #rdf_subject URI
|
85
87
|
* `rdf_label` queries across common (& configured) label fields and returning the best match
|
86
88
|
|
87
89
|
```ruby
|
@@ -115,10 +117,10 @@ Data is cast back to the appropriate class when it is accessed.
|
|
115
117
|
my_thing.date
|
116
118
|
# => [Thu, 19 Jun 2014]
|
117
119
|
```
|
118
|
-
|
120
|
+
|
119
121
|
Note that you can mix types on a single property.
|
120
122
|
|
121
|
-
```ruby
|
123
|
+
```ruby
|
122
124
|
my_thing.date << DateTime.now
|
123
125
|
my_thing.date << "circa 2014"
|
124
126
|
my_thing.date
|
@@ -143,12 +145,15 @@ Resources can persist to various databases and triplestores though integration w
|
|
143
145
|
ActiveTriples::Repositories.add_repository :default, RDF::Repository.new
|
144
146
|
ActiveTriples::Repositories.add_repository :people, RDF::Repository.new
|
145
147
|
|
146
|
-
class Person
|
148
|
+
class Person
|
149
|
+
include ActiveTriples::RDFSource
|
147
150
|
configure :type => RDF::FOAF.Person, :base_uri => 'http://example.org/people#', :repository => :people
|
148
151
|
property :name, :predicate => RDF::FOAF.name
|
149
152
|
end
|
150
153
|
|
151
|
-
class Thing
|
154
|
+
class Thing
|
155
|
+
include ActiveTriples::RDFSource
|
156
|
+
|
152
157
|
configure :type => RDF::OWL.Thing, :base_uri => 'http://example.org/things#', :repository => :default
|
153
158
|
property :title, :predicate => RDF::DC.title
|
154
159
|
property :description, :predicate => RDF::DC.description
|
@@ -183,4 +188,3 @@ Please observe the following guidelines:
|
|
183
188
|
- Organize your commits into logical units.
|
184
189
|
- Don't leave trailing whitespace (i.e. run ```git diff --check``` before committing).
|
185
190
|
- Use [well formed](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) commit messages.
|
186
|
-
|
data/lib/active_triples.rb
CHANGED
@@ -5,9 +5,10 @@ require 'active_support'
|
|
5
5
|
module ActiveTriples
|
6
6
|
extend ActiveSupport::Autoload
|
7
7
|
eager_autoload do
|
8
|
+
autoload :RDFSource
|
8
9
|
autoload :Resource
|
9
10
|
autoload :List
|
10
|
-
autoload :
|
11
|
+
autoload :Relation
|
11
12
|
autoload :Configurable
|
12
13
|
autoload :Properties
|
13
14
|
autoload :PropertyBuilder
|
@@ -16,6 +17,10 @@ module ActiveTriples
|
|
16
17
|
autoload :NodeConfig
|
17
18
|
autoload :NestedAttributes
|
18
19
|
autoload :Identifiable
|
20
|
+
autoload :Configuration
|
21
|
+
|
22
|
+
# deprecated class
|
23
|
+
autoload :Term, 'active_triples/relation'
|
19
24
|
end
|
20
25
|
|
21
26
|
# Raised when a declared repository doesn't have a definition
|
@@ -12,17 +12,20 @@ module ActiveTriples
|
|
12
12
|
# Available properties are base_uri, rdf_label, type, and repository
|
13
13
|
module Configurable
|
14
14
|
extend Deprecation
|
15
|
-
|
16
15
|
def base_uri
|
17
|
-
|
16
|
+
configuration[:base_uri]
|
18
17
|
end
|
19
18
|
|
20
19
|
def rdf_label
|
21
|
-
|
20
|
+
configuration[:rdf_label]
|
22
21
|
end
|
23
22
|
|
24
23
|
def type
|
25
|
-
|
24
|
+
configuration[:type]
|
25
|
+
end
|
26
|
+
|
27
|
+
def configuration
|
28
|
+
@configuration ||= Configuration.new
|
26
29
|
end
|
27
30
|
|
28
31
|
##
|
@@ -33,7 +36,7 @@ module ActiveTriples
|
|
33
36
|
end
|
34
37
|
|
35
38
|
def repository
|
36
|
-
:parent
|
39
|
+
configuration[:repository] || :parent
|
37
40
|
end
|
38
41
|
|
39
42
|
##
|
@@ -52,24 +55,20 @@ module ActiveTriples
|
|
52
55
|
#
|
53
56
|
# @param options [Hash]
|
54
57
|
def configure(options = {})
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
type: options[:type],
|
59
|
-
repository: options[:repository]
|
60
|
-
}.each do |name, value|
|
61
|
-
if value
|
62
|
-
value = self.send("transform_#{name}", value) if self.respond_to?("transform_#{name}")
|
63
|
-
define_singleton_method(name) do
|
64
|
-
value
|
65
|
-
end
|
58
|
+
options = options.map do |key, value|
|
59
|
+
if self.respond_to?("transform_#{key}")
|
60
|
+
value = self.__send__("transform_#{key}", value)
|
66
61
|
end
|
62
|
+
[key, value]
|
67
63
|
end
|
64
|
+
@configuration = configuration.merge(options)
|
68
65
|
end
|
69
66
|
|
70
|
-
def transform_type(
|
71
|
-
|
72
|
-
|
67
|
+
def transform_type(values)
|
68
|
+
Array(values).map do |value|
|
69
|
+
RDF::URI.new(value).tap do |uri|
|
70
|
+
Resource.type_registry[uri] = self
|
71
|
+
end
|
73
72
|
end
|
74
73
|
end
|
75
74
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ActiveTriples
|
2
|
+
require_relative 'configuration/item'
|
3
|
+
require_relative 'configuration/merge_item'
|
4
|
+
require_relative 'configuration/item_factory'
|
5
|
+
##
|
6
|
+
# Class which contains configuration for RDFSources.
|
7
|
+
class Configuration
|
8
|
+
attr_accessor :inner_hash
|
9
|
+
# @param [Hash] options the configuration options.
|
10
|
+
def initialize(options={})
|
11
|
+
@inner_hash = Hash[options.to_a]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Merges this configuration with other configuration options. This uses
|
15
|
+
# reflection setters to handle special cases like :type.
|
16
|
+
#
|
17
|
+
# @param [Hash] options configuration options to merge in.
|
18
|
+
# @return [ActiveTriples::Configuration] the configuration object which is a
|
19
|
+
# result of merging.
|
20
|
+
def merge(options)
|
21
|
+
new_config = Configuration.new(options)
|
22
|
+
new_config.items.each do |property, item|
|
23
|
+
build_configuration_item(property).set item.value
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a hash with keys as the configuration property and values as
|
29
|
+
# reflections which know how to set a new value to it.
|
30
|
+
#
|
31
|
+
# @return [Hash{Symbol => ActiveTriples::Configuration::Item}]
|
32
|
+
def items
|
33
|
+
to_h.each_with_object({}) do |config_value, hsh|
|
34
|
+
key = config_value.first
|
35
|
+
hsh[key] = build_configuration_item(key)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the configured value for an option
|
40
|
+
#
|
41
|
+
# @return the configured value
|
42
|
+
def [](value)
|
43
|
+
to_h[value]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the available configured options as a hash.
|
47
|
+
#
|
48
|
+
# This filters the options the class is initialized with.
|
49
|
+
#
|
50
|
+
# @return [Hash{Symbol => String, ::RDF::URI}]
|
51
|
+
def to_h
|
52
|
+
@inner_hash.slice(*valid_config_options)
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def build_configuration_item(key)
|
58
|
+
configuration_item_factory.new(self, key)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def configuration_item_factory
|
64
|
+
@configuration_item_factory ||= ItemFactory.new
|
65
|
+
end
|
66
|
+
|
67
|
+
def valid_config_options
|
68
|
+
[:base_uri, :rdf_label, :type, :repository]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActiveTriples
|
2
|
+
class Configuration
|
3
|
+
# Basic configuration item which overrides the value for a key on the object.
|
4
|
+
class Item
|
5
|
+
attr_reader :object, :key
|
6
|
+
def initialize(object, key)
|
7
|
+
@object = object
|
8
|
+
@key = key
|
9
|
+
end
|
10
|
+
|
11
|
+
def value
|
12
|
+
object.inner_hash[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
def set(value)
|
16
|
+
object.inner_hash[key] = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveTriples
|
2
|
+
class Configuration
|
3
|
+
## Returns a configuration item appropriate for a given configuration property.
|
4
|
+
class ItemFactory
|
5
|
+
# @return [MergeItem, Item]
|
6
|
+
def new(object, name)
|
7
|
+
if merge_configs.include?(name)
|
8
|
+
merge_item.new(object, name)
|
9
|
+
else
|
10
|
+
item.new(object, name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def merge_item
|
15
|
+
MergeItem
|
16
|
+
end
|
17
|
+
|
18
|
+
def item
|
19
|
+
Item
|
20
|
+
end
|
21
|
+
|
22
|
+
def merge_configs
|
23
|
+
[:type]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ActiveTriples
|
2
|
+
class Configuration
|
3
|
+
# Configuration item which sets a value by turning the original into an array and
|
4
|
+
# appending the given value to it.
|
5
|
+
#
|
6
|
+
# This enables multiple types to be set on an object, for example.
|
7
|
+
class MergeItem < Item
|
8
|
+
def set(value)
|
9
|
+
object.inner_hash[key] = Array(object.inner_hash[key])
|
10
|
+
object.inner_hash[key] |= Array(value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -7,12 +7,12 @@ module ActiveTriples::Identifiable
|
|
7
7
|
delegate :rdf_subject, :type, to: :resource
|
8
8
|
|
9
9
|
##
|
10
|
-
# @return [ActiveTriples::Resource] a resource that contains this object's
|
10
|
+
# @return [ActiveTriples::Resource] a resource that contains this object's
|
11
11
|
# graph.
|
12
12
|
def resource
|
13
13
|
@resource ||= resource_class.new(to_uri)
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def parent
|
17
17
|
@parent ||= resource.parent
|
18
18
|
end
|
@@ -21,7 +21,7 @@ module ActiveTriples::Identifiable
|
|
21
21
|
@parent = val
|
22
22
|
end
|
23
23
|
|
24
|
-
##
|
24
|
+
##
|
25
25
|
# @return [String] a uri or slug
|
26
26
|
def to_uri
|
27
27
|
return id if respond_to? :id and !resource_class.base_uri.nil?
|
data/lib/active_triples/list.rb
CHANGED
@@ -28,7 +28,7 @@ module ActiveTriples
|
|
28
28
|
def initialize(*args)
|
29
29
|
super
|
30
30
|
parent = graph.parent if graph.respond_to? :parent
|
31
|
-
@graph = ListResource.new(subject) << graph unless graph.kind_of?
|
31
|
+
@graph = ListResource.new(subject) << graph unless graph.kind_of? RDFSource
|
32
32
|
graph << parent if parent
|
33
33
|
graph.list = self
|
34
34
|
graph.reload
|
@@ -97,7 +97,9 @@ module ActiveTriples
|
|
97
97
|
##
|
98
98
|
# This class is the graph/Resource that backs the List and
|
99
99
|
# supplies integration with the rest of ActiveTriples
|
100
|
-
class ListResource
|
100
|
+
class ListResource
|
101
|
+
include ActiveTriples::RDFSource
|
102
|
+
|
101
103
|
attr_reader :list
|
102
104
|
|
103
105
|
def list=(list)
|
@@ -171,11 +173,11 @@ module ActiveTriples
|
|
171
173
|
@graph.type = RDF.List
|
172
174
|
resource.set_value(RDF.first, value)
|
173
175
|
resource.insert([subject, RDF.rest, RDF.nil])
|
174
|
-
resource << value if value.kind_of?
|
176
|
+
resource << value if value.kind_of? RDFSource
|
175
177
|
return self
|
176
178
|
end
|
177
179
|
super
|
178
|
-
resource << value if value.kind_of?
|
180
|
+
resource << value if value.kind_of? RDFSource
|
179
181
|
end
|
180
182
|
end
|
181
183
|
end
|