spira 0.0.1.pre → 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.
- data/README +151 -29
- data/VERSION +1 -1
- data/lib/spira.rb +86 -1
- data/lib/spira/errors.rb +94 -0
- data/lib/spira/resource.rb +53 -7
- data/lib/spira/resource/class_methods.rb +113 -47
- data/lib/spira/resource/dsl.rb +137 -70
- data/lib/spira/resource/instance_methods.rb +165 -56
- data/lib/spira/resource/validations.rb +32 -8
- data/lib/spira/type.rb +82 -0
- data/lib/spira/types.rb +25 -0
- data/lib/spira/types/any.rb +23 -0
- data/lib/spira/types/boolean.rb +31 -0
- data/lib/spira/types/float.rb +28 -0
- data/lib/spira/types/integer.rb +27 -0
- data/lib/spira/types/string.rb +27 -0
- data/lib/spira/version.rb +23 -0
- metadata +13 -9
data/lib/spira/resource.rb
CHANGED
@@ -1,4 +1,37 @@
|
|
1
1
|
module Spira
|
2
|
+
|
3
|
+
##
|
4
|
+
# Spira::Resource is the main interface to Spira. Classes and modules
|
5
|
+
# include Spira::Resource to create projections of RDF data as a class. For
|
6
|
+
# an overview, see the {file:README}.
|
7
|
+
#
|
8
|
+
# Projections are a mapping of RDF predicates to fields.
|
9
|
+
#
|
10
|
+
# class Person
|
11
|
+
# include Spira::Resource
|
12
|
+
#
|
13
|
+
# property :name, :predicate => FOAF.name
|
14
|
+
# property :age, :predicate => FOAF.age, :type => Integer
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# RDF::URI('http://example.org/people/bob').as(Person) #=> <#Person @uri=http://example.org/people/bob>
|
18
|
+
#
|
19
|
+
# Spira resources include the RDF namespace, and can thus reference all of
|
20
|
+
# the default RDF.rb vocabularies without the RDF:: prefix:
|
21
|
+
#
|
22
|
+
# property :name, :predicate => FOAF.name
|
23
|
+
#
|
24
|
+
# The Spira::Resource documentation is broken into several parts, vaguely
|
25
|
+
# related by functionality:
|
26
|
+
# * {Spira::Resource::DSL} contains methods used during the declaration of a class or module
|
27
|
+
# * {Spira::Resource::ClassMethods} contains class methods for use by declared classes
|
28
|
+
# * {Spira::Resource::InstanceMethods} contains methods for use by instances of Spira resource classes
|
29
|
+
# * {Spira::Resource::Validations} contains some default validation functions
|
30
|
+
#
|
31
|
+
# @see Spira::Resource::DSL
|
32
|
+
# @see Spira::Resource::ClassMethods
|
33
|
+
# @see Spira::Resource::InstanceMethods
|
34
|
+
# @see Spira::Resource::Validations
|
2
35
|
module Resource
|
3
36
|
|
4
37
|
autoload :DSL, 'spira/resource/dsl'
|
@@ -6,20 +39,33 @@ module Spira
|
|
6
39
|
autoload :InstanceMethods, 'spira/resource/instance_methods'
|
7
40
|
autoload :Validations, 'spira/resource/validations'
|
8
41
|
|
42
|
+
##
|
43
|
+
# When a child class includes Spira::Resource, this does the magic to make
|
44
|
+
# it a Spira resource.
|
45
|
+
#
|
46
|
+
# @private
|
9
47
|
def self.included(child)
|
10
|
-
|
11
|
-
|
12
|
-
child
|
13
|
-
|
14
|
-
|
48
|
+
# Don't do inclusion work twice. Checking for the properties accessor is
|
49
|
+
# a proxy for a proper check to see if this is a resource already. Ruby
|
50
|
+
# has already extended the child class' ancestors to include
|
51
|
+
# Spira::Resource by the time we get here.
|
52
|
+
# FIXME: Find a 'more correct' check.
|
53
|
+
unless child.respond_to?(:properties)
|
54
|
+
child.extend DSL
|
55
|
+
child.extend ClassMethods
|
56
|
+
child.instance_eval do
|
57
|
+
class << self
|
58
|
+
attr_accessor :properties, :lists
|
59
|
+
end
|
60
|
+
@properties = {}
|
61
|
+
@lists = {}
|
15
62
|
end
|
16
|
-
@properties = {}
|
17
|
-
@lists = {}
|
18
63
|
end
|
19
64
|
end
|
20
65
|
|
21
66
|
# This lets including classes reference vocabularies without the RDF:: prefix
|
22
67
|
include RDF
|
68
|
+
include Spira::Types
|
23
69
|
include InstanceMethods
|
24
70
|
|
25
71
|
end
|
@@ -1,14 +1,21 @@
|
|
1
1
|
module Spira
|
2
2
|
module Resource
|
3
3
|
|
4
|
-
|
5
|
-
#
|
4
|
+
##
|
5
|
+
# This module contains all class methods available to a declared Spira::Resource class.
|
6
|
+
# {Spira::Resource} contains more information about Spira resources.
|
6
7
|
#
|
8
|
+
# @see Spira::Resource
|
9
|
+
# @see Spira::Resource::InstanceMethods
|
10
|
+
# @see Spira::Resource::DSL
|
7
11
|
module ClassMethods
|
8
|
-
def repository=(repo)
|
9
|
-
@repository = repo
|
10
|
-
end
|
11
12
|
|
13
|
+
##
|
14
|
+
# The current repository for this class
|
15
|
+
#
|
16
|
+
# @param [RDF::Repository] repo The repository
|
17
|
+
# @return [Void]
|
18
|
+
# @private
|
12
19
|
def repository
|
13
20
|
case @repository_name
|
14
21
|
when nil
|
@@ -18,68 +25,127 @@ module Spira
|
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
##
|
29
|
+
# Create a new projection instance of this class for the given URI. If a
|
30
|
+
# class has a base_uri given, and the argument is not an `RDF::URI`, the
|
31
|
+
# given identifier will be appended to the base URI.
|
32
|
+
#
|
33
|
+
# Spira does not have 'find' or 'create' functions. As RDF identifiers
|
34
|
+
# are globally unique, they all simply 'are'.
|
35
|
+
#
|
36
|
+
# On calling `for`, a new instance is created for the given URI. The
|
37
|
+
# first time access is attempted on a field, the repository will be
|
38
|
+
# queried for existing attributes, which will be used for the given URI.
|
39
|
+
# Underlying repositories are not accessed at the time of calling `for`.
|
40
|
+
#
|
41
|
+
# A class with a base URI may still be projected for any URI, whether or
|
42
|
+
# not it uses the given resource class' base URI.
|
43
|
+
#
|
44
|
+
# @raise [TypeError] if an RDF type is given in the attributes and one is
|
45
|
+
# given in the attributes.
|
46
|
+
# @raise [ArgumentError] if a non-URI is given and the class does not
|
47
|
+
# have a base URI.
|
48
|
+
# @overload for(uri, attributes = {})
|
49
|
+
# @param [RDF::URI] uri The URI to create an instance for
|
50
|
+
# @param [Hash{Symbol => Any}] attributes Initial attributes
|
51
|
+
# @overload for(identifier, attributes = {})
|
52
|
+
# @param [Any] uri The identifier to append to the base URI for this class
|
53
|
+
# @param [Hash{Symbol => Any}] attributes Initial attributes
|
54
|
+
# @return [Spira::Resource] The newly created instance
|
55
|
+
# @see http://rdf.rubyforge.org/RDF/URI.html
|
56
|
+
def for(identifier, attributes = {})
|
57
|
+
if !self.type.nil? && attributes[:type]
|
58
|
+
raise TypeError, "#{self} has an RDF type, #{self.type}, and cannot accept one as an argument."
|
38
59
|
end
|
39
|
-
|
60
|
+
uri = uri_for(identifier)
|
61
|
+
self.new(uri, attributes)
|
40
62
|
end
|
41
63
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
64
|
+
##
|
65
|
+
# Creates a URI based on a base_uri and string or URI
|
66
|
+
#
|
67
|
+
# @param [Any] Identifier
|
68
|
+
# @return [RDF::URI]
|
69
|
+
# @raise [ArgumentError] If this class cannot create an identifier from the given string
|
70
|
+
# @see http://rdf.rubyforge.org/RDF/URI.html
|
71
|
+
def uri_for(identifier)
|
72
|
+
case identifier
|
47
73
|
when RDF::URI
|
48
74
|
identifier
|
49
75
|
when String
|
50
|
-
|
76
|
+
uri = RDF::URI.new(identifier)
|
77
|
+
return uri if uri.absolute?
|
78
|
+
raise ArgumentError, "Cannot create identifier for #{self} by String without base_uri; RDF::URI required" if self.base_uri.nil?
|
51
79
|
separator = self.base_uri.to_s[-1,1] == "/" ? '' : '/'
|
52
|
-
RDF::URI.
|
80
|
+
RDF::URI.new(self.base_uri.to_s + separator + identifier)
|
53
81
|
else
|
54
|
-
raise ArgumentError, "Cannot
|
55
|
-
end
|
56
|
-
statements = self.repository.query(:subject => uri)
|
57
|
-
if statements.empty?
|
58
|
-
nil
|
59
|
-
else
|
60
|
-
self.new(identifier, :statements => statements)
|
82
|
+
raise ArgumentError, "Cannot create an identifier for #{self} from #{identifier}, expected RDF::URI or String"
|
61
83
|
end
|
62
84
|
end
|
63
|
-
|
85
|
+
|
86
|
+
|
87
|
+
##
|
88
|
+
# The number of URIs projectable as a given class in the repository.
|
89
|
+
# This method is only valid for classes which declare a `type` with the
|
90
|
+
# `type` method in the DSL.
|
91
|
+
#
|
92
|
+
# @raise [TypeError] if the resource class does not have an RDF type declared
|
93
|
+
# @return [Integer] the count
|
94
|
+
# @see Spira::Resource::DSL
|
64
95
|
def count
|
65
96
|
raise TypeError, "Cannot count a #{self} without a reference type URI." if @type.nil?
|
66
97
|
result = repository.query(:predicate => RDF.type, :object => @type)
|
67
98
|
result.count
|
68
99
|
end
|
69
100
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
101
|
+
##
|
102
|
+
# Returns true if the given property is a has_many property, false otherwise
|
103
|
+
#
|
104
|
+
# @return [true, false]
|
105
|
+
def is_list?(property)
|
106
|
+
@lists.has_key?(property)
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Handling inheritance
|
111
|
+
#
|
112
|
+
# @private
|
113
|
+
def inherited(child)
|
114
|
+
child.instance_eval do
|
115
|
+
include Spira::Resource
|
116
|
+
end
|
117
|
+
# FIXME: This is clearly brittle and ugly.
|
118
|
+
[:@base_uri, :@default_vocabulary, :@repository_name, :@type].each do |variable|
|
119
|
+
value = instance_variable_get(variable).nil? ? nil : instance_variable_get(variable).dup
|
120
|
+
child.instance_variable_set(variable, value)
|
121
|
+
end
|
122
|
+
[:@properties, :@lists, :@validators].each do |variable|
|
123
|
+
if child.instance_variable_get(variable).nil?
|
124
|
+
if instance_variable_get(variable).nil?
|
125
|
+
child.instance_variable_set(variable, nil)
|
126
|
+
else
|
127
|
+
child.instance_variable_set(variable, instance_variable_get(variable).dup)
|
128
|
+
end
|
129
|
+
elsif !(instance_variable_get(variable).nil?)
|
130
|
+
child.instance_variable_set(variable, instance_variable_get(variable).dup.merge(child.instance_variable_get(variable)))
|
75
131
|
end
|
76
|
-
attributes[:type] = @type
|
77
132
|
end
|
78
|
-
resource = self.new(name, attributes)
|
79
133
|
end
|
80
134
|
|
81
|
-
|
82
|
-
|
135
|
+
##
|
136
|
+
# Handling module inclusions
|
137
|
+
#
|
138
|
+
# @private
|
139
|
+
def included(child)
|
140
|
+
inherited(child)
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# The list of validation functions for this projection
|
145
|
+
#
|
146
|
+
# @return [Array<Symbol>]
|
147
|
+
def validators
|
148
|
+
@validators ||= []
|
83
149
|
end
|
84
150
|
|
85
151
|
end
|
data/lib/spira/resource/dsl.rb
CHANGED
@@ -1,41 +1,122 @@
|
|
1
1
|
require 'promise'
|
2
2
|
|
3
3
|
module Spira
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
module Resource
|
5
|
+
|
6
|
+
##
|
7
|
+
# This module consists of Spira::Resource class methods which correspond to
|
8
|
+
# the Spira resource class declaration DSL. See {Spira::Resource} for more
|
9
|
+
# information.
|
10
|
+
#
|
11
|
+
# @see Spira::Resource
|
12
|
+
# @see Spira::Resource::ClassMethods
|
13
|
+
# @see Spira::Resource::InstanceMethods
|
14
|
+
# @see Spira::Resource::Validations
|
14
15
|
module DSL
|
15
16
|
|
17
|
+
##
|
18
|
+
# The name of the default repository to use for this class. This
|
19
|
+
# repository will be queried and written to instead of the :default
|
20
|
+
# repository.
|
21
|
+
#
|
22
|
+
# @param [Symbol] name
|
23
|
+
# @return [Void]
|
16
24
|
def default_source(name)
|
17
25
|
@repository_name = name
|
18
26
|
@repository = Spira.repository(name)
|
19
27
|
end
|
20
|
-
|
28
|
+
|
29
|
+
##
|
30
|
+
# The base URI for this class. Attempts to create instances for non-URI
|
31
|
+
# objects will be appended to this base URI.
|
32
|
+
#
|
33
|
+
# @param [String, RDF::URI] base uri
|
34
|
+
# @return [Void]
|
21
35
|
def base_uri(uri = nil)
|
22
36
|
@base_uri = uri unless uri.nil?
|
23
37
|
@base_uri
|
24
38
|
end
|
25
|
-
|
39
|
+
|
40
|
+
##
|
41
|
+
# The default vocabulary for this class. Setting a default vocabulary
|
42
|
+
# will allow properties to be defined without a `:predicate` option.
|
43
|
+
# Predicates will instead be created by appending the property name to
|
44
|
+
# the given string.
|
45
|
+
#
|
46
|
+
# @param [String, RDF::URI] base uri
|
47
|
+
# @return [Void]
|
26
48
|
def default_vocabulary(uri)
|
27
49
|
@default_vocabulary = uri
|
28
50
|
end
|
29
51
|
|
52
|
+
|
53
|
+
##
|
54
|
+
# Add a property to this class. A property is an accessor field that
|
55
|
+
# represents an RDF predicate.
|
56
|
+
#
|
57
|
+
# @example A simple string property
|
58
|
+
# property :name, :predicate => FOAF.name, :type => String
|
59
|
+
# @example A property which defaults to {Spira::Types::Any}
|
60
|
+
# property :name, :predicate => FOAF.name
|
61
|
+
# @example An integer property
|
62
|
+
# property :age, :predicate => FOAF.age, :type => Integer
|
63
|
+
# @param [Symbol] name The name of this property
|
64
|
+
# @param [Hash{Symbol => Any}] opts property options
|
65
|
+
# @option opts [RDF::URI] :predicate The RDF predicate which will refer to this property
|
66
|
+
# @option opts [Spira::Type, String] :type (Spira::Types::Any) The
|
67
|
+
# type for this property. If a Spira::Type is given, that class will be
|
68
|
+
# used to serialize and unserialize values. If a String is given, it
|
69
|
+
# should be the String form of a Spira::Resource class name (Strings are
|
70
|
+
# used to prevent issues with load order).
|
71
|
+
# @see Spira::Types
|
72
|
+
# @see Spira::Type
|
73
|
+
# @return [Void]
|
30
74
|
def property(name, opts = {} )
|
31
75
|
add_accessors(name,opts,:hash_accessors)
|
32
76
|
end
|
33
77
|
|
78
|
+
##
|
79
|
+
# The plural form of `property`. `Has_many` has the same options as
|
80
|
+
# `property`, but instead of a single value, a Ruby Array of objects will
|
81
|
+
# be created instead. Be warned that this should be a Set to match RDF
|
82
|
+
# semantics, but this is not currently implemented. Duplicate values of
|
83
|
+
# an array will be lost on save.
|
84
|
+
#
|
85
|
+
# @see Spira::Resource::DSL#property
|
34
86
|
def has_many(name, opts = {})
|
35
87
|
add_accessors(name,opts,:hash_accessors)
|
36
88
|
@lists[name] = true
|
37
89
|
end
|
38
90
|
|
91
|
+
##
|
92
|
+
# Validate this model with the given validator function name.
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# class Person
|
96
|
+
# include Spira::Resource
|
97
|
+
# property :name, :predicate => FOAF.name
|
98
|
+
# validate :is_awesome
|
99
|
+
# def is_awesome
|
100
|
+
# assert(name =~ /Thor/, :name, "not awesome")
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
# @param [Symbol] validator
|
104
|
+
# @return [Void]
|
105
|
+
def validate(validator)
|
106
|
+
validators << validator unless validators.include?(validator)
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
##
|
111
|
+
# Associate an RDF type with this class. RDF resources can be multiple
|
112
|
+
# types at once, but if they have an `RDF.type` statement for the given
|
113
|
+
# URI, this class can #count them.
|
114
|
+
#
|
115
|
+
# @param [RDF::URI] uri The URI object of the `RDF.type` triple
|
116
|
+
# @return [Void]
|
117
|
+
# @see http://rdf.rubyforge.net/RDF/URI.html
|
118
|
+
# @see http://rdf.rubyforge.org/RDF.html#type-class_method
|
119
|
+
# @see Spira::Resource::ClassMethods#count
|
39
120
|
def type(uri = nil)
|
40
121
|
unless uri.nil?
|
41
122
|
@type = case uri
|
@@ -48,41 +129,55 @@ module Spira
|
|
48
129
|
@type
|
49
130
|
end
|
50
131
|
|
132
|
+
# Build a Ruby value from an RDF value.
|
51
133
|
#
|
52
134
|
# @private
|
53
|
-
def build_value(statement, type)
|
135
|
+
def build_value(statement, type, existing_relation = nil)
|
54
136
|
case
|
55
137
|
when statement == nil
|
56
138
|
nil
|
57
|
-
when type
|
58
|
-
statement.object
|
59
|
-
when type
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
139
|
+
when type.is_a?(Class) && type.ancestors.include?(Spira::Type)
|
140
|
+
type.unserialize(statement.object)
|
141
|
+
when type.is_a?(Symbol) || type.is_a?(String)
|
142
|
+
klass = begin
|
143
|
+
Kernel.const_get(type.to_s)
|
144
|
+
rescue NameError
|
145
|
+
unless klass.is_a?(Class) && klass.ancestors.include?(Spira::Resource)
|
146
|
+
raise TypeError, "#{type} is not a Spira Resource (referenced as #{type} by #{self}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
case
|
150
|
+
when false && existing_relation && (existing_relation.uri == statement.object.to_uri)
|
151
|
+
existing_relation
|
152
|
+
else
|
153
|
+
promise { klass.for(statement.object) ||
|
154
|
+
klass.create(statement.object) }
|
155
|
+
end
|
156
|
+
else
|
157
|
+
raise TypeError, "Unable to unserialize #{statement.object} for #{type}"
|
65
158
|
end
|
66
159
|
end
|
67
160
|
|
161
|
+
# Build an RDF value from a Ruby value for a property
|
68
162
|
# @private
|
69
163
|
def build_rdf_value(value, type)
|
70
164
|
case
|
71
|
-
when
|
165
|
+
when type.is_a?(Class) && type.ancestors.include?(Spira::Type)
|
166
|
+
type.serialize(value)
|
167
|
+
when value && value.class.ancestors.include?(Spira::Resource)
|
72
168
|
value.uri
|
73
|
-
when type == nil
|
74
|
-
value
|
75
169
|
when type == RDF::URI && value.is_a?(RDF::URI)
|
76
170
|
value
|
77
|
-
when type.is_a?(RDF::URI)
|
78
|
-
RDF::Literal.new(value, :datatype => type)
|
79
171
|
else
|
80
|
-
|
172
|
+
raise TypeError, "Unable to serialize #{value} for #{type}"
|
81
173
|
end
|
82
174
|
end
|
83
175
|
|
84
176
|
private
|
85
177
|
|
178
|
+
##
|
179
|
+
# Add getters and setters for a property or list.
|
180
|
+
# @private
|
86
181
|
def add_accessors(name, opts, accessors_method)
|
87
182
|
predicate = case
|
88
183
|
when opts[:predicate]
|
@@ -93,8 +188,16 @@ module Spira
|
|
93
188
|
separator = @default_vocabulary.to_s[-1,1] == "/" ? '' : '/'
|
94
189
|
RDF::URI.new(@default_vocabulary.to_s + separator + name.to_s)
|
95
190
|
end
|
96
|
-
|
97
|
-
|
191
|
+
type = case
|
192
|
+
when opts[:type].nil?
|
193
|
+
Spira::Types::Any
|
194
|
+
when opts[:type].is_a?(Symbol) || opts[:type].is_a?(String)
|
195
|
+
opts[:type]
|
196
|
+
when !(Spira.types[opts[:type]].nil?)
|
197
|
+
Spira.types[opts[:type]]
|
198
|
+
else
|
199
|
+
raise TypeError, "Unrecognized type: #{opts[:type]}"
|
200
|
+
end
|
98
201
|
@properties[name] = {}
|
99
202
|
@properties[name][:predicate] = predicate
|
100
203
|
@properties[name][:type] = type
|
@@ -106,6 +209,11 @@ module Spira
|
|
106
209
|
|
107
210
|
end
|
108
211
|
|
212
|
+
##
|
213
|
+
# Getter and Setter methods for predicates.
|
214
|
+
# FIXME: this and add_accessors are from an older version in which
|
215
|
+
# multiple versions of accessors existed, and can be refactored.
|
216
|
+
# @private
|
109
217
|
def hash_accessors(name, predicate, type)
|
110
218
|
setter = lambda do |arg|
|
111
219
|
attribute_set(name,arg)
|
@@ -118,47 +226,6 @@ module Spira
|
|
118
226
|
[getter, setter]
|
119
227
|
end
|
120
228
|
|
121
|
-
def list_accessors(name, predicate, type)
|
122
|
-
|
123
|
-
setter = lambda do |arg|
|
124
|
-
old = @repo.query(:subject => @uri, :predicate => predicate)
|
125
|
-
@repo.delete(*old.to_a) unless old.empty?
|
126
|
-
new = []
|
127
|
-
arg.each do |value|
|
128
|
-
value = self.class.build_rdf_value(value, type)
|
129
|
-
new << RDF::Statement.new(@uri, predicate, value)
|
130
|
-
end
|
131
|
-
@repo.insert(*new)
|
132
|
-
end
|
133
|
-
|
134
|
-
getter = lambda do
|
135
|
-
values = []
|
136
|
-
statements = @repo.query(:subject => @uri, :predicate => predicate)
|
137
|
-
statements.each do |statement|
|
138
|
-
values << self.class.build_value(statement, type)
|
139
|
-
end
|
140
|
-
values
|
141
|
-
end
|
142
|
-
|
143
|
-
[getter, setter]
|
144
|
-
end
|
145
|
-
|
146
|
-
def single_accessors(name, predicate, type)
|
147
|
-
setter = lambda do |arg|
|
148
|
-
old = @repo.query(:subject => @uri, :predicate => predicate)
|
149
|
-
@repo.delete(*old.to_a) unless old.empty?
|
150
|
-
arg = self.class.build_rdf_value(arg, type)
|
151
|
-
@repo.insert(RDF::Statement.new(@uri, predicate, arg))
|
152
|
-
end
|
153
|
-
|
154
|
-
getter = lambda do
|
155
|
-
statement = @repo.query(:subject => @uri, :predicate => predicate).first
|
156
|
-
self.class.build_value(statement, type)
|
157
|
-
end
|
158
|
-
|
159
|
-
[getter, setter]
|
160
|
-
end
|
161
|
-
|
162
229
|
end
|
163
230
|
end
|
164
231
|
end
|