ld4l-open_annotation_rdf 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +14 -0
- data/README.md +231 -0
- data/Rakefile +2 -0
- data/ld4l-open_annotation_rdf.gemspec +46 -0
- data/lib/ld4l/open_annotation_rdf.rb +66 -0
- data/lib/ld4l/open_annotation_rdf/annotation.rb +82 -0
- data/lib/ld4l/open_annotation_rdf/comment_annotation.rb +47 -0
- data/lib/ld4l/open_annotation_rdf/comment_body.rb +24 -0
- data/lib/ld4l/open_annotation_rdf/configuration.rb +127 -0
- data/lib/ld4l/open_annotation_rdf/semantic_tag_annotation.rb +66 -0
- data/lib/ld4l/open_annotation_rdf/semantic_tag_body.rb +70 -0
- data/lib/ld4l/open_annotation_rdf/tag_annotation.rb +98 -0
- data/lib/ld4l/open_annotation_rdf/tag_body.rb +83 -0
- data/lib/ld4l/open_annotation_rdf/version.rb +5 -0
- data/lib/ld4l/open_annotation_rdf/vocab/cnt.rb +6 -0
- data/lib/ld4l/open_annotation_rdf/vocab/dctypes.rb +5 -0
- data/lib/ld4l/open_annotation_rdf/vocab/oa.rb +23 -0
- data/spec/ld4l/open_annotation_rdf/annotation_spec.rb +603 -0
- data/spec/ld4l/open_annotation_rdf/comment_annotation_spec.rb +559 -0
- data/spec/ld4l/open_annotation_rdf/comment_body_spec.rb +371 -0
- data/spec/ld4l/open_annotation_rdf/configuration_spec.rb +194 -0
- data/spec/ld4l/open_annotation_rdf/semantic_tag_annotation_spec.rb +619 -0
- data/spec/ld4l/open_annotation_rdf/semantic_tag_body_spec.rb +412 -0
- data/spec/ld4l/open_annotation_rdf/tag_annotation_spec.rb +672 -0
- data/spec/ld4l/open_annotation_rdf/tag_body_spec.rb +430 -0
- data/spec/ld4l/open_annotation_rdf_spec.rb +57 -0
- data/spec/spec_helper.rb +21 -0
- metadata +201 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module LD4L
|
2
|
+
module OpenAnnotationRDF
|
3
|
+
class CommentAnnotation < LD4L::OpenAnnotationRDF::Annotation
|
4
|
+
|
5
|
+
@localname_prefix="ca"
|
6
|
+
|
7
|
+
property :hasBody, :predicate => RDFVocabularies::OA.hasBody, :class_name => LD4L::OpenAnnotationRDF::CommentBody
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
# Create a comment annotation body and set the hasBody property to it.
|
12
|
+
#
|
13
|
+
# @param [String]
|
14
|
+
#
|
15
|
+
# @return instance of SemanticTagBody
|
16
|
+
def setComment(comment)
|
17
|
+
@body = LD4L::OpenAnnotationRDF::CommentBody.new(
|
18
|
+
ActiveTriples::LocalName::Minter.generate_local_name(
|
19
|
+
LD4L::OpenAnnotationRDF::CommentBody, 10, @localname_prefix,
|
20
|
+
LD4L::OpenAnnotationRDF.configuration.localname_minter ))
|
21
|
+
@body.content = comment
|
22
|
+
@body.format = "text/plain"
|
23
|
+
set_value(:hasBody, @body)
|
24
|
+
@body
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Special processing for new and resumed CommentAnnotations
|
29
|
+
#
|
30
|
+
def initialize(*args)
|
31
|
+
super(*args)
|
32
|
+
|
33
|
+
# set motivatedBy
|
34
|
+
m = get_values(:motivatedBy)
|
35
|
+
set_value(:motivatedBy, RDFVocabularies::OA.commenting) unless m.kind_of?(Array) && m.size > 0
|
36
|
+
|
37
|
+
# resume CommentBody if it exists
|
38
|
+
comment_uri = get_values(:hasBody).first
|
39
|
+
if( comment_uri )
|
40
|
+
comment_uri = comment_uri.rdf_subject if comment_uri.kind_of?(ActiveTriples::Resource)
|
41
|
+
@body = LD4L::OpenAnnotationRDF::CommentBody.new(comment_uri)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module LD4L
|
2
|
+
module OpenAnnotationRDF
|
3
|
+
class CommentBody < ActiveTriples::Resource
|
4
|
+
|
5
|
+
class << self; attr_reader :localname_prefix end
|
6
|
+
@localname_prefix="cb"
|
7
|
+
|
8
|
+
configure :type => RDFVocabularies::CNT.ContentAsText,
|
9
|
+
:base_uri => LD4L::OpenAnnotationRDF.configuration.base_uri,
|
10
|
+
:repository => :default
|
11
|
+
|
12
|
+
property :content, :predicate => RDFVocabularies::CNT.chars # :type => XSD.string
|
13
|
+
property :format, :predicate => RDF::DC.format # :type => XSD.string
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super(*args)
|
17
|
+
|
18
|
+
t = get_values(:type)
|
19
|
+
t << RDFVocabularies::DCTYPES.Text
|
20
|
+
set_value(:type,t)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module LD4L
|
2
|
+
module OpenAnnotationRDF
|
3
|
+
|
4
|
+
# Used by LD4L::OpenAnnotationRDF class to configure...
|
5
|
+
# * base_uri
|
6
|
+
# * local_minter
|
7
|
+
# * unique_tags
|
8
|
+
#
|
9
|
+
# @example Configure all configurable properties
|
10
|
+
# LD4L::OpenAnnotationRDF.configure do |config|
|
11
|
+
# config.base_uri = "http://www.example.org/annotations/"
|
12
|
+
# config.localname_minter = lambda { |prefix=""| prefix+SecureRandom.uuid }
|
13
|
+
# config.unique_tags = true
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# @example Usage of base uri and local name
|
17
|
+
# # uri = base_uri + localname"
|
18
|
+
# annotation = LD4L::OpenAnnotationRDF::CommentAnnotation.new(
|
19
|
+
# ActiveTriples::LocalName::Minter.generate_local_name(
|
20
|
+
# LD4L::OpenAnnotationRDF::CommentBody, 10, 'a',
|
21
|
+
# LD4L::OpenAnnotationRDF.configuration.localname_minter ))
|
22
|
+
# annotation.rdf_subject
|
23
|
+
# # => "http://www.example.org/annotations/a9f85752c-9c2c-4a65-997a-68482895a656"
|
24
|
+
#
|
25
|
+
# @note Use LD4L::OpenAnnotationRDF.configure to call the methods in this class. See 'Configure all configurable
|
26
|
+
# properties' example for most common approach to configuration.
|
27
|
+
class Configuration
|
28
|
+
|
29
|
+
##
|
30
|
+
# @overload base_uri
|
31
|
+
# Get the base_uri to be used when generating rdf_subjects for new objects. See example configuration and usage in class documentation examples.
|
32
|
+
# @return the configured base_uri
|
33
|
+
# @overload base_uri=(new_base_uri)
|
34
|
+
# Set the base_uri to be used when generating rdf_subjects for new objects. See example configuration and usage in class documentation examples.
|
35
|
+
# @param [String] new value for the base_uri
|
36
|
+
# @note base_uri will only take effect when a model class is first created. Once the model class is created, the base_uri is bound to the class.
|
37
|
+
attr_reader :base_uri
|
38
|
+
|
39
|
+
##
|
40
|
+
# @overload localname_minter
|
41
|
+
# Get the localname_minter to be used when generating rdf_subjects for new objects. See example configuration and usage in class documentation examples.
|
42
|
+
# @return the configured localname_minter
|
43
|
+
# @overload localname_minter=(new_localname_minter)
|
44
|
+
# Set the localname_minter to be used when generating rdf_subjects for new objects. See example configuration and usage in class documentation examples.
|
45
|
+
# @param [String] new value for the localname_minter
|
46
|
+
attr_reader :localname_minter
|
47
|
+
|
48
|
+
##
|
49
|
+
# @overload unique_tags
|
50
|
+
# Get whether the GEM should enforce uniqueness of user generated tags when using
|
51
|
+
# the TagAnnotation::setTag method. See example configuration and usage in class documentation examples.
|
52
|
+
# @return the configured unique_tags
|
53
|
+
# @overload unique_tags=(new_unique_tags)
|
54
|
+
# Set whether the GEM should enforce uniqueness of user generated tags when using
|
55
|
+
# the TagAnnotation::setTag method.
|
56
|
+
# @param [Boolean] new value for the unique_tags
|
57
|
+
#
|
58
|
+
# true - enforce uniqueness (default)
|
59
|
+
# - annotations share TagBodys
|
60
|
+
# - setTag method looks for an existing TagBody with the tag value and reuses the existing TagBody
|
61
|
+
# - setTag to change a tag's value will create/reuse a different TagBody for the new tag value
|
62
|
+
# false - do not enforce uniqueness
|
63
|
+
# - annotation owns its TagBody
|
64
|
+
# - setTag first time call creates a TagBody with the tag value
|
65
|
+
# - setTag to change the tag's value will modify the tag value in this annotation's TagBody
|
66
|
+
attr_reader :unique_tags
|
67
|
+
|
68
|
+
def self.default_base_uri
|
69
|
+
@default_base_uri = "http://localhost/".freeze
|
70
|
+
end
|
71
|
+
private_class_method :default_base_uri
|
72
|
+
|
73
|
+
def self.default_localname_minter
|
74
|
+
# by setting to nil, it will use the default minter in the minter gem
|
75
|
+
@default_localname_minter = nil
|
76
|
+
end
|
77
|
+
private_class_method :default_localname_minter
|
78
|
+
|
79
|
+
def self.default_unique_tags
|
80
|
+
@default_unique_tags = true
|
81
|
+
end
|
82
|
+
private_class_method :default_unique_tags
|
83
|
+
|
84
|
+
def initialize
|
85
|
+
@base_uri = self.class.send(:default_base_uri)
|
86
|
+
@localname_minter = self.class.send(:default_localname_minter)
|
87
|
+
@unique_tags = self.class.send(:default_unique_tags)
|
88
|
+
end
|
89
|
+
|
90
|
+
def base_uri=(new_base_uri)
|
91
|
+
@base_uri = new_base_uri
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Reset the base_uri to be used when generating rdf_subject for new objects back to the default configuration.
|
96
|
+
#
|
97
|
+
def reset_base_uri
|
98
|
+
@base_uri = self.class.send(:default_base_uri)
|
99
|
+
end
|
100
|
+
|
101
|
+
def localname_minter=(new_minter)
|
102
|
+
@localname_minter = new_minter
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Reset the minter to be used to generate the local name portion of the rdf_subject for new objects to the
|
107
|
+
# default minter.
|
108
|
+
#
|
109
|
+
def reset_localname_minter
|
110
|
+
@localname_minter = self.class.send(:default_localname_minter)
|
111
|
+
end
|
112
|
+
|
113
|
+
def unique_tags=(new_unique_indicator)
|
114
|
+
@unique_tags = new_unique_indicator
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Reset whether the GEM should enforce uniqueness of user generated tags, when using
|
119
|
+
# the TagAnnotation::setTag method, to the default configuration (true).
|
120
|
+
#
|
121
|
+
# @see unique_tags=
|
122
|
+
def reset_unique_tags
|
123
|
+
@unique_tags = self.class.send(:default_unique_tags)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module LD4L
|
2
|
+
module OpenAnnotationRDF
|
3
|
+
class SemanticTagAnnotation < LD4L::OpenAnnotationRDF::Annotation
|
4
|
+
|
5
|
+
@localname_prefix = "sta"
|
6
|
+
|
7
|
+
# USAGE: Use setTerm to set the hasBody property to be the URI of the controlled vocabulary term that
|
8
|
+
# is the annotation.
|
9
|
+
|
10
|
+
# TODO: Should a semantic tag be destroyed when the last annotation referencing the term is destroyed?
|
11
|
+
|
12
|
+
##
|
13
|
+
# Set the hasBody property to the URI of the controlled vocabulary term that is the annotation and
|
14
|
+
# create the semantic tag body instance identifying the term as a semantic tag annotation.
|
15
|
+
#
|
16
|
+
# @param [String] controlled vocabulary uri for the term
|
17
|
+
#
|
18
|
+
# @return instance of SemanticTagBody
|
19
|
+
def setTerm(term_uri)
|
20
|
+
raise ArgumentError, 'Argument must be a uri string or an instance of RDF::URI' unless
|
21
|
+
term_uri.kind_of?(String) && term_uri.size > 0 || term_uri.kind_of?(RDF::URI)
|
22
|
+
|
23
|
+
# return existing body if term is unchanged
|
24
|
+
old_term_uri = @body ? @body.rdf_subject.to_s : nil
|
25
|
+
term_uri = RDF::URI(term_uri) unless term_uri.kind_of?(RDF::URI)
|
26
|
+
return @body if old_term_uri && old_term_uri == term_uri.to_s
|
27
|
+
|
28
|
+
@body = LD4L::OpenAnnotationRDF::SemanticTagBody.new(term_uri)
|
29
|
+
set_value(:hasBody, @body)
|
30
|
+
@body
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Special processing for new and resumed SemanticTagAnnotations
|
35
|
+
#
|
36
|
+
def initialize(*args)
|
37
|
+
super(*args)
|
38
|
+
|
39
|
+
# set motivatedBy
|
40
|
+
m = get_values(:motivatedBy)
|
41
|
+
set_value(:motivatedBy, RDFVocabularies::OA.tagging) unless m.kind_of?(Array) && m.size > 0
|
42
|
+
|
43
|
+
# resume SemanticTagBody if it exists
|
44
|
+
term_uri = get_values(:hasBody).first
|
45
|
+
if( term_uri )
|
46
|
+
term_uri = term_uri.rdf_subject if term_uri.kind_of?(ActiveTriples::Resource)
|
47
|
+
@body = LD4L::OpenAnnotationRDF::SemanticTagBody.new(term_uri)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def destroy
|
52
|
+
# TODO Determine behavior of destroy
|
53
|
+
# Behaviour Options
|
54
|
+
# * Always destroy SemanticTagAnnotation
|
55
|
+
# * Handling of SemanticTagBody
|
56
|
+
# ** If SemanticTagBody is used only by this SemanticTagAnnotation, destroy it.
|
57
|
+
# ** Otherwise, do not destroy it.
|
58
|
+
# TODO Write tests for this behaviour.
|
59
|
+
# TODO Write code here to enforce.
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module LD4L
|
2
|
+
module OpenAnnotationRDF
|
3
|
+
class SemanticTagBody < ActiveTriples::Resource
|
4
|
+
|
5
|
+
class << self; attr_reader :localname_prefix end
|
6
|
+
@localname_prefix="stb"
|
7
|
+
|
8
|
+
# USAGE: When creating a semantic tag body, use the URI of the controlled vocabulary term as the RDF Subject URI
|
9
|
+
# for an instance of this class.
|
10
|
+
|
11
|
+
configure :type => RDFVocabularies::OA.SemanticTag,
|
12
|
+
:base_uri => LD4L::OpenAnnotationRDF.configuration.base_uri,
|
13
|
+
:repository => :default
|
14
|
+
|
15
|
+
##
|
16
|
+
# Get a list of annotations using a term.
|
17
|
+
#
|
18
|
+
# @param [String] controlled vocabulary uri for the term
|
19
|
+
#
|
20
|
+
# @return array of annotation URIs
|
21
|
+
#
|
22
|
+
# NOTE: This method returns only persisted annotations.
|
23
|
+
def self::annotations_using( term_uri )
|
24
|
+
raise ArgumentError, 'Argument must be a uri string or an instance of RDF::URI' unless
|
25
|
+
term_uri.kind_of?(String) && term_uri.size > 0 || term_uri.kind_of?(RDF::URI)
|
26
|
+
|
27
|
+
term_uri = RDF::URI(term_uri) unless term_uri.kind_of?(RDF::URI)
|
28
|
+
|
29
|
+
# find usage by Annotations
|
30
|
+
graph = ActiveTriples::Repositories.repositories[repository]
|
31
|
+
query = RDF::Query.new({
|
32
|
+
:annotation => {
|
33
|
+
RDF.type => RDFVocabularies::OA.Annotation,
|
34
|
+
RDFVocabularies::OA.hasBody => term_uri,
|
35
|
+
}
|
36
|
+
})
|
37
|
+
annotations = []
|
38
|
+
results = query.execute(graph)
|
39
|
+
results.each { |r| annotations << r.to_hash[:annotation] }
|
40
|
+
annotations
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
##
|
45
|
+
# Destroy the SemanticTagBody only if the term is not used by another SemanticAnnotation
|
46
|
+
#
|
47
|
+
# @param [String] controlled vocabulary uri for the term
|
48
|
+
#
|
49
|
+
# @return true if destroyed; otherwise, false if used by other annotations
|
50
|
+
#
|
51
|
+
# NOTE: Use this method after changing the term AND persisting the annotation on which the term was changed.
|
52
|
+
def self::destroy_if_unused( term_uri )
|
53
|
+
raise ArgumentError, 'Argument must be a uri string or an instance of RDF::URI' unless
|
54
|
+
term_uri.kind_of?(String) && term_uri.size > 0 || term_uri.kind_of?(RDF::URI)
|
55
|
+
|
56
|
+
term_uri = RDF::URI(term_uri) unless term_uri.kind_of?(RDF::URI)
|
57
|
+
|
58
|
+
# find usage by Annotations
|
59
|
+
annotations = self::annotations_using( term_uri )
|
60
|
+
destroyed = false
|
61
|
+
if( annotations.empty? )
|
62
|
+
stb = LD4L::OpenAnnotationRDF::SemanticTagBody.new(term_uri)
|
63
|
+
destroyed = stb.destroy!
|
64
|
+
end
|
65
|
+
destroyed
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module LD4L
|
2
|
+
module OpenAnnotationRDF
|
3
|
+
class TagAnnotation < LD4L::OpenAnnotationRDF::Annotation
|
4
|
+
|
5
|
+
@localname_prefix="ta"
|
6
|
+
|
7
|
+
property :hasBody, :predicate => RDFVocabularies::OA.hasBody, :class_name => LD4L::OpenAnnotationRDF::TagBody
|
8
|
+
|
9
|
+
# TODO: Should a tag be destroyed when the last annotation referencing the tag is destroyed?
|
10
|
+
|
11
|
+
##
|
12
|
+
# Set the hasBody property to the URI of the one and only TagBody holding the tag value. Create a new TagBody
|
13
|
+
# if one doesn't exist with this value.
|
14
|
+
#
|
15
|
+
# @param [String] tag value
|
16
|
+
#
|
17
|
+
# @return instance of TagBody
|
18
|
+
def setTag(tag)
|
19
|
+
raise ArgumentError, 'Argument must be a string with at least one character' unless tag.kind_of?(String) && tag.size > 0
|
20
|
+
|
21
|
+
# return existing body if tag value is unchanged
|
22
|
+
old_tag = @body ? @body.tag : nil
|
23
|
+
return @body if old_tag && old_tag.include?(tag)
|
24
|
+
|
25
|
+
if LD4L::OpenAnnotationRDF.configuration.unique_tags
|
26
|
+
# when unique_tags = true, try to find an existing TagBody with the tag value before creating a new TagBody
|
27
|
+
# TODO Determine behavior of setTag when unique_tags=true
|
28
|
+
# Behaviour Options:
|
29
|
+
# * Look for an existing TagBody with this value.
|
30
|
+
# ** If none found, create a new TagBody.
|
31
|
+
# ** If one found, set @body to this TagBody
|
32
|
+
# ** If multiple found, use the first one found
|
33
|
+
# ### the same one may not be the first one found each time the query executes
|
34
|
+
@body = LD4L::OpenAnnotationRDF.configuration.unique_tags ? LD4L::OpenAnnotationRDF::TagBody.fetch_by_tag_value(tag) : nil
|
35
|
+
if @body == nil
|
36
|
+
@body = LD4L::OpenAnnotationRDF::TagBody.new(
|
37
|
+
ActiveTriples::LocalName::Minter.generate_local_name(
|
38
|
+
LD4L::OpenAnnotationRDF::TagBody, 10, @localname_prefix,
|
39
|
+
LD4L::OpenAnnotationRDF.configuration.localname_minter ))
|
40
|
+
@body.tag = tag
|
41
|
+
end
|
42
|
+
else
|
43
|
+
# when unique_tags = false, ??? (see TODO)
|
44
|
+
# TODO Determine behavior of setTag when unique_tags=false
|
45
|
+
# Behaviour Options:
|
46
|
+
# * If this TagAnnotation does not have a TagBody (@body) set, then create a new TagBody.
|
47
|
+
# * If this TagBody is used only by this TagAnnotation, then change the value in the TagBody.
|
48
|
+
# * If this TagBody is used by multiple TagAnnotations,
|
49
|
+
# ** EITHER change the value in the TagBody which changes it for all the TagAnnotations.
|
50
|
+
# ### Likely an undesirable side effect having the value change for all TagAnnotations
|
51
|
+
# ** OR create a new TagBody and update @body to that TagBody
|
52
|
+
# OR
|
53
|
+
# * [CURRENT] Always create a new TagBody each time setTag is called and update @body
|
54
|
+
# ### This last options has the potential for orphaned TagBodys that no TagAnnotation references.
|
55
|
+
# TODO Rethink the current behavior which is always to create a new TagBody potentially leaving around orphans.
|
56
|
+
@body = LD4L::OpenAnnotationRDF::TagBody.new(
|
57
|
+
ActiveTriples::LocalName::Minter.generate_local_name(
|
58
|
+
LD4L::OpenAnnotationRDF::TagBody, 10, @localname_prefix,
|
59
|
+
LD4L::OpenAnnotationRDF.configuration.localname_minter ))
|
60
|
+
@body.tag = tag
|
61
|
+
end
|
62
|
+
set_value(:hasBody, @body)
|
63
|
+
@body
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Special processing for new and resumed TagAnnotations
|
68
|
+
#
|
69
|
+
def initialize(*args)
|
70
|
+
super(*args)
|
71
|
+
|
72
|
+
# set motivatedBy
|
73
|
+
m = get_values(:motivatedBy)
|
74
|
+
set_value(:motivatedBy, RDFVocabularies::OA.tagging) unless m.kind_of?(Array) && m.size > 0
|
75
|
+
|
76
|
+
# resume TagBody if it exists
|
77
|
+
tag_uri = get_values(:hasBody).first
|
78
|
+
if( tag_uri )
|
79
|
+
tag_uri = tag_uri.rdf_subject if tag_uri.kind_of?(ActiveTriples::Resource)
|
80
|
+
@body = LD4L::OpenAnnotationRDF::TagBody.new(tag_uri)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def destroy
|
85
|
+
# TODO Determine behavior of destroy
|
86
|
+
# Behaviour Options
|
87
|
+
# * Always destroy TagAnnotation
|
88
|
+
# * Handling of TagBody
|
89
|
+
# ** If TagBody is used only by this TagAnnotation, destroy it.
|
90
|
+
# ** Otherwise, do not destroy it.
|
91
|
+
# TODO Write tests for this behaviour.
|
92
|
+
# TODO Write code here to enforce.
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module LD4L
|
2
|
+
module OpenAnnotationRDF
|
3
|
+
class TagBody < ActiveTriples::Resource
|
4
|
+
|
5
|
+
class << self; attr_reader :localname_prefix end
|
6
|
+
@localname_prefix="tb"
|
7
|
+
|
8
|
+
configure :type => RDFVocabularies::OA.Tag,
|
9
|
+
:base_uri => LD4L::OpenAnnotationRDF.configuration.base_uri,
|
10
|
+
:repository => :default
|
11
|
+
|
12
|
+
property :tag, :predicate => RDFVocabularies::CNT.chars # :type => XSD.string
|
13
|
+
|
14
|
+
##
|
15
|
+
# Get a list of annotations using the tag value.
|
16
|
+
#
|
17
|
+
# @param [String] tag value
|
18
|
+
#
|
19
|
+
# @return array of annotation URIs
|
20
|
+
#
|
21
|
+
# NOTE: This method returns only persisted annotations.
|
22
|
+
def self::annotations_using( tag_value )
|
23
|
+
raise ArgumentError, 'Argument must be a string with at least one character' unless
|
24
|
+
tag_value.kind_of?(String) && tag_value.size > 0
|
25
|
+
|
26
|
+
tb = self::fetch_by_tag_value( tag_value )
|
27
|
+
return [] unless tb
|
28
|
+
tag_uri = tb.rdf_subject
|
29
|
+
|
30
|
+
# find usage by Annotations
|
31
|
+
graph = ActiveTriples::Repositories.repositories[repository]
|
32
|
+
query = RDF::Query.new({
|
33
|
+
:annotation => {
|
34
|
+
RDF.type => RDFVocabularies::OA.Annotation,
|
35
|
+
RDFVocabularies::OA.hasBody => tag_uri,
|
36
|
+
}
|
37
|
+
})
|
38
|
+
results = query.execute(graph)
|
39
|
+
|
40
|
+
# process results
|
41
|
+
annotations = []
|
42
|
+
results.each { |r| annotations << r.to_hash[:annotation] }
|
43
|
+
annotations
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
##
|
48
|
+
# Search the configured repository for a TagBody triple that has the tag value for the tag property.
|
49
|
+
#
|
50
|
+
# @param [String] tag value
|
51
|
+
#
|
52
|
+
# @return instance of TagBody if found; otherwise, nil
|
53
|
+
def self::fetch_by_tag_value( tag_value )
|
54
|
+
raise ArgumentError, 'Argument must be a string with at least one character' unless
|
55
|
+
tag_value.kind_of?(String) && tag_value.size > 0
|
56
|
+
|
57
|
+
graph = ActiveTriples::Repositories.repositories[repository]
|
58
|
+
query = RDF::Query.new({
|
59
|
+
:tagbody => {
|
60
|
+
RDF.type => RDFVocabularies::OA.Tag,
|
61
|
+
RDFVocabularies::CNT.chars => tag_value,
|
62
|
+
}
|
63
|
+
})
|
64
|
+
|
65
|
+
tagbody = nil
|
66
|
+
results = query.execute(graph)
|
67
|
+
unless( results.empty? )
|
68
|
+
tagbody_uri = results[0].to_hash[:tagbody]
|
69
|
+
tagbody = LD4L::OpenAnnotationRDF::TagBody.new(tagbody_uri)
|
70
|
+
end
|
71
|
+
tagbody
|
72
|
+
end
|
73
|
+
|
74
|
+
def initialize(*args)
|
75
|
+
super(*args)
|
76
|
+
|
77
|
+
t = get_values(:type)
|
78
|
+
t << RDFVocabularies::CNT.ContentAsText
|
79
|
+
set_value(:type,t)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|