rtm 0.1.0 → 0.1.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/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
|