active-triples 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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +12 -0
- data/AUTHORS +2 -0
- data/Gemfile +3 -0
- data/LICENSE +24 -0
- data/README.md +38 -0
- data/active-triples.gemspec +35 -0
- data/lib/active_triples.rb +29 -0
- data/lib/active_triples/configurable.rb +61 -0
- data/lib/active_triples/indexing.rb +76 -0
- data/lib/active_triples/list.rb +155 -0
- data/lib/active_triples/nested_attributes.rb +132 -0
- data/lib/active_triples/node_config.rb +56 -0
- data/lib/active_triples/properties.rb +96 -0
- data/lib/active_triples/repositories.rb +36 -0
- data/lib/active_triples/resource.rb +369 -0
- data/lib/active_triples/term.rb +188 -0
- data/lib/active_triples/version.rb +3 -0
- data/spec/rdf_list_spec.rb +183 -0
- data/spec/rdf_nested_attributes_spec.rb +183 -0
- data/spec/rdf_properties_spec.rb +81 -0
- data/spec/rdf_repositories_spec.rb +28 -0
- data/spec/rdf_resource_spec.rb +447 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/active_model_lint.rb +81 -0
- metadata +197 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e1dcbe5917c46ab351078d1c6e7b2be54d66c68f
|
4
|
+
data.tar.gz: 5cc8dfc6dfbba4a833566f568d395a15ba79c535
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 17d3134eb50d437947dada9a3eadd4b298968c2fef571e25796de38f4b6de48b3eef9935fcfd9c0a5cd9089570ddd4f4fdcd40a9e1a499d5521026e1d8de020b
|
7
|
+
data.tar.gz: 6beee86d363f0791be42dbd5507a6dad99fa3e7ceb2beedacd39d704ee63ade58dba85fec512d0f5d25fdbf60088844b7aaeb9b3917a70ef697d020193782c9f
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/AUTHORS
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
ActiveTriples
|
2
|
+
==============
|
3
|
+
|
4
|
+
[](https://travis-ci.org/no-reply/ActiveTriples)
|
5
|
+
|
6
|
+
Modeling RDF graphs in Ruby.
|
7
|
+
|
8
|
+
How to Use
|
9
|
+
-----------
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class Thing < ActiveTriples::Resource
|
13
|
+
configure :type => RDF::OWL.Thing, :base_uri => 'http://example.org/things#'
|
14
|
+
property :title, :predicate => RDF::DC.title
|
15
|
+
property :description, :predicate => RDF::DC.description
|
16
|
+
property :creator, :predicate => RDF::DC.creator, :class_name => 'Person'
|
17
|
+
end
|
18
|
+
|
19
|
+
obj = Thing.new('123')
|
20
|
+
obj.title = 'Resource'
|
21
|
+
obj.description = 'A resource in an RDF graph.'
|
22
|
+
|
23
|
+
obj.dump :ntriples
|
24
|
+
# => "<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 in an RDF graph.\" .\n"
|
25
|
+
|
26
|
+
class Person < ActiveTriples::Resource
|
27
|
+
configure :type => RDF::FOAF.Person, :base_uri => 'http://example.org/people#'
|
28
|
+
property :name, :predicate => RDF::FOAF.name
|
29
|
+
end
|
30
|
+
|
31
|
+
obj.creator = Person.new
|
32
|
+
obj.creator
|
33
|
+
# => [#<Person:0x3fbe84ac9234(default)>]
|
34
|
+
|
35
|
+
obj.creator.first.name = 'Herman Melville'
|
36
|
+
obj.dump :ntriples
|
37
|
+
# => "<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 in an RDF graph.\" .\n<http://example.org/things#123> <http://purl.org/dc/terms/creator> _:g70087502237940 .\n_:g70087502237940 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .\n"
|
38
|
+
```
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "active_triples/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "active-triples"
|
7
|
+
s.version = ActiveTriples::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Tom Johnson", "Trey Terrell"]
|
10
|
+
s.homepage = 'https://github.com/no-reply/ActiveTriples'
|
11
|
+
s.email = 'thomas.johnson@oregonstate.edu'
|
12
|
+
s.summary = %q{RDF graphs in ActiveModel wrappers.}
|
13
|
+
s.description = %q{ActiveTriples provides tools for modeling RDF as discrete resources.}
|
14
|
+
s.license = "Public Domain"
|
15
|
+
s.required_ruby_version = '>= 1.9.3'
|
16
|
+
|
17
|
+
s.add_dependency('rdf', '~> 1.1')
|
18
|
+
s.add_dependency('linkeddata', '~> 1.1')
|
19
|
+
s.add_dependency('activemodel')
|
20
|
+
s.add_dependency('deprecation', '~> 0.1')
|
21
|
+
s.add_dependency('activesupport')
|
22
|
+
|
23
|
+
s.add_development_dependency('rdoc')
|
24
|
+
s.add_development_dependency('rspec')
|
25
|
+
s.add_development_dependency('webmock')
|
26
|
+
s.add_development_dependency('nokogiri')
|
27
|
+
|
28
|
+
s.files = `git ls-files`.split("\n")
|
29
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
30
|
+
|
31
|
+
s.extra_rdoc_files = [
|
32
|
+
"LICENSE",
|
33
|
+
"README.md"
|
34
|
+
]
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
require 'active_triples/version'
|
3
|
+
|
4
|
+
module ActiveTriples
|
5
|
+
autoload :Resource, 'active_triples/resource'
|
6
|
+
autoload :List, 'active_triples/list'
|
7
|
+
autoload :Term, 'active_triples/term'
|
8
|
+
autoload :Indexing, 'active_triples/indexing'
|
9
|
+
autoload :Configurable, 'active_triples/configurable'
|
10
|
+
autoload :Properties, 'active_triples/properties'
|
11
|
+
autoload :Repositories, 'active_triples/repositories'
|
12
|
+
autoload :NodeConfig, 'active_triples/node_config'
|
13
|
+
autoload :NestedAttributes, 'active_triples/nested_attributes'
|
14
|
+
|
15
|
+
def self.class_from_string(class_name, container_class=Kernel)
|
16
|
+
container_class = container_class.name if container_class.is_a? Module
|
17
|
+
container_parts = container_class.split('::')
|
18
|
+
(container_parts + class_name.split('::')).flatten.inject(Kernel) do |mod, class_name|
|
19
|
+
if mod == Kernel
|
20
|
+
Object.const_get(class_name)
|
21
|
+
elsif mod.const_defined? class_name.to_sym
|
22
|
+
mod.const_get(class_name)
|
23
|
+
else
|
24
|
+
container_parts.pop
|
25
|
+
class_from_string(class_name, container_parts.join('::'))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'deprecation'
|
2
|
+
|
3
|
+
module ActiveTriples
|
4
|
+
##
|
5
|
+
# Module to include configurable class-wide properties common to
|
6
|
+
# Resource and RDFDatastream. It does its work at the class level,
|
7
|
+
# and is meant to be extended.
|
8
|
+
#
|
9
|
+
# Define properties at the class level with:
|
10
|
+
#
|
11
|
+
# configure base_uri: "http://oregondigital.org/resource/", repository: :parent
|
12
|
+
# Available properties are base_uri, rdf_label, type, and repository
|
13
|
+
module Configurable
|
14
|
+
extend Deprecation
|
15
|
+
|
16
|
+
def base_uri
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def rdf_label
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def type
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def rdf_type(value)
|
29
|
+
Deprecation.warn Configurable, "rdf_type is deprecated and will be removed in active-fedora 8.0.0. Use configure type: instead.", caller
|
30
|
+
configure type: value
|
31
|
+
end
|
32
|
+
|
33
|
+
def repository
|
34
|
+
:parent
|
35
|
+
end
|
36
|
+
|
37
|
+
# API method for configuring class properties an RDF Resource may need.
|
38
|
+
# This is an alternative to overriding the methods extended with this module.
|
39
|
+
def configure(options = {})
|
40
|
+
{
|
41
|
+
base_uri: options[:base_uri],
|
42
|
+
rdf_label: options[:rdf_label],
|
43
|
+
type: options[:type],
|
44
|
+
repository: options[:repository]
|
45
|
+
}.each do |name, value|
|
46
|
+
if value
|
47
|
+
value = self.send("transform_#{name}", value) if self.respond_to?("transform_#{name}")
|
48
|
+
define_singleton_method(name) do
|
49
|
+
value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def transform_type(value)
|
56
|
+
RDF::URI.new(value).tap do |value|
|
57
|
+
Resource.type_registry[value] = self
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ActiveFedora
|
2
|
+
module Rdf
|
3
|
+
module Indexing
|
4
|
+
extend Deprecation
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# In active_fedora 8, we can get the prefix part from Datastream.prefix
|
8
|
+
def apply_prefix(name)
|
9
|
+
"#{dsid.underscore}__#{name}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def prefix(name)
|
13
|
+
Deprecation.warn Indexing, "prefix is deprecated. Use apply_prefix instead. In active-fedora 8, the prefix method will just return the prefix to be applied, and will not do the applying. This will enable conformity between OmDatastream and RdfDatastream"
|
14
|
+
apply_prefix(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_solr(solr_doc = Hash.new) # :nodoc:
|
18
|
+
fields.each do |field_key, field_info|
|
19
|
+
values = resource.get_values(field_key)
|
20
|
+
Array(values).each do |val|
|
21
|
+
if val.kind_of? RDF::URI
|
22
|
+
val = val.to_s
|
23
|
+
elsif val.kind_of? Rdf::Resource
|
24
|
+
val = val.solrize
|
25
|
+
end
|
26
|
+
self.class.create_and_insert_terms(apply_prefix(field_key), val, field_info[:behaviors], solr_doc)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
solr_doc
|
30
|
+
end
|
31
|
+
|
32
|
+
# Gives the primary solr name for a column. If there is more than one indexer on the field definition, it gives the first
|
33
|
+
def primary_solr_name(field)
|
34
|
+
config = self.class.config_for_term_or_uri(field)
|
35
|
+
return nil unless config # punt on index names for deep nodes!
|
36
|
+
if behaviors = config.behaviors
|
37
|
+
behaviors.each do |behavior|
|
38
|
+
result = ActiveFedora::SolrService.solr_name(apply_prefix(field), behavior, type: config.type)
|
39
|
+
return result if Solrizer::DefaultDescriptors.send(behavior).evaluate_suffix(:text).stored?
|
40
|
+
end
|
41
|
+
raise RuntimeError "no stored fields were found"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module ClassMethods
|
46
|
+
def prefix(dsid, name)
|
47
|
+
Deprecation.warn Indexing, "prefix is deprecated and will be removed in active-fedora 8.0.0.", caller
|
48
|
+
"#{dsid.underscore}__#{name}".to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
# Gives the datatype for a column.
|
52
|
+
def type(field)
|
53
|
+
config_for_term_or_uri(field).type
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
# returns a Hash, e.g.: {field => {:values => [], :type => :something, :behaviors => []}, ...}
|
59
|
+
def fields
|
60
|
+
field_map = {}.with_indifferent_access
|
61
|
+
|
62
|
+
self.class.properties.each do |name, config|
|
63
|
+
type = config[:type]
|
64
|
+
behaviors = config[:behaviors]
|
65
|
+
next unless type and behaviors
|
66
|
+
next if config[:class_name] && config[:class_name] < ActiveFedora::Base
|
67
|
+
resource.query(:subject => rdf_subject, :predicate => config[:predicate]).each_statement do |statement|
|
68
|
+
field_map[name] ||= {:values => [], :type => type, :behaviors => behaviors}
|
69
|
+
field_map[name][:values] << statement.object.to_s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
field_map
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module ActiveTriples
|
2
|
+
##
|
3
|
+
# An implementation of RDF::List intregrated with ActiveTriples.
|
4
|
+
#
|
5
|
+
# A thoughtful reflection period is encouraged before using the
|
6
|
+
# rdf:List concept in your data. The community may pursue other
|
7
|
+
# options for ordered sets.
|
8
|
+
class List < RDF::List
|
9
|
+
include ActiveTriples::NestedAttributes
|
10
|
+
extend Configurable
|
11
|
+
extend Properties
|
12
|
+
|
13
|
+
delegate :rdf_subject, :mark_for_destruction, :marked_for_destruction?, :set_value, :get_values, :parent, :dump, :attributes=, to: :resource
|
14
|
+
alias_method :to_ary, :to_a
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def from_uri(uri, vals)
|
18
|
+
list = ListResource.from_uri(uri, vals)
|
19
|
+
self.new(list.rdf_subject, list)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def resource
|
24
|
+
graph
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(*args)
|
28
|
+
super
|
29
|
+
parent = graph.parent if graph.respond_to? :parent
|
30
|
+
@graph = ListResource.new(subject) << graph unless graph.kind_of? Resource
|
31
|
+
graph << parent if parent
|
32
|
+
graph.list = self
|
33
|
+
graph.singleton_class.properties = self.class.properties
|
34
|
+
graph.singleton_class.properties.keys.each do |property|
|
35
|
+
graph.singleton_class.send(:register_property, property)
|
36
|
+
end
|
37
|
+
graph.insert RDF::Statement.new(subject, RDF.type, RDF.List)
|
38
|
+
graph.reload
|
39
|
+
end
|
40
|
+
|
41
|
+
def []=(idx, value)
|
42
|
+
raise IndexError "index #{idx} too small for array: minimum 0" if idx < 0
|
43
|
+
|
44
|
+
if idx >= length
|
45
|
+
(idx - length).times do
|
46
|
+
self << RDF::OWL.Nothing
|
47
|
+
end
|
48
|
+
return self << value
|
49
|
+
end
|
50
|
+
each_subject.with_index do |v, i|
|
51
|
+
next unless i == idx
|
52
|
+
resource.set_value(v, RDF.first, value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Override to return AF::Rdf::Resources as values, where
|
58
|
+
# appropriate.
|
59
|
+
def each(&block)
|
60
|
+
return super unless block_given?
|
61
|
+
|
62
|
+
super do |value|
|
63
|
+
block.call(node_from_value(value))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Do these like #each.
|
69
|
+
def first
|
70
|
+
node_from_value(super)
|
71
|
+
end
|
72
|
+
|
73
|
+
def shift
|
74
|
+
node_from_value(super)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Find an AF::Rdf::Resource from the value returned by RDF::List
|
79
|
+
def node_from_value(value)
|
80
|
+
if value.kind_of? RDF::Resource
|
81
|
+
type_uri = resource.query([value, RDF.type, nil]).to_a.first.try(:object)
|
82
|
+
klass = ActiveTriples::Resource.type_registry[type_uri]
|
83
|
+
klass ||= Resource
|
84
|
+
return klass.from_uri(value,resource)
|
85
|
+
end
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# This class is the graph/Resource that backs the List and
|
91
|
+
# supplies integration with the rest of ActiveTriples
|
92
|
+
class ListResource < Resource
|
93
|
+
attr_reader :list
|
94
|
+
|
95
|
+
def list=(list)
|
96
|
+
@list ||= list
|
97
|
+
end
|
98
|
+
|
99
|
+
def attributes=(values)
|
100
|
+
raise ArgumentError, "values must be a Hash, you provided #{values.class}" unless values.kind_of? Hash
|
101
|
+
values.with_indifferent_access.each do |key, value|
|
102
|
+
if self.singleton_class.properties.keys.map{ |k| "#{k}_attributes"}.include?(key)
|
103
|
+
klass = properties[key[0..-12]]['class_name']
|
104
|
+
klass = ActiveTriples.class_from_string(klass, final_parent.class) if klass.is_a? String
|
105
|
+
value.is_a?(Hash) ? attributes_hash_to_list(values[key], klass) : attributes_to_list(value, klass)
|
106
|
+
values.delete key
|
107
|
+
end
|
108
|
+
end
|
109
|
+
persist!
|
110
|
+
super
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def attributes_to_list(value, klass)
|
115
|
+
value.each do |entry|
|
116
|
+
item = klass.new()
|
117
|
+
item.attributes = entry
|
118
|
+
list << item
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def attributes_hash_to_list(value, klass)
|
123
|
+
value.each do |counter, attr|
|
124
|
+
item = klass.new()
|
125
|
+
item.attributes = attr if attr
|
126
|
+
list[counter.to_i] = item
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Monkey patch to allow lists to have subject URIs.
|
133
|
+
# Overrides RDF::List to prevent URI subjects
|
134
|
+
# from being replaced with nodes.
|
135
|
+
#
|
136
|
+
# @NOTE Lists built this way will return false for #valid?
|
137
|
+
def <<(value)
|
138
|
+
value = case value
|
139
|
+
when nil then RDF.nil
|
140
|
+
when RDF::Value then value
|
141
|
+
when Array then RDF::List.new(nil, graph, value)
|
142
|
+
else value
|
143
|
+
end
|
144
|
+
|
145
|
+
if empty?
|
146
|
+
resource.set_value(RDF.first, value)
|
147
|
+
resource.insert([subject, RDF.rest, RDF.nil])
|
148
|
+
resource << value if value.kind_of? Resource
|
149
|
+
return self
|
150
|
+
end
|
151
|
+
super
|
152
|
+
resource << value if value.kind_of? Resource
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|