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.
@@ -0,0 +1,98 @@
1
+ module RTM::AR
2
+ class Topics < TMSetDelegator
3
+ def wrap(obj)
4
+ Topic.wrap(obj)
5
+ end
6
+ end
7
+ class TopicMapConstructs < TMSetDelegator
8
+ def wrap(obj)
9
+ TopicMapConstruct.wrap(obj)
10
+ end
11
+ end
12
+ class Associations < TMSetDelegator
13
+ def wrap(obj)
14
+ Association.wrap(obj)
15
+ end
16
+ end
17
+ class TopicNames < TMSetDelegator
18
+ def wrap(obj)
19
+ TopicName.wrap(obj)
20
+ end
21
+ end
22
+ class Occurrences < TMSetDelegator
23
+ def wrap(obj)
24
+ Occurrence.wrap(obj)
25
+ end
26
+ end
27
+ class AssociationRoles < TMSetDelegator
28
+ def wrap(obj)
29
+ AssociationRole.wrap(obj)
30
+ end
31
+ end
32
+ class Reifiables < TMSetDelegator
33
+ def wrap(obj)
34
+ TopicMapConstruct.wrap(obj)
35
+ end
36
+ end
37
+ class Variants < TMSetDelegator
38
+ def wrap(obj)
39
+ Variant.wrap(obj)
40
+ end
41
+ end
42
+ class TopicMaps < TMSetDelegator
43
+ def [](obj)
44
+ # support for getting topic_map by base_locator
45
+ if obj.is_a? String
46
+ # return wrap(__getobj__.find { |tm| tm.base_locator == obj })
47
+ return wrap(TMDM::TopicMap.find_by_base_locator(obj))
48
+ end
49
+ # normal index retrieval
50
+ super
51
+ end
52
+
53
+ def wrap(obj)
54
+ TopicMap.wrap(obj)
55
+ end
56
+ end
57
+ class Locators < TMSetDelegator
58
+ def [](obj)
59
+ # support for getting locators by reference
60
+ if obj.is_a? String
61
+ return wrap(__getobj__.find { |tm| tm.reference == obj })
62
+ end
63
+ # normal index retrieval
64
+ super
65
+ end
66
+ def wrap(obj)
67
+ return nil unless obj
68
+ return obj if obj.respond_to? :__getobj__
69
+ case obj.class.name
70
+ when "RTM::AR::TMDM::ItemIdentifier"
71
+ ItemIdentifier.wrap(obj)
72
+ when "RTM::AR::TMDM::SubjectIdentifier"
73
+ SubjectIdentifier.wrap(obj)
74
+ when "RTM::AR::TMDM::SubjectLocator"
75
+ SubjectLocator.wrap(obj)
76
+ else
77
+ Locator.wrap(obj)
78
+ end
79
+ end
80
+ end
81
+
82
+ class ItemIdentifiers < Locators
83
+ def wrap(obj)
84
+ ItemIdentifier.wrap(obj)
85
+ end
86
+ end
87
+ class SubjectIdentifiers < Locators
88
+ def wrap(obj)
89
+ SubjectIdentifier.wrap(obj)
90
+ end
91
+
92
+ end
93
+ class SubjectLocators < Locators
94
+ def wrap(obj)
95
+ SubjectLocator.wrap(obj)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,62 @@
1
+ module RTM::AR
2
+ class TopicMapConstruct < TMDelegator
3
+ include RTM::TopicMapConstruct
4
+
5
+ def self.abstract_class?
6
+ self == TopicMapConstruct
7
+ end
8
+ property_set :item_identifiers, :aka => [:ii, :iid, :source_locators], :type => :ItemIdentifier, :wrap => true,
9
+ #:create => :item_identifier, :create_aka => :cii
10
+ :add => true, :remove => true
11
+
12
+ delegate :remove, :to => :destroy
13
+
14
+ delegate :id
15
+ # property_parent :parent # mmh..
16
+
17
+ property :topic_map, :rw => true, :type => :TopicMap, :wrap => true
18
+
19
+ #class_delegate :create
20
+
21
+ def self.wrap(obj)
22
+ return nil unless obj
23
+ raise "Double wrapping" if obj.respond_to?(:__getobj__)
24
+ case obj.class.name
25
+ when "RTM::AR::TMDM::Topic"
26
+ Topic.wrap(obj)
27
+ when "RTM::AR::TMDM::Variant"
28
+ Variant.wrap(obj)
29
+ when "RTM::AR::TMDM::TopicName"
30
+ TopicName.wrap(obj)
31
+ when "RTM::AR::TMDM::Occurrence"
32
+ Occurrence.wrap(obj)
33
+ when "RTM::AR::TMDM::Association"
34
+ Association.wrap(obj)
35
+ when "RTM::AR::TMDM::AssociationRole"
36
+ AssociationRole.wrap(obj)
37
+ when "RTM::AR::TMDM::TopicMap"
38
+ TopicMap.wrap(obj)
39
+ else
40
+ raise "Can't wrap object. Class for wrapping #{obj.class} unknown (object: #{obj})"
41
+ end
42
+ end
43
+
44
+ def self.find(*args)
45
+ res = RTM::AR::TMDM.const_get(name.split("::").last).find(*args)
46
+ if res.respond_to? :each
47
+ TopicMapConstructs.wrap(res)
48
+ else
49
+ TopicMapConstruct.wrap(res)
50
+ end
51
+ end
52
+ end
53
+
54
+ class Reifiable < TopicMapConstruct
55
+ include RTM::Reifiable
56
+
57
+ def self.abstract_class?
58
+ self == Reifiable
59
+ end
60
+ property :reifier, :type => :Topic, :rw => :true, :wrap => true
61
+ end
62
+ end
@@ -0,0 +1,420 @@
1
+ module RTM::AR
2
+ class TMDelegator
3
+ def initialize(obj)
4
+ @obj = obj
5
+ end
6
+
7
+ def __getobj__
8
+ @obj
9
+ end
10
+
11
+ def __setobj__(obj)
12
+ @obj = obj
13
+ end
14
+
15
+ def self.delegate(sym, options={})
16
+ to = options[:to] || sym
17
+ module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
18
+ def #{sym}(*args, &block)
19
+ __getobj__.send(:#{to}, *args, &block)
20
+ end
21
+ EOS
22
+
23
+ if options[:rw]
24
+ module_eval(<<-EOS, "(__TMDELEGATOR2__)", 1)
25
+ def #{sym}=(*args, &block)
26
+ __getobj__.send(:#{to}=, *args, &block)
27
+ #{options[:save] ? "__getobj__.save" : "" }
28
+ end
29
+ EOS
30
+ end
31
+
32
+ if options[:aka]
33
+ options[:aka] = [options[:aka]] unless options[:aka].respond_to? :each
34
+ options[:aka].each do |aka|
35
+ module_eval(<<-EOS, "(__TMDELEGATOR3__)", 1)
36
+ alias :#{aka} :#{sym}
37
+ EOS
38
+
39
+ if options[:rw]
40
+ module_eval(<<-EOS, "(__TMDELEGATOR3__)", 1)
41
+ alias :#{aka}= :#{sym}=
42
+ EOS
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def self.class_delegate(sym, options={})
49
+ module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
50
+ class << self
51
+ def #{sym}(*args, &block)
52
+ __getobj__.send(:#{sym}, *args, &block)
53
+ end
54
+ end
55
+ EOS
56
+
57
+ if options[:aka]
58
+ options[:aka] = [options[:aka]] unless options[:aka].respond_to? :each
59
+ options[:aka].each do |aka|
60
+ module_eval(<<-EOS, "(__TMDELEGATOR2__)", 1)
61
+ class << self
62
+ alias :#{aka} :#{sym}
63
+ end
64
+ EOS
65
+ end
66
+ end
67
+ end
68
+
69
+ def self.parent(sym, options={})
70
+ module_eval(<<-EOS, "(__TMDELEGATOR__)", 1)
71
+ def #{sym}
72
+ TopicMapConstruct.wrap(__getobj__.send(:#{sym}))
73
+ end
74
+ EOS
75
+ aka_property(sym, [:parent, :p])
76
+ end
77
+
78
+ def self.property_set(prop, options={})
79
+ # puts "In #{self.name.to_s.ljust(20)} we have type #{options[:type].to_s.ljust(20)} for property #{prop}"
80
+ if options[:wrap]
81
+ #puts "#{self}: #{options[:type]}"
82
+ module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_W__)", 1)
83
+ def #{prop}(*args)
84
+ if args.size == 0
85
+ # fetch normal
86
+ #{options[:type]}s.wrap(__getobj__.#{prop}, self, :#{options[:type]})
87
+ else
88
+ # fetch with filter
89
+ #puts args.inspect
90
+ # TODO enhance/fix condition transform code
91
+ a = {}.merge(args.first)
92
+ if a[:type] && !a[:ttype]
93
+ a[:ttype] = a[:type]
94
+ a.delete(:type)
95
+ end
96
+ a.each do |k,v|
97
+ if v.respond_to?(:__getobj__)
98
+ a[(k.to_s + "_id").to_sym] = v.id
99
+ end
100
+ end
101
+ #{options[:type]}s.wrap(__getobj__.#{prop}.find(:all, :conditions=> a), self, :#{options[:type]})
102
+ end
103
+ end
104
+ EOS
105
+ else
106
+ module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_NW__)", 1)
107
+ def #{prop}
108
+ __getobj__.#{prop}
109
+ end
110
+ EOS
111
+ end
112
+
113
+ if options[:create]
114
+ # some :create_args:
115
+ #
116
+ # create_locator reference:string
117
+ # [ :name => :reference, :type => :String]
118
+ #
119
+ # create_topic_name value:String, scope:Collection
120
+ # create_topic_name value:String, type: Topic, scope:Collection
121
+ # [ {:name => :value, :type => :String}, {:name => :type, :type => :Topic, :optional => true}, {:name => :scope, :type => :Collection} ]
122
+ #
123
+ # create_occurrence value:String, type: Topic, scope:Collection
124
+ # create_occurrence resource: Locator, type: Topic, scope:Collection
125
+ # [ {:name => :value, :type => [:String, :Locator]}, {:name => :type, :type => :Topic}, {:name => :scope, :type => :Collection} ]
126
+ #
127
+ # create_association_role player:topic, type: topic
128
+ # [ {:name => :player, :type => :Topic}, {:name => :type, :type => :Topic}]
129
+ #
130
+ # create_variant value:string, :scope:Collection
131
+ # create_variant resource:locator, :scope:Collection
132
+ # [ {:name => :value, :type => [:String, :Locator]}, {:name => :scope, :type => :Collection}]
133
+
134
+ module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY_SET_CREATE__)", 1)
135
+ def create_#{ options[:create]}(*args, &block)
136
+ arg_defs = #{ (options[:create_args] || nil ).inspect}
137
+
138
+ a = parse_args(args, arg_defs)
139
+
140
+ a = enhance_args_hash(a, arg_defs) if arg_defs
141
+
142
+ a = a.reject{|k,v| v.nil?}
143
+
144
+ # hack to change :type to :ttype for AR backend
145
+ # puts a.inspect unless a.is_a? Hash
146
+ if a[:type] && !a[:ttype]
147
+ a[:ttype] = a[:type]
148
+ a.delete(:type)
149
+ end
150
+ if [:Locator,:ItemIdentifier, :SubjectIdentifier, :SubjectLocator].include?(:#{options[:type]})
151
+ unless a[:topic_map]
152
+ a[:topic_map] = topic_map.__getobj__
153
+ end
154
+ end
155
+
156
+ if block_given?
157
+ obj = #{options[:type]}.wrap( __getobj__.#{options[:create]}s.new(a) )
158
+ yield obj
159
+ obj.save
160
+ else
161
+ obj = #{options[:type]}.wrap( __getobj__.#{options[:create]}s.create(a) )
162
+ end
163
+ obj
164
+ end
165
+ EOS
166
+
167
+ if options[:create_aka]
168
+ aka_property("create_#{options[:create]}", options[:create_aka])
169
+ end
170
+ end
171
+
172
+ if options[:add]
173
+ module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_ADD__)", 1)
174
+ def add_#{prop.to_s.singularize}(*args, &block)
175
+ #{prop}.add(*args, &block)
176
+ end
177
+ RUBY
178
+ aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "add_#{a}"})
179
+ aka_property("add_#{prop.to_s.singularize}", options[:aka].map{|a| "a#{a}"})
180
+ end
181
+
182
+ if options[:remove]
183
+ module_eval(<<-RUBY, "(__AR_DELEGATOR_PROPERTY_SET_REMOVE__)", 1)
184
+ def remove_#{prop.to_s.singularize}(*args, &block)
185
+ #{prop}.remove(*args, &block)
186
+ end
187
+ RUBY
188
+ aka_property("remove_#{prop.to_s.singularize}", options[:aka].map{|a| "remove_#{a}"})
189
+ aka_property("remove_#{prop.to_s.singularize}", options[:aka].map{|a| "r#{a}"})
190
+ end
191
+
192
+ # TODO: aliases for property_set.add as add_property
193
+
194
+ aka_property(prop, options[:aka]) if options[:aka]
195
+ end
196
+
197
+ private
198
+ def parse_args(args, arg_defs)
199
+ a = {}
200
+ a = args.pop if args.last.is_a? Hash
201
+ # We are finished if there are no more parameters or we have no arg_def.
202
+ # Special case: non optional parameters must have been in the Hash, just a hash is also allowed.
203
+ return a if args.size == 0 || arg_defs == nil
204
+
205
+ # we have some args
206
+ if args.size == arg_defs.size # all are given
207
+ return args2hash(a, args,arg_defs)
208
+ elsif args.size == arg_defs.reject { |d| d[:optional]}
209
+ return args2hash(a, args, arg_defs.reject {|d| d[:optional]})
210
+ end
211
+ #warn("Functions with more than one optional parameter are not supported. This will only work if the left out ones are the last.")
212
+ return args2hash(a, args,arg_defs)
213
+ end
214
+
215
+ def args2hash(a, args, arg_defs)
216
+ arg_defs.zip(args) do |argd,arg|
217
+ a[argd[:name]] = arg
218
+ end
219
+
220
+ return a
221
+ end
222
+
223
+ def enhance_args_hash(a, arg_defs)
224
+ #puts "enhance_args: #{a.inspect} ---\n#{arg_defs.inspect}"
225
+ return a if a.empty?
226
+ arg_defs.each do |argd|
227
+ #puts "enhancing #{argd[:name]}, which is a #{a[argd[:name]].class}"
228
+ if argd[:type] == :Topic
229
+ if a[argd[:name]].is_a? String
230
+ a[argd[:name]] = topic_map._topic_by_locator!(a[argd[:name]])
231
+ elsif a[argd[:name]].is_a?(RTM::Topic)
232
+ a[argd[:name]] = a[argd[:name]].__getobj__
233
+ end
234
+ end
235
+ if argd[:type] == :Locator || (argd[:type].respond_to?(:include?) && argd[:type].include?(:Locator))
236
+ a[argd[:name]] = a[argd[:name]].to_s
237
+ end
238
+ end
239
+ a
240
+ end
241
+
242
+ public
243
+ def self.property(prop, options={})
244
+ module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY__)", 1)
245
+ def #{prop}
246
+ #{options[:wrap]? "#{options[:type]}.wrap":""}( __getobj__.#{prop})
247
+ end
248
+ EOS
249
+
250
+ if options[:rw]
251
+ case options[:type]
252
+ when :Topic
253
+ module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
254
+ def #{prop}=(obj)
255
+ obj = topic_map.topic_by_locator!(obj) unless obj.is_a? #{options[:type]}
256
+ __getobj__.#{prop} = obj.__getobj__
257
+ __getobj__.save
258
+ end
259
+ EOS
260
+ when :TopicMap
261
+ module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
262
+ def #{prop}=(obj)
263
+ obj = RTM.create obj.to_s unless obj.is_a? #{options[:type]}
264
+ __getobj__.#{prop} = obj.__getobj__
265
+ __getobj__.save
266
+ end
267
+ EOS
268
+ when :String, :Locator
269
+ module_eval(<<-EOS, "(__AR_DELEGATOR_PROPERTY2__)", 1)
270
+ def #{prop}=(obj)
271
+ __getobj__.#{prop} = obj.to_s
272
+ __getobj__.save
273
+ end
274
+ EOS
275
+ else
276
+ raise "Don't know how to do wrapping for #{options[:type]}"
277
+ end
278
+
279
+ end
280
+
281
+ aka_property(prop, options[:aka]) if options[:aka]
282
+ end
283
+
284
+ def self.aka_property(prop, aka)
285
+ aka = [aka].flatten
286
+ aka.each do |a|
287
+ #puts "generating alias #{a} for #{prop}"
288
+ module_eval(<<-EOS, "(__AR_DELEGATOR_AKA_PROPERTY__)", 1)
289
+ alias :#{a} :#{prop}
290
+ EOS
291
+ end
292
+ end
293
+
294
+ def self.index_property_set(prop, options={})
295
+ r = options[:rule]
296
+ module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET__)", 1)
297
+ def direct_#{prop}_roles
298
+ # prefetch typing topics
299
+ rtype = @ips_#{prop}_rtype ||= self.topic_map.get("#{r[:role_type]}")
300
+ atype = @ips_#{prop}_atype ||= self.topic_map.get("#{r[:association_type]}")
301
+ otype = @ips_#{prop}_otype ||= self.topic_map.get("#{r[:other_role_type]}")
302
+ # return nothing if any of the typing topics does not exist
303
+ return [] unless rtype && atype && otype
304
+ # we do that only here and not earlier because some might me nil
305
+ rtype = rtype.id
306
+ atype = atype.id
307
+ otype = otype.id
308
+ self.__getobj__.roles.map{|r|
309
+ r.ttype_id != nil &&
310
+ r.ttype_id == rtype &&
311
+ r.parent.roles.size == #{r[:association_arity]} &&
312
+ r.parent != nil &&
313
+ r.parent.ttype_id == atype &&
314
+ (r2 = r.parent.roles.select{|r2| r2.ttype_id != nil &&
315
+ r2.ttype_id == otype}.first) &&
316
+ r2}.select{|r2| r2}.map{|r2| AssociationRole.wrap(r2)}
317
+ end
318
+ def direct_#{prop}
319
+ direct_#{prop}_roles.map{|r2| r2.player}.uniq
320
+ end
321
+ EOS
322
+
323
+ if r[:transitive]
324
+ module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET2__)", 1)
325
+ def #{prop}
326
+ d = todo = self.direct_#{prop}
327
+ while todo.size > 0
328
+ todo = todo.map{|dt| dt.direct_#{prop}}.flatten.uniq - d
329
+ d += todo
330
+ end
331
+ d
332
+ #d2 = self.direct_#{prop}.map {|dt| dt.#{prop}}.flatten
333
+ #(d+d2).uniq
334
+ end
335
+ EOS
336
+ else
337
+ if r[:infer]
338
+ module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET3__)", 1)
339
+ def #{prop}
340
+ (self.direct_#{prop} + self.#{r[:infer]}.map{|d2| d2.direct_#{prop}}).flatten.uniq
341
+ end
342
+ EOS
343
+ elsif r[:infer_other]
344
+ module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET4__)", 1)
345
+ def #{prop}
346
+ d = self.direct_#{prop}
347
+ (d + d.map{|d2| d2.#{r[:infer_other]}}).flatten.uniq
348
+ end
349
+ EOS
350
+ end
351
+ end
352
+ if r[:add]
353
+ module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET5__)", 1)
354
+ def add_#{r[:add]}(t)
355
+ a = self.topic_map.create_association("#{r[:association_type]}")
356
+ a.create_role self, "#{r[:role_type]}"
357
+ a.create_role t, "#{r[:other_role_type]}"
358
+ a
359
+ # TODO add_x in index_property_set needs to trigger reload of the topics somewhere
360
+ end
361
+ def remove_#{r[:add]}(t)
362
+ direct_#{prop}_roles.select{|r| r.player == t}.each{|r| r.parent.remove}
363
+ # TODO remove_x in index_property_set needs to trigger reload of the topics somewhere
364
+ end
365
+ EOS
366
+ end
367
+ end
368
+
369
+ def self.equality(eqfields, options={})
370
+ field_condition = eqfields.map {|f| "self.#{f} == o.#{f}" }.join(" && ")
371
+ module_eval(<<-EOS, "(__AR_EQUALITY__)", 1)
372
+ def ==(o)
373
+ return false unless o
374
+ return true if #{field_condition}
375
+ false
376
+ end
377
+ EOS
378
+ end
379
+ def eql?(o)
380
+ return false unless o
381
+ return true if self.class == o.class && self.id == o.id
382
+ false
383
+ end
384
+ def hash
385
+ return self.id.hash
386
+ end
387
+
388
+ def self.wrapper_cache
389
+ module_eval(<<-EOS, "(__AR_WRAPPER_CACHE__)", 1)
390
+ def self.wrap(obj)
391
+ return nil unless obj
392
+ raise "Double wrapping" if obj.respond_to?(:__getobj__)
393
+ t = self.wrapped(obj)
394
+ if t
395
+ t.__setobj__(obj)
396
+ return t
397
+ end
398
+ self.new(obj)
399
+ end
400
+
401
+ def self.wrapped(unwrapped_obj)
402
+ @@wrapped ||= {}
403
+ return @@wrapped[unwrapped_obj.id] if unwrapped_obj.respond_to? :id
404
+ @@wrapped[unwrapped_obj]
405
+ end
406
+ def self.reset_wrapped
407
+ @@wrapped = {}
408
+ end
409
+ def initialize(*args)
410
+ super
411
+ @@wrapped ||= {}
412
+ @@wrapped[self.id]=self
413
+ end
414
+ EOS
415
+ end
416
+
417
+ alias :i :id
418
+ delegate :reload
419
+ end
420
+ end