rtm 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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