rtm 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/activetopicmaps.rb +229 -0
- data/lib/rtm/backend/active_record/association_and_role.rb +54 -0
- data/lib/rtm/backend/active_record/locators.rb +53 -0
- data/lib/rtm/backend/active_record/name_variant_occurrence.rb +44 -0
- data/lib/rtm/backend/active_record/quaaxtm2rtm.rb +113 -0
- data/lib/rtm/backend/active_record/quaaxtm2rtmviews.rb +134 -0
- data/lib/rtm/backend/active_record/set_wrapper.rb +98 -0
- data/lib/rtm/backend/active_record/tm_construct.rb +62 -0
- data/lib/rtm/backend/active_record/tm_delegator.rb +420 -0
- data/lib/rtm/backend/active_record/tm_set_delegator.rb +195 -0
- data/lib/rtm/backend/active_record/tmdm.rb +0 -1
- data/lib/rtm/backend/active_record/topic.rb +153 -0
- data/lib/rtm/backend/active_record/topic_map.rb +285 -0
- data/lib/rtm/backend/active_record.rb +9 -1350
- data/lib/rtm/io/to_jtm.rb +5 -1
- metadata +74 -68
@@ -0,0 +1,195 @@
|
|
1
|
+
module RTM::AR
|
2
|
+
class TMSetDelegator < TMDelegator
|
3
|
+
include Enumerable
|
4
|
+
# attr_reader :content_class_name
|
5
|
+
def initialize(obj,parent,type)
|
6
|
+
@obj = obj
|
7
|
+
@parent = parent
|
8
|
+
@type = type
|
9
|
+
end
|
10
|
+
|
11
|
+
# This class method wraps a Set completely while the instance method wraps one single contained object
|
12
|
+
def self.wrap(obj, parent=nil, type=nil)
|
13
|
+
return nil unless obj
|
14
|
+
raise "Double wrapping" if obj.respond_to?(:__getobj__)
|
15
|
+
self.new(obj, parent, type)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(obj)
|
19
|
+
return unless obj
|
20
|
+
|
21
|
+
old = @obj.detect { |x| x == obj } # can't that be done easier?
|
22
|
+
if old
|
23
|
+
old.merge obj
|
24
|
+
else
|
25
|
+
if obj.respond_to? :__getobj__
|
26
|
+
@obj << obj.__getobj__
|
27
|
+
else
|
28
|
+
case @type
|
29
|
+
when :Topic
|
30
|
+
@obj << @parent.topic_map.get!(obj).__getobj__
|
31
|
+
@parent.__getobj__.reload
|
32
|
+
|
33
|
+
when :ItemIdentifier
|
34
|
+
if @parent.class.name.to_s =~ /::Topic$/
|
35
|
+
tbi = @parent.topic_map._item_identifier(obj)
|
36
|
+
if tbi && tmc=tbi.topic_map_construct
|
37
|
+
if tmc.class.name =~ /::Topic$/
|
38
|
+
return @parent if tmc == @parent.__getobj__
|
39
|
+
result = Topic.wrap(tmc).merge @parent
|
40
|
+
return result
|
41
|
+
else
|
42
|
+
raise "Duplicate Item Identifier"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
tbsi = @parent.topic_map._subject_identifier(obj.to_s)
|
46
|
+
if tbsi
|
47
|
+
if t=tbsi.topic
|
48
|
+
return @parent if t == @parent.__getobj__
|
49
|
+
result = Topic.wrap(t).merge @parent
|
50
|
+
# after merging, we still need to add the II
|
51
|
+
result.__getobj__.item_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
52
|
+
return result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
result = @obj << @parent.topic_map._item_identifier!(obj.to_s)
|
57
|
+
return result
|
58
|
+
|
59
|
+
when :SubjectIdentifier
|
60
|
+
# check for existing item identifier
|
61
|
+
tbi = @parent.topic_map._item_identifier(obj)
|
62
|
+
if tbi && tmc=tbi.topic_map_construct
|
63
|
+
if tmc.class.name =~ /::Topic$/
|
64
|
+
return @parent if tmc == @parent.__getobj__
|
65
|
+
result = Topic.wrap(tmc).merge @parent
|
66
|
+
# after merging, we still need to add the SI
|
67
|
+
result.__getobj__.subject_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
68
|
+
return result
|
69
|
+
else
|
70
|
+
warn("This subject identifier IRI already belongs to another topic map construct (not a topic)")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
# check for existing subject identifier
|
74
|
+
tbsi = @parent.topic_map._subject_identifier(obj.to_s)
|
75
|
+
if tbsi
|
76
|
+
if true && t=tbsi.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning
|
77
|
+
return @parent if t == @parent.__getobj__
|
78
|
+
result = Topic.wrap(t).merge @parent
|
79
|
+
return result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
@obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
83
|
+
|
84
|
+
when :SubjectLocator
|
85
|
+
tbsl = @parent.topic_map._subject_locator(obj.to_s)
|
86
|
+
if tbsl
|
87
|
+
if true && t=tbsl.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning
|
88
|
+
return @parent if t == @parent.__getobj__
|
89
|
+
result = Topic.wrap(t).merge @parent
|
90
|
+
return result
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
alias :<< :add
|
100
|
+
|
101
|
+
def add_all(objs)
|
102
|
+
return unless objs
|
103
|
+
objs.each {|obj| add(obj)}
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
def each(&b)
|
108
|
+
@obj.each { |e| yield wrap(e)}
|
109
|
+
end
|
110
|
+
|
111
|
+
def size
|
112
|
+
@obj.size
|
113
|
+
end
|
114
|
+
alias :length :size
|
115
|
+
|
116
|
+
def empty?
|
117
|
+
@obj.empty?
|
118
|
+
end
|
119
|
+
|
120
|
+
def delete(obj)
|
121
|
+
obj = obj.__getobj__ if obj.respond_to? :__getobj__
|
122
|
+
case @type
|
123
|
+
when :ItemIdentifier, :SubjectIdentifier, :SubjectLocator
|
124
|
+
obj = @obj.find_by_reference(@parent.topic_map.resolve(obj.to_s)) if obj.is_a? String
|
125
|
+
end
|
126
|
+
@obj.delete(obj)
|
127
|
+
# item_identifiers: remove also from topicMap
|
128
|
+
#removed_event obj if respond_to? :removed_event
|
129
|
+
end
|
130
|
+
alias :remove :delete
|
131
|
+
|
132
|
+
def include?(obj)
|
133
|
+
return @obj.include?(obj)
|
134
|
+
#@obj.each { |e| return true if e == obj } # T#ODO support for get
|
135
|
+
#false
|
136
|
+
end
|
137
|
+
|
138
|
+
def first
|
139
|
+
wrap(@obj.entries.first)
|
140
|
+
end
|
141
|
+
def last
|
142
|
+
wrap(@obj.entries.last)
|
143
|
+
end
|
144
|
+
|
145
|
+
def to_s
|
146
|
+
"[#{@obj.entries.map { |e| wrap(e).to_s }.join(", ") }]"
|
147
|
+
end
|
148
|
+
def [](i)
|
149
|
+
wrap(@obj[i])
|
150
|
+
end
|
151
|
+
|
152
|
+
def content_class
|
153
|
+
# @content_class ||= RTM.const_get(@content_class_name)
|
154
|
+
@content_class ||= RTM.const_get("#{@content_class_name}MemImpl")
|
155
|
+
end
|
156
|
+
|
157
|
+
def find(*args)
|
158
|
+
res = @obj.find(*args)
|
159
|
+
if res.respond_to? :each
|
160
|
+
TopicMapConstructs.wrap(res)
|
161
|
+
else
|
162
|
+
TopicMapConstruct.wrap(res)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def &(other)
|
167
|
+
@obj.to_a & other.to_a
|
168
|
+
end
|
169
|
+
|
170
|
+
alias :old_method_missing :method_missing
|
171
|
+
def method_missing(method_name, *args)
|
172
|
+
if @obj.size > 0 && first.respond_to?(method_name) && (![:__getobj__, :__setobj__].include?(method_name))
|
173
|
+
a = []
|
174
|
+
inject(a) {|all,single| all << single.send(method_name, *args)}
|
175
|
+
a
|
176
|
+
else
|
177
|
+
old_method_missing(method_name, *args)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
alias :old_respond_to? :respond_to?
|
182
|
+
def respond_to?(method_name)
|
183
|
+
resp = old_respond_to?(method_name)
|
184
|
+
return resp if resp # i.e. if true
|
185
|
+
return false if [:__getobj__, :__setobj__].include?(method_name)
|
186
|
+
# ... and ask first child otherwise
|
187
|
+
@obj.size > 0 && first.respond_to?(method_name)
|
188
|
+
end
|
189
|
+
|
190
|
+
# TMSetDelegator#to_a doesn't help as thought, but maybe we come back to that l8r...
|
191
|
+
#def to_a
|
192
|
+
# @obj.map {|o| wrap(o)}
|
193
|
+
#end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module RTM::AR
|
2
|
+
class Topic < TopicMapConstruct
|
3
|
+
include RTM::Topic
|
4
|
+
wrapper_cache
|
5
|
+
|
6
|
+
parent :topic_map
|
7
|
+
property_set :subject_identifiers, :aka => [:si,:sid], :type => :SubjectIdentifier, :wrap => true,
|
8
|
+
#:create => :subject_identifier, :create_aka => [:csi,:csid],
|
9
|
+
#:create_args => [{:name => :reference, :type => :String}]
|
10
|
+
:add => true, :remove => true
|
11
|
+
property_set :subject_locators, :aka => [:sl,:slo], :type => :SubjectLocator, :wrap => true,
|
12
|
+
#:create => :subject_locator, :create_aka => [:csl, :cslo],
|
13
|
+
#:create_args => [{:name => :reference, :type => :String}]
|
14
|
+
:add => true, :remove => true
|
15
|
+
|
16
|
+
property :reified, :computable => true, :type => :Reifiable, :wrap => true
|
17
|
+
|
18
|
+
property_set :topic_names, :aka => [:n, :names], :type => :TopicName, :wrap => true,
|
19
|
+
:create => :topic_name, :create_aka => [:create_name, :cn],
|
20
|
+
:create_args => [ {:name => :value, :type => :String}, {:name => :type, :type => :Topic, :optional => true}, {:name => :scope, :type => :Collection} ]
|
21
|
+
|
22
|
+
property_set :occurrences, :aka => :o, :type => :Occurrence, :wrap => true,
|
23
|
+
:create => :occurrence, :create_aka => :co,
|
24
|
+
:create_args => [ {:name => :value, :type => [:String, :Locator]}, {:name => :type, :type => :Topic}, {:name => :scope, :type => :Collection} ]
|
25
|
+
|
26
|
+
def characteristics
|
27
|
+
topic_names.to_a + occurrences.to_a
|
28
|
+
end
|
29
|
+
def internal_occurrences
|
30
|
+
occurrences.select{|o| o.datatype != RTM::PSI[:IRI]}
|
31
|
+
end
|
32
|
+
def external_occurrences
|
33
|
+
occurrences.select{|o| o.datatype == RTM::PSI[:IRI]}
|
34
|
+
end
|
35
|
+
|
36
|
+
property_set :roles, :aka => [:r, :roles_played, :association_roles], :computable => true, :type => :AssociationRole, :wrap => true
|
37
|
+
|
38
|
+
property_set :associations, :aka => [:a, :associations_played], :type => :Association, :wrap => true
|
39
|
+
|
40
|
+
property_set :scoped_objects, :type => :TopicMapConstruct, :wrap => true
|
41
|
+
property_set :scoped_associations, :type => :Association, :wrap => true
|
42
|
+
property_set :scoped_topic_names, :aka => :scoped_names, :type => :TopicName, :wrap => true
|
43
|
+
property_set :scoped_variants, :type => :Variant, :wrap => true
|
44
|
+
property_set :scoped_occurrences, :type => :Occurrence, :wrap => true
|
45
|
+
|
46
|
+
property_set :associations_typed, :aka => :at, :type => :Association, :wrap => true
|
47
|
+
property_set :association_roles_typed, :aka => [:roles_typed,:art,:rt], :type => :AssociationRole, :wrap => true
|
48
|
+
property_set :topic_names_typed, :aka => [:names_typed,:tnt,:nt], :type => :TopicName, :wrap => true
|
49
|
+
property_set :occurrences_typed, :aka => :ot, :type => :Occurrence, :wrap => true
|
50
|
+
|
51
|
+
# maybe these pairs could be declared each with a single statement and a reversible option
|
52
|
+
index_property_set :types, :type => :Topic, :rule => {
|
53
|
+
:transitive => false,
|
54
|
+
:role_type => RTM::PSI[:instance],
|
55
|
+
:association_type => RTM::PSI[:type_instance],
|
56
|
+
:association_arity => 2,
|
57
|
+
:other_role_type => RTM::PSI[:type],
|
58
|
+
:infer_other => :supertypes,
|
59
|
+
:add => :type,
|
60
|
+
}
|
61
|
+
index_property_set :instances, :type => :Topic, :rule => {
|
62
|
+
:transitive => false,
|
63
|
+
:role_type => RTM::PSI[:type],
|
64
|
+
:association_type => RTM::PSI[:type_instance],
|
65
|
+
:association_arity => 2,
|
66
|
+
:other_role_type => RTM::PSI[:instance],
|
67
|
+
:infer => :subtypes,
|
68
|
+
:add => :instance,
|
69
|
+
}
|
70
|
+
index_property_set :supertypes, :type => :Topic, :rule => {
|
71
|
+
:transitive => true,
|
72
|
+
:role_type => RTM::PSI[:subtype],
|
73
|
+
:association_type => RTM::PSI[:supertype_subtype],
|
74
|
+
:association_arity => 2,
|
75
|
+
:other_role_type => RTM::PSI[:supertype],
|
76
|
+
:add => :supertype,
|
77
|
+
}
|
78
|
+
index_property_set :subtypes, :type => :Topic, :rule => {
|
79
|
+
:transitive => true,
|
80
|
+
:role_type => RTM::PSI[:supertype],
|
81
|
+
:association_type => RTM::PSI[:supertype_subtype],
|
82
|
+
:association_arity => 2,
|
83
|
+
:other_role_type => RTM::PSI[:subtype],
|
84
|
+
:add => :subtype,
|
85
|
+
}
|
86
|
+
|
87
|
+
def [](topicref)
|
88
|
+
topicref =~ /^(-\s*)?(.+)?$/
|
89
|
+
if $1
|
90
|
+
nametype = $2 || RTM::PSI[:name_type]
|
91
|
+
names.select{|n| n.type == topic_map.get(nametype)}
|
92
|
+
else
|
93
|
+
raise "No occurrence type given" unless $2 and !$2.empty?
|
94
|
+
occurrences.select{|o| o.type == topic_map.get($2)}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def []=(topicref, value)
|
99
|
+
topicref =~ /^(-\s*)?(.+)?$/
|
100
|
+
if $1
|
101
|
+
nametype = $2 || topic_map.get!(RTM::PSI[:name_type])
|
102
|
+
n = create_name(value, nametype)
|
103
|
+
n
|
104
|
+
else
|
105
|
+
raise "No occurrence type given" unless $2
|
106
|
+
o = create_occurrence(value, $2)
|
107
|
+
o
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def counterparts
|
112
|
+
self.roles.map{|sr| sr.parent.roles.reject{|r| r.id==sr.id}}
|
113
|
+
end
|
114
|
+
def counterplayers
|
115
|
+
self.counterparts.map{|r| r.player}
|
116
|
+
end
|
117
|
+
|
118
|
+
# class:Topic equality, http://www.isotopicmaps.org/sam/sam-model/#d0e1029
|
119
|
+
#
|
120
|
+
# This method is all crap. These ActiveRecord Arrays can't be intersected,
|
121
|
+
# so I map the identifiers to their reference which seems long winded.
|
122
|
+
# Still I find it better than using their ID in the long.
|
123
|
+
#
|
124
|
+
def ==(o)
|
125
|
+
return false unless o
|
126
|
+
# Two topic items are equal if they have:
|
127
|
+
# * at least one equal string in their [subject identifiers] properties,
|
128
|
+
# -> test if intersection are > 0
|
129
|
+
my_si = self.subject_identifiers.map{|si| si.reference}
|
130
|
+
ot_si = o.subject_identifiers.map{|si| si.reference}
|
131
|
+
return true if ( my_si & ot_si).size > 0
|
132
|
+
|
133
|
+
# * at least one equal string in their [item identifiers] properties,
|
134
|
+
my_ii = self.item_identifiers.map{|ii| ii.reference}
|
135
|
+
ot_ii = o.item_identifiers.map{|ii| ii.reference}
|
136
|
+
return true if (my_ii & ot_ii).size > 0
|
137
|
+
|
138
|
+
# * at least one equal string in their [subject locators] properties,
|
139
|
+
my_sl = self.subject_locators.map{|sl| sl.reference}
|
140
|
+
ot_sl = o.subject_locators.map{|sl| sl.reference}
|
141
|
+
return true if (my_sl & ot_sl).size > 0
|
142
|
+
|
143
|
+
# * an equal string in the [subject identifiers] property of the one topic item and the [item identifiers] property of the other, or
|
144
|
+
return true if (my_si & ot_ii).size > 0
|
145
|
+
return true if (my_ii & ot_si).size > 0
|
146
|
+
|
147
|
+
# * the same information item in their [reified] properties.
|
148
|
+
return true if self.reified != nil && o.reified != nil && (self.reified == o.reified)
|
149
|
+
# ... otherwise
|
150
|
+
false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
module RTM::AR
|
2
|
+
class TopicMap < Reifiable
|
3
|
+
include RTM::TopicMap
|
4
|
+
wrapper_cache
|
5
|
+
property_set :topics, :aka => :t, :type => :Topic, :wrap => true,
|
6
|
+
:create => :topic, :create_aka => :ct
|
7
|
+
|
8
|
+
property_set :associations, :aka => [:a, :assocs], :type => :Association, :wrap => true,
|
9
|
+
:create => :association, :create_aka => :ca,
|
10
|
+
:create_args => [{:name => :type, :type => :Topic}]
|
11
|
+
|
12
|
+
|
13
|
+
delegate :base_locator
|
14
|
+
|
15
|
+
property_set :association_types, :aka => :at, :type => :Topic, :wrap => true
|
16
|
+
property_set :association_role_types, :aka => [:role_types,:art,:rt], :type => :Topic, :wrap => true
|
17
|
+
property_set :topic_name_types, :aka => [:name_types,:tnt,:nt], :type => :Topic, :wrap => true
|
18
|
+
property_set :occurrence_types, :aka => :ot, :type => :Topic, :wrap => true
|
19
|
+
|
20
|
+
property_set :topic_names, :aka => [:names,:n], :type => :TopicName, :wrap => :true
|
21
|
+
property_set :occurrences, :aka => :o, :type => :Occurrence, :wrap => :true
|
22
|
+
property_set :association_roles, :aka => [:roles, :r], :type => :AssociationRole, :wrap => :true
|
23
|
+
|
24
|
+
def types
|
25
|
+
topics.select{|t| t.instances.size > 0}
|
26
|
+
end
|
27
|
+
alias :topic_types :types
|
28
|
+
def fast_types
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# This fetches all topics who have no topic-instances (but they might be types for associations etc.).
|
33
|
+
# See indivduals
|
34
|
+
def non_types
|
35
|
+
topics.select{|t| t.instances.size == 0}
|
36
|
+
end
|
37
|
+
|
38
|
+
# This fetches all topics which are not type for something else (including topics, associations etc.).
|
39
|
+
# See non_types
|
40
|
+
def individuals
|
41
|
+
non_types.select{|t| t.associations_typed.size==0 && t.roles_typed.size==0 && t.names_typed.size==0 && t.occurrences_typed.size==0}
|
42
|
+
end
|
43
|
+
def instances
|
44
|
+
topics.select{|t| t.types.size > 0}
|
45
|
+
end
|
46
|
+
def non_instances
|
47
|
+
topics.reject{|t| t.types.size > 0}
|
48
|
+
end
|
49
|
+
def internal_occurrences
|
50
|
+
occurrences.select{|o| o.datatype != RTM::PSI[:IRI]}
|
51
|
+
end
|
52
|
+
def external_occurrences
|
53
|
+
occurrences.select{|o| o.datatype == RTM::PSI[:IRI]}
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.create(base_locator, params={})
|
57
|
+
tm = self.wrap(TMDM::TopicMap.find_or_create_by_base_locator(base_locator))
|
58
|
+
yield tm if block_given?
|
59
|
+
tm
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.topic_maps
|
63
|
+
TopicMaps.wrap(TMDM::TopicMap.find(:all))
|
64
|
+
end
|
65
|
+
|
66
|
+
# Resolves an IRI or fragment relative to the base_locator of this topic_map or an optional given alternative_base_locator
|
67
|
+
#
|
68
|
+
# Absolute IRIs are taken as is.
|
69
|
+
#
|
70
|
+
# Relative IRIs:
|
71
|
+
# If the base_locator is a directory (ends with "/") it is appended like a file, i.e. directly
|
72
|
+
# If the base_locator is a file it is appended as a fragment (with # in between)
|
73
|
+
def resolve(obj,alternative_base_locator=nil)
|
74
|
+
uri = obj.to_s
|
75
|
+
# TODO uri = URI.decode(obj.to_s) # this InvalidURIError somethimes :(
|
76
|
+
begin
|
77
|
+
uri_uri = URI.parse(uri)
|
78
|
+
rescue URI::InvalidComponentError => ice
|
79
|
+
warn "Catched an URI::InvalidComponentError for URI: #{uri}, message was \"#{ice.message}\"\n" +
|
80
|
+
"Will continue using the UNRESOLVED IRI, claiming it is absolute."
|
81
|
+
return uri
|
82
|
+
end
|
83
|
+
if uri_uri.absolute?
|
84
|
+
return uri_uri.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
uri = uri[1..-1] if uri[0] == "#"[0]
|
88
|
+
bl = alternative_base_locator || base_locator
|
89
|
+
if bl[-1,1] == "/"
|
90
|
+
return bl + uri
|
91
|
+
else
|
92
|
+
return bl + "#" + uri
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#private
|
97
|
+
|
98
|
+
def _item_identifier(iid)
|
99
|
+
__getobj__.locators.find_by_reference(resolve(iid)) # doesn't work :( --> , :include => [ :topic_map_construct ])
|
100
|
+
end
|
101
|
+
def _item_identifier!(iid)
|
102
|
+
__getobj__.locators.find_or_create_by_reference(resolve(iid)) # doesn't work :( --> , :include => [ :topic_map_construct ])
|
103
|
+
end
|
104
|
+
|
105
|
+
def _subject_identifier(iid)
|
106
|
+
__getobj__.subject_identifiers.find_by_reference(iid, :include => :topic)
|
107
|
+
end
|
108
|
+
def _subject_identifier!(iid)
|
109
|
+
__getobj__.subject_identifiers.find_or_create_by_reference(iid, :include => :topic)
|
110
|
+
end
|
111
|
+
|
112
|
+
def _subject_locator(iid)
|
113
|
+
__getobj__.subject_locators.find_by_reference(iid, :include => :topic)
|
114
|
+
end
|
115
|
+
def _subject_locator!(iid)
|
116
|
+
__getobj__.subject_locators.find_or_create_by_reference(iid, :include => :topic)
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# internal helper for by_item_identifier, doesn't wrap result
|
121
|
+
def _by_item_identifier(iid)
|
122
|
+
ii = __getobj__.locators.find_by_reference(resolve(iid)) #, :include => [ :topic_map_construct ])
|
123
|
+
return ii.topic_map_construct if ii
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
def _topic_by_item_identifier(iid)
|
127
|
+
t = _by_item_identifier(iid)
|
128
|
+
return nil unless t
|
129
|
+
return t if t.class.name =~ /::Topic$/ # only return something if the thing is a topic
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
|
133
|
+
# internal helper for topic_by_item_identifier!, doesn't wrap result
|
134
|
+
def _topic_by_item_identifier!(iid)
|
135
|
+
ii = __getobj__.locators.find_or_create_by_reference(resolve(iid))#, :include => [ :topic_map_construct ])
|
136
|
+
return ii.topic_map_construct if ii.topic_map_construct && ii.topic_map_construct_type =~ /::Topic$/
|
137
|
+
top2 = _topic_by_subject_identifier(resolve(iid))
|
138
|
+
if top2
|
139
|
+
ii.topic_map_construct = top2
|
140
|
+
else
|
141
|
+
ii.topic_map_construct = create_topic.__getobj__
|
142
|
+
end
|
143
|
+
ii.save
|
144
|
+
ii.topic_map_construct
|
145
|
+
end
|
146
|
+
# internal helper for topic_by_subject_identifier, doesn't wrap result
|
147
|
+
def _topic_by_subject_identifier(sid)
|
148
|
+
si = __getobj__.subject_identifiers.find_by_reference(sid, :include => [ :topic ])
|
149
|
+
return si.topic if si
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
# internal helper for topic_by_subject_identifier!, doesn't wrap result
|
153
|
+
def _topic_by_subject_identifier!(sid)
|
154
|
+
si = __getobj__.subject_identifiers.find_or_create_by_reference(sid, :include => [ :topic ])
|
155
|
+
return si.topic if si.topic
|
156
|
+
begin
|
157
|
+
top2 = _by_item_identifier(sid)
|
158
|
+
rescue ActiveRecord::RecordNotFound => rnf
|
159
|
+
si.topic = create_topic.__getobj__
|
160
|
+
else
|
161
|
+
if top2 && top2.respond_to?(:subject_identifiers)
|
162
|
+
si.topic = top2
|
163
|
+
else
|
164
|
+
si.topic = create_topic.__getobj__
|
165
|
+
end
|
166
|
+
end
|
167
|
+
si.save
|
168
|
+
si.topic
|
169
|
+
end
|
170
|
+
|
171
|
+
# internal helper for topic_by_subject_locator, doesn't wrap result
|
172
|
+
def _topic_by_subject_locator(slo)
|
173
|
+
sl = __getobj__.subject_locators.find_by_reference(RTM::LocatorHelpers.slo2iri(slo)) #, :include => [ :topic ])
|
174
|
+
return sl.topic if sl
|
175
|
+
nil
|
176
|
+
end
|
177
|
+
|
178
|
+
# internal helper for topic_by_subject_locator!, doesn't wrap result
|
179
|
+
def _topic_by_subject_locator!(slo)
|
180
|
+
sl = __getobj__.subject_locators.find_or_create_by_reference(RTM::LocatorHelpers.slo2iri(slo), :include => [ :topic ])
|
181
|
+
return sl.topic if sl.topic
|
182
|
+
sl.topic = create_topic.__getobj__
|
183
|
+
sl.save
|
184
|
+
sl.topic
|
185
|
+
end
|
186
|
+
def _topic_by_locator(iri)
|
187
|
+
raise "Locator may not be nil" unless iri
|
188
|
+
if RTM::LocatorHelpers.is_a_slo?(iri)
|
189
|
+
_topic_by_subject_locator(iri)
|
190
|
+
elsif URI.parse(iri).absolute?
|
191
|
+
_topic_by_subject_identifier(iri)
|
192
|
+
else
|
193
|
+
_topic_by_item_identifier(iri)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def _topic_by_locator!(iri)
|
198
|
+
raise "Locator may not be nil" unless iri
|
199
|
+
if RTM::LocatorHelpers.is_a_slo?(iri)
|
200
|
+
_topic_by_subject_locator!(iri)
|
201
|
+
elsif URI.parse(iri).absolute?
|
202
|
+
_topic_by_subject_identifier!(iri)
|
203
|
+
else
|
204
|
+
_topic_by_item_identifier!(iri)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
public
|
209
|
+
# returns an item identifier from the topic_map if it exists
|
210
|
+
def item_identifier(iid)
|
211
|
+
ItemIdentifier.wrap(_item_identifier(iid))
|
212
|
+
end
|
213
|
+
# returns an item identififier from the topic_map or creates it if it doesn't exist
|
214
|
+
def item_identifier!(iid)
|
215
|
+
ItemIdentifier.wrap(_item_identifier!(iid))
|
216
|
+
end
|
217
|
+
alias :create_locator :item_identifier!
|
218
|
+
# Returns a topic map construct by it's item identifier or nil if not found.
|
219
|
+
# It's the equivalent to TMAPI's TopicMapObjectIndex.getTopicMapObjectBySourceLocator
|
220
|
+
def by_item_identifier(iid)
|
221
|
+
TopicMapConstruct.wrap(_by_item_identifier(iid))
|
222
|
+
end
|
223
|
+
# Returns a topic by it's item identifier. The topic will be created if not found.
|
224
|
+
def topic_by_item_identifier!(iid)
|
225
|
+
Topic.wrap(_topic_by_item_identifier!(iid))
|
226
|
+
end
|
227
|
+
# Returns a topic by it's subject identifier or nil if not found.
|
228
|
+
# It's the equivalent to TMAPI's TopicsIndex.getTopicBySubjectIdentifier.
|
229
|
+
def topic_by_subject_identifier(sid)
|
230
|
+
Topic.wrap(_topic_by_subject_identifier(sid))
|
231
|
+
end
|
232
|
+
# returns a topic by it's subject identifier. The topic will be created if not found.
|
233
|
+
def topic_by_subject_identifier!(sid)
|
234
|
+
Topic.wrap(_topic_by_subject_identifier!(sid))
|
235
|
+
end
|
236
|
+
# Returns a topic by it's subject locator or nil if not found.
|
237
|
+
# It's the equivalent to TMAPI's TopicsIndex.getTopicBySubjectLocator
|
238
|
+
def topic_by_subject_locator(slo)
|
239
|
+
Topic.wrap(_topic_by_subject_locator(slo))
|
240
|
+
end
|
241
|
+
# returns a topic by it's subject locator. The topic will be created if not found.
|
242
|
+
def topic_by_subject_locator!(slo)
|
243
|
+
Topic.wrap(_topic_by_subject_locator!(slo))
|
244
|
+
end
|
245
|
+
|
246
|
+
# Gets a topic from this topic map using its (relative) item identifier,
|
247
|
+
# its (absolute) subject identifier or its (absolute and by "=" prepended) subject locator)
|
248
|
+
#
|
249
|
+
# Returns nil if the Topic does not exist.
|
250
|
+
#
|
251
|
+
def topic_by_locator(iri)
|
252
|
+
return iri if iri.is_a? Topic
|
253
|
+
# @tblc ||= {}
|
254
|
+
# t = @tblc[iri]
|
255
|
+
# return t if t
|
256
|
+
t = Topic.wrap(_topic_by_locator(iri))
|
257
|
+
# @tblc[iri] = t if t
|
258
|
+
# t
|
259
|
+
end
|
260
|
+
alias :get :topic_by_locator
|
261
|
+
|
262
|
+
# Gets a topic from this topic map using its (relative) item identifier,
|
263
|
+
# its (absolute) subject identifier or its (absolute and by "=" prepended) subject locator)
|
264
|
+
#
|
265
|
+
# If there is no topic with this item identifier, subject identifier or subject locator, it is created.
|
266
|
+
#
|
267
|
+
def topic_by_locator!(iri)
|
268
|
+
return iri if iri.is_a? Topic
|
269
|
+
# @tblc ||= {}
|
270
|
+
# t = @tblc[iri]
|
271
|
+
# return t if t
|
272
|
+
t = Topic.wrap(_topic_by_locator!(iri))
|
273
|
+
# @tblc[iri] = t
|
274
|
+
# t
|
275
|
+
end
|
276
|
+
alias :get! :topic_by_locator!
|
277
|
+
|
278
|
+
# I am not sure if this is at all correct. TMDM doesn't say a word about it
|
279
|
+
# and the approach to compare topic maps is CXTM. I chose this because we
|
280
|
+
# should (at least at the time of writing) have only one topic with a given
|
281
|
+
# base locator in RTM. If you don't like it, drop me a mail and explain why
|
282
|
+
# and propose something better.
|
283
|
+
equality [:base_locator]
|
284
|
+
end
|
285
|
+
end
|