1 # $Id: abstraction.rb,v 1.13 2011/12/13 23:54:06 machan Exp $
2
3 require 'tmdoc/tmstd'
4 require 'tmdoc/constant'
5
6
7 module TmDoc
8
9 module Model::Abstraction
10
11 class Store < TmStd::Lsm::Product::Abstract; end
12
13
14
15 module Path
16
17 class Abstract < TmStd::Lsm::Collection::Sequence::Abstract
18 include TmStd::Lsm::Collection::Sequence::Equalable
19 include TmStd::Lsm::Collection::Sequence::Comparable
20
21
22 def initialize(elements = [])
23 ASSERT.kind_of __path_separator_string__, String
24
25 super
26 end
27
28
29 def join(sep = __path_separator_string__)
30 ASSERT.kind_of sep, String
31
32 str = super(sep)
33
34 ASSERT.kind_of str, String
35 end
36
37
38 def to_s(sep = __path_separator_string__)
39 ASSERT.kind_of sep, String
40
41 str = self.join(sep)
42
43 ASSERT.kind_of str, String
44 end
45
46
47 private
48
49 def __path_separator_string__
50 begin
51 sep = self.class.const_get('PATH_SEPARATOR_STRING')
52 rescue NameError
53 raise SubclassResponsibility
54 end
55
56 ASSERT.kind_of sep, String
57 end
58 end
59
60
61
62 class Absolute < Abstract
63 def Absolute.new_root
64 self.new([])
65 end
66
67
68 def +(other)
69 ASSERT.kind_of other, Relative
70
71 path = super
72
73 ASSERT.kind_of path, Absolute
74 end
75
76
77 def to_s(sep = __path_separator_string__)
78 ASSERT.kind_of sep, String
79
80 str = sep + super
81
82 ASSERT.kind_of str, String
83 end
84 end
85
86
87
88 class SetOfPath < TmStd::Lsm::Collection::Set::Abstract
89 LSM_ELEMENT_CLASS = Absolute
90 end
91
92
93
94 class Relative < Abstract
95 def to_absolute
96 klass = __absolute_path_class__
97
98 ASSERT.subclass_of klass, Absolute
99
100 klass.new(self.to_a)
101 end
102
103
104 def +(other)
105 ASSERT.kind_of other, Relative
106
107 super
108 end
109
110
111 private
112
113 def __absolute_path_class__
114 begin
115 klass = self.class.const_get('ABSOLUTE_PATH_CLASS')
116 rescue NameError
117 raise Exception::SubclassResponsibility
118 end
119
120 ASSERT.subclass_of klass, Abstract
121 end
122 end
123
124 end # TmDoc::Model::Abstraction::Path
125
126
127
128 module Subject
129
130 class GenericSubject < TmStd::Lsm::Product::Abstract
131 include Comparable
132
133
134 def ==(other)
135 result = self.eql? other
136
137 ASSERT.boolean result
138 end
139
140
141 def eql?(other)
142 raise Exception::SubclassResponsibility
143 end
144
145
146 def hash
147 raise Exception::SubclassResponsibility
148 end
149
150
151 def freeze_equality!
152 raise Exception::SubclassResponsibility
153 end
154
155
156 def <=>(other)
157 raise Exception::SubclassResponsibility
158 end
159 end
160
161
162
163 class SeqOfGenericSubject < TmStd::Lsm::Collection::Sequence::Abstract
164 LSM_ELEMENT_CLASS = GenericSubject
165 end
166
167
168
169 class SetOfGenericSubject < TmStd::Lsm::Collection::Set::Abstract
170 LSM_ELEMENT_CLASS = GenericSubject
171 end
172
173
174
175 class PhysicalSubject < GenericSubject
176 attr_reader :name, :seq_num
177 attr_reader :hash
178
179
180 def initialize(name, seq_num)
181 ASSERT.kind_of name, String
182 ASSERT.kind_of seq_num, Integer
183
184 @name = name
185 @seq_num = seq_num
186
187 @name.freeze
188 @seq_num.freeze
189
190 @hash = format("%s %d", @name, @seq_num).hash
191 end
192
193
194 def eql?(other)
195 result = self.name == other.name && self.seq_num == other.seq_num
196
197 ASSERT.boolean result
198 end
199
200
201 def freeze_equality!
202 nil # Nop, already frozen.
203 end
204
205
206 def <=>(other)
207 result_of_seq_num = self.seq_num <=> other.seq_num
208
209 result = if result_of_seq_num == 0
210 self.name <=> other.name
211 else
212 result_of_seq_num
213 end
214
215 ASSERT.kind_of result, Integer
216 end
217
218
219 def to_s(label)
220 ASSERT.kind_of label, String
221
222 str = format "%s[#%d]: %s", label, self.seq_num, self.name
223
224 ASSERT.kind_of str, String
225 end
226
227
228 def print(indent)
229 ASSERT.kind_of indent, Integer
230
231 is = "\t" * indent
232
233 LOG::Debug.log(
234 "%s---- %s[#%d]: %s ----",
235 is, self.class.to_s, self.seq_num, self.name
236 )
237
238 nil
239 end
240 end
241
242
243
244 class SetOfPhysicalSubject < SetOfGenericSubject
245 LSM_ELEMENT_CLASS = PhysicalSubject
246 end
247
248
249
250 class LogicalSubject < GenericSubject
251 attr_reader :location,
252 :above_path,
253 :name,
254 :seq_num
255 attr_reader :hash
256
257
258 def initialize(
259 location = nil, above_path = nil, name = nil, seq_num = nil
260 )
261 ASSERT.opt_kind_of location, Model::Abstraction::Location
262 ASSERT.opt_kind_of above_path, Model::Abstraction::Path::Absolute
263 ASSERT.opt_kind_of name, String
264 ASSERT.opt_kind_of seq_num, Integer
265
266 super()
267
268 @above_path = above_path
269 @name = name
270 @location = location
271 @seq_num = if seq_num then seq_num else 0 end
272
273 @above_path.freeze_equality! if @above_path
274 @name.freeze if @name
275 @location.freeze_equality! if @location
276 @seq_num.freeze if @seq_num
277
278 @hash = format(
279 "%s %s %s %s",
280 if @above_path then @above_path else '-' end,
281 if @name then @name else '-' end,
282 if @location then @location.to_s else '-' end,
283 if @seq_num then @seq_num.to_s else '-' end
284 ).hash
285 end
286
287
288 def to_s(label, opt_str = nil)
289 ASSERT.kind_of label, String
290 ASSERT.opt_kind_of opt_str, String
291
292 str = format("%s %s%s%s",
293 label,
294
295 self.above_path.to_s,
296
297 if opt_str then ' ' + opt_str else '' end,
298
299 if self.location
300 ' -- ' + self.location.to_s
301 else
302 ''
303 end
304 )
305
306 ASSERT.kind_of str, String
307 end
308
309
310 def print(indent)
311 ASSERT.kind_of indent, Integer
312
313 is = "\t" * indent
314
315 LOG::Debug.log(
316 "%s---- %s%s%s ----",
317
318 is,
319
320 if self.name then self.name else '' end,
321
322 if self.seq_num && self.seq_num != 0
323 format " [#%d]", self.seq_num
324 else
325 ''
326 end,
327
328 format(": %s", self.class.to_s)
329 )
330
331 if self.location
332 LOG::Debug.log "%slocation: %s", is, self.location.to_s
333 end
334
335 if self.above_path
336 LOG::Debug.log "%sabove_path: %s", is, self.above_path.to_s
337 end
338
339 nil
340 end
341
342
343 def path
344 unless self.name
345 raise Exception::SubclassResponsibility
346 end
347
348 path = self.above_path << self.name
349
350 ASSERT.kind_of path, Model::Abstraction::Path::Absolute
351 end
352
353
354 def eql?(other)
355 result =
356 if LogicalSubject >= other.class then true else false end &&
357 self.above_path == other.above_path &&
358 self.name == other.name &&
359 self.location == other.location &&
360 self.seq_num == other.seq_num
361
362 ASSERT.boolean result
363 end
364
365
366 def freeze_equality!
367 nil # Nop, already frozen
368 end
369
370
371 def <=>(other)
372 ASSERT.kind_of other, LogicalSubject
373
374 location_result =
375 LogicalSubject.__compare__ self.location, other.location
376 if location_result != 0
377 return location_result
378 end
379
380 seq_num_result =
381 LogicalSubject.__compare__ self.seq_num, other.seq_num
382 if seq_num_result != 0
383 return seq_num_result
384 end
385
386 above_path_result =
387 LogicalSubject.__compare__ self.above_path, other.above_path
388 if above_path_result != 0
389 return above_path_result
390 end
391
392 name_result = LogicalSubject.__compare__ self.name, other.name
393
394 ASSERT.kind_of name_result, Integer
395 end
396
397
398 def compare_by_name(other)
399 ASSERT.kind_of other, LogicalSubject
400
401 name_result = LogicalSubject.__compare__ self.name, other.name
402 if name_result != 0
403 return name_result
404 end
405
406 above_path_result = LogicalSubject.__compare__(
407 self.above_path, other.above_path
408 )
409 if above_path_result != 0
410 return above_path_result
411 end
412
413 location_result =
414 LogicalSubject.__compare__ self.location, other.location
415 if location_result != 0
416 return location_result
417 end
418
419 seq_num_result =
420 LogicalSubject.__compare__ self.seq_num, other.seq_num
421
422 ASSERT.kind_of seq_num_result, Integer
423 end
424
425
426 def self.__compare__(self_obj, other_obj)
427 result = if self_obj
428 if other_obj
429 self_obj <=> other_obj
430 else
431 1
432 end
433 else
434 if other_obj
435 -1
436 else
437 0
438 end
439 end
440
441 ASSERT.kind_of result, Integer
442 end
443 end
444
445
446
447 class SetOfLogicalSubject < SetOfGenericSubject
448 LSM_ELEMENT_CLASS = LogicalSubject
449 end
450
451
452
453 class SeqOfLogicalSubject < SeqOfGenericSubject
454 LSM_ELEMENT_CLASS = LogicalSubject
455 end
456
457 end # TmDoc::Model::Abstraction::Subject
458
459
460
461 class Location < TmStd::Lsm::Product::Abstract
462 include Comparable
463
464 attr_reader :a_file, :line_num
465 attr_reader :hash
466
467
468 def initialize(a_file, line_num)
469 ASSERT.kind_of a_file, Subject::PhysicalSubject
470 ASSERT.kind_of line_num, Integer
471
472 @a_file = a_file
473 @line_num = line_num
474
475 @a_file.freeze_equality!
476 @line_num.freeze
477
478 @hash = format("#%s#%d", self.a_file.to_s, self.line_num).hash
479 end
480
481
482 def to_s
483 str = format "#%d in '%s'", self.line_num, self.a_file.to_s
484
485 ASSERT.kind_of str, String
486 end
487
488
489 def file_name
490 str = self.a_file.name
491
492 ASSERT.kind_of str, String
493 end
494
495
496 def eql?(other)
497 result = if Location >= other.class then true else false end &&
498 self.a_file == other.a_file &&
499 self.line_num == other.line_num
500
501 ASSERT.boolean result
502 end
503
504
505 def freeze_equality!
506 nil # Nop, already frozen.
507 end
508
509
510 def <=>(other)
511 ASSERT.kind_of other, Location
512
513 result_file = self.a_file <=> other.a_file
514
515 result = if result_file == 0
516 self.line_num <=> other.line_num
517 else
518 result_file
519 end
520
521 ASSERT.kind_of result, Integer
522 end
523 end
524
525
526
527 class SetOfLocation < TmStd::Lsm::Collection::Set::Abstract
528 LSM_ELEMENT_CLASS = Location
529 end
530
531
532
533 class GenericDocument < TmStd::Lsm::Product::Abstract; end
534
535
536
537 class SeqOfGenericDocument < TmStd::Lsm::Collection::Sequence::Abstract
538 LSM_ELEMENT_CLASS = GenericDocument
539 end
540
541 end # TmDoc::Model::Abstraction
542
543 end # TmDoc