1 # $Id: abstraction.rb,v 1.3 2012/04/17 02:49:40 machan Exp $
2
3 require 'tmdoc/tmstd'
4 require 'tmdoc/tmstd/xml'
5
6
7 module TmStd
8
9 module DocBook
10
11 module Abstraction
12
13 class Element < TmStd::Lsm::Product::Abstract
14 attr_reader :attr_id, :attr_class
15
16 def initialize(common_attrs = {})
17 Assertion.kind_of common_attrs, Hash
18
19 @attr_id = @attr_class = nil
20 for key, val in common_attrs
21 Assertion.kind_of key, Symbol
22
23 case key
24 when :id
25 Assertion.kind_of val, String, "Key: #{key}"
26
27 @attr_id = val
28 when :class
29 Assertion.kind_of val, String
30
31 @attr_class = val
32 else
33 Assertion.abort "Unknown attribute key: '%s'", key
34 end
35 end
36 end
37
38
39 def to_xml(tag, specific_attrs = {}, opts = {}, &block)
40 Assertion.kind_of tag, Symbol
41 Assertion.kind_of specific_attrs, Hash
42 Assertion.kind_of opts, Hash
43
44 attrs = common_attributes.merge(specific_attrs)
45
46 Xml::Element.new(tag, attrs, opts) {
47 xml_contents = if block
48 block.call
49 else
50 contents_to_xml
51 end
52
53 Assertion.kind_of xml_contents, Array
54 }
55 end
56
57
58 private
59
60 def parse_attributes(attrs = {}, attr_defs = {})
61 Assertion.kind_of attrs, Hash
62 Assertion.kind_of attr_defs, Hash
63
64 result_attrs = attrs.inject({}) { |result, pair|
65 Assertion.tuple_of pair, [Symbol, Object]
66 key, val = pair
67
68 attr_def = attr_defs[key]
69 if attr_def
70 Assertion.tuple_of(
71 attr_def, [Class, Proc],
72 "Type declaration error on the attribute: '%s'", key
73 )
74
75 class_of_val, func = attr_def
76 Assertion.kind_of(val, class_of_val,
77 "Value type error on the attribute: '%s'", key
78 )
79
80 func.call val
81
82 result
83 else
84 result.merge key => val
85 end
86 }
87
88 Assertion.kind_of result_attrs, Hash
89 end
90
91
92 def common_attributes
93 common_attrs = attributes :id => @attr_id, :class => @attr_class
94
95 Assertion.kind_of common_attrs, Hash
96 end
97
98
99 def attributes(source_attrs = {})
100 Assertion.kind_of source_attrs, Hash
101
102 target_attrs = source_attrs.reject { |key, val|
103 Assertion.kind_of key, Symbol
104
105 val.nil?
106 }.inject({}) { |hash_of_attr, pair|
107 Assertion.tuple_of pair, [Symbol, String]
108 key, string = pair
109
110 hash_of_attr.merge key => string
111 }
112
113 Assertion.kind_of target_attrs, Hash
114 end
115
116
117 def contents_to_xml
118 []
119 end
120 end
121
122
123
124
125 class Content < Lsm::Sum::KindOf; end
126
127
128
129 class SeqOfContent < TmStd::Lsm::Collection::Sequence::Abstract
130 LSM_ELEMENT_CLASS = Abstraction::Content
131 end
132
133 EMPTY_SEQ_OF_CONTENT = SeqOfContent.new
134
135
136
137 class LeafElement < Element; end
138
139
140
141 class NodeElement < Element
142 include Enumerable
143
144 attr_reader :contents
145
146
147 def initialize(contents_class, content_class, attrs = {}, &block)
148 Assertion.subclass_of contents_class, SeqOfContent
149 Assertion.subclass_of content_class, Content
150 Assertion.kind_of attrs, Hash
151
152 super attrs
153
154 @contents =
155 if block
156 elements = block.call
157 Assertion.kind_of elements, Array
158
159 unless elements.empty?
160 contents_class.new(
161 elements.map { |elem|
162 Assertion.kind_of elem, Element
163
164 content_class.new(elem)
165 }
166 )
167 else
168 EMPTY_SEQ_OF_CONTENT
169 end
170 else
171 EMPTY_SEQ_OF_CONTENT
172 end
173 end
174
175
176 def each(&block)
177 self.contents.each(&block)
178
179 nil
180 end
181
182
183 private
184
185 def contents_to_xml
186 xml_contents = self.map { |content|
187 xml_content = content.lsm_member.to_xml
188 Assertion.kind_of xml_content, Xml::Abstraction::Unit
189
190 xml_content
191 }
192
193 Assertion.kind_of xml_contents, Array
194 end
195 end
196
197
198
199 class Division < NodeElement
200 DOC_TYPE =
201 '<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"' +
202 ' "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">'
203
204 def to_xml(tag, opts = {})
205 Assertion.kind_of tag, Symbol
206 Assertion.kind_of opts, Hash
207
208
209 is_document = false
210 for key, val in opts
211 Assertion.kind_of key, Symbol
212
213 case key
214 when :is_document
215 Assertion.boolean val
216
217 is_document = val
218 else
219 Assertion.abort "Unknown option: %s", key
220 end
221 end
222
223 xml_elem =
224 if is_document
225 Xml::Document.new(tag, DOC_TYPE, common_attributes) {
226 contents_to_xml
227 }
228 else
229 Xml::Element.new(tag, common_attributes) {
230 contents_to_xml
231 }
232 end
233
234 Assertion.kind_of xml_elem, Xml::Element
235 end
236 end
237
238
239
240 class Info < NodeElement; end
241
242
243
244 class List < NodeElement; end
245
246
247
248 class Row < NodeElement; end
249
250
251
252 class Entry < NodeElement; end
253
254
255
256 class Name < LeafElement
257 def initialize(name, common_attrs = {})
258 Assertion.kind_of name, String
259 Assertion.kind_of common_attrs, Hash
260
261 super common_attrs
262
263 @name = name
264 end
265
266
267 def to_xml(tag)
268 Assertion.kind_of tag, Symbol
269
270 super(tag) { [ Xml::Text.new(@name) ] }
271 end
272 end
273
274 end # TmStd::DocBook::Abstraction
275
276 end # TmStd::DocBook
277
278 end # TmStd