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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 809451f4e93b30a688fe6408869e9a854f17566b
4
- data.tar.gz: e7245d27ba5ead992693c0287cda780552525ab6
3
+ metadata.gz: a4dc6967bd4ea18668b379926f3504e0c67c5135
4
+ data.tar.gz: c75e487fcf484d7e1f91a7a919ac9c56c2728c1b
5
5
  SHA512:
6
- metadata.gz: b00382722ed8c6217be858229f817707f3e9ab79de5f9d8c286894f670c1918da137aefa2f30d852ccf6f4b61974cd28d97f9a6b0833faa6bd5dc70721208b2d
7
- data.tar.gz: 5a1df0a4b7f39d97af9a28f78cefb34af861b0a8c4276a0c50bce79b6455838d6f705b7fc6c737b7c02a1b864d5d200f70a5afcb13decc544e03d0b2d4a1bf15
6
+ metadata.gz: d548a15c50003b4625c33283399bd8d101edceec9671658012b1702cead051c7230188afe2a6100feb9bd93c3a08204bbd4395266fec6aebc071863e3e647b28
7
+ data.tar.gz: c2a1f637cd7a4edf4a9a3eb3fd78fcbf143e964561d6648d674353575a4c5312aee21f8502de003b4ae1a4bbb4c7f13760eabbdfe35d126ef9f312e9efd14775
@@ -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
- - jruby-19mode
10
+ - 2.2.1
11
+ - ruby-head
12
+ - jruby
13
+ - rbx-2
10
14
  matrix:
11
15
  allow_failures:
12
- - rvm: jruby-19mode
16
+ - rvm: jruby
@@ -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
@@ -1,3 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
+
5
+ gem 'pry-byebug' unless ENV["CI"]
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 Resources with property/attribute configuration, accessors, and other methods to support Linked Data in a Ruby/Rails enviornment.
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 Resource Models
20
- ------------------------
19
+ Defining RDFSource Models
20
+ -------------------------
21
21
 
22
- The core class of ActiveTriples is ActiveTriples::Resource. You can subclass this to create ActiveModel-like classes that represent a node in an RDF graph, and its surrounding statements. Resources implement all the functionality of an RDF::Graph. You can manipulate them by adding or deleting statements, query, serialize, and load arbitrary RDF.
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 < ActiveTriples::Resource
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, and a model class can be configured on individual properties.
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 < ActiveTriples::Resource
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
- A Resource 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.
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 Resources, too. Or you can use generic setters and getters with URI predicates:
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 Resource's #rdf_subject URI
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 < ActiveTriples::Resource
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 < ActiveTriples::Resource
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
-
@@ -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 :Term
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
- nil
16
+ configuration[:base_uri]
18
17
  end
19
18
 
20
19
  def rdf_label
21
- nil
20
+ configuration[:rdf_label]
22
21
  end
23
22
 
24
23
  def type
25
- nil
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
- base_uri: options[:base_uri],
57
- rdf_label: options[:rdf_label],
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(value)
71
- RDF::URI.new(value).tap do |value|
72
- Resource.type_registry[value] = self
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?
@@ -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? Resource
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 < Resource
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? Resource
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? Resource
180
+ resource << value if value.kind_of? RDFSource
179
181
  end
180
182
  end
181
183
  end