kwartz 3.0.0

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.
Files changed (169) hide show
  1. data/COPYING +340 -0
  2. data/ChangeLog +103 -0
  3. data/README.txt +37 -0
  4. data/bin/kwartz +12 -0
  5. data/doc-api/classes/Kwartz.html +218 -0
  6. data/doc-api/classes/Kwartz/Assertion.html +140 -0
  7. data/doc-api/classes/Kwartz/AssertionError.html +148 -0
  8. data/doc-api/classes/Kwartz/AttrInfo.html +320 -0
  9. data/doc-api/classes/Kwartz/BaseError.html +206 -0
  10. data/doc-api/classes/Kwartz/BaseTranslator.html +331 -0
  11. data/doc-api/classes/Kwartz/CharacterType.html +212 -0
  12. data/doc-api/classes/Kwartz/CommandOptionError.html +154 -0
  13. data/doc-api/classes/Kwartz/CommandOptions.html +374 -0
  14. data/doc-api/classes/Kwartz/Config.html +150 -0
  15. data/doc-api/classes/Kwartz/ConvertError.html +191 -0
  16. data/doc-api/classes/Kwartz/Converter.html +252 -0
  17. data/doc-api/classes/Kwartz/CssStyleParser.html +483 -0
  18. data/doc-api/classes/Kwartz/DocumentRuleset.html +369 -0
  19. data/doc-api/classes/Kwartz/ElementExpander.html +325 -0
  20. data/doc-api/classes/Kwartz/ElementInfo.html +312 -0
  21. data/doc-api/classes/Kwartz/ElementRuleset.html +582 -0
  22. data/doc-api/classes/Kwartz/EperlHandler.html +338 -0
  23. data/doc-api/classes/Kwartz/EperlTranslator.html +167 -0
  24. data/doc-api/classes/Kwartz/ErubisHandler.html +113 -0
  25. data/doc-api/classes/Kwartz/ErubisTranslator.html +168 -0
  26. data/doc-api/classes/Kwartz/ErubyHandler.html +337 -0
  27. data/doc-api/classes/Kwartz/ErubyTranslator.html +167 -0
  28. data/doc-api/classes/Kwartz/ExpandStatement.html +227 -0
  29. data/doc-api/classes/Kwartz/Expression.html +119 -0
  30. data/doc-api/classes/Kwartz/Handler.html +558 -0
  31. data/doc-api/classes/Kwartz/JstlHandler.html +657 -0
  32. data/doc-api/classes/Kwartz/JstlTranslator.html +226 -0
  33. data/doc-api/classes/Kwartz/KwartzError.html +146 -0
  34. data/doc-api/classes/Kwartz/Main.html +384 -0
  35. data/doc-api/classes/Kwartz/NativeExpression.html +236 -0
  36. data/doc-api/classes/Kwartz/NativeStatement.html +254 -0
  37. data/doc-api/classes/Kwartz/Node.html +156 -0
  38. data/doc-api/classes/Kwartz/ParseError.html +148 -0
  39. data/doc-api/classes/Kwartz/PhpHandler.html +333 -0
  40. data/doc-api/classes/Kwartz/PhpTranslator.html +194 -0
  41. data/doc-api/classes/Kwartz/PresentationLogicParser.html +830 -0
  42. data/doc-api/classes/Kwartz/PrintStatement.html +221 -0
  43. data/doc-api/classes/Kwartz/RailsHandler.html +587 -0
  44. data/doc-api/classes/Kwartz/RailsTranslator.html +167 -0
  45. data/doc-api/classes/Kwartz/RubyStyleParser.html +558 -0
  46. data/doc-api/classes/Kwartz/Ruleset.html +117 -0
  47. data/doc-api/classes/Kwartz/Statement.html +119 -0
  48. data/doc-api/classes/Kwartz/StrutsTranslator.html +190 -0
  49. data/doc-api/classes/Kwartz/TagInfo.html +314 -0
  50. data/doc-api/classes/Kwartz/TextConverter.html +270 -0
  51. data/doc-api/classes/Kwartz/Translator.html +318 -0
  52. data/doc-api/classes/Test.html +107 -0
  53. data/doc-api/classes/Test/Unit.html +101 -0
  54. data/doc-api/created.rid +1 -0
  55. data/doc-api/files/__/README_txt.html +150 -0
  56. data/doc-api/files/kwartz/assert_rb.html +114 -0
  57. data/doc-api/files/kwartz/binding/eperl_rb.html +116 -0
  58. data/doc-api/files/kwartz/binding/erubis_rb.html +116 -0
  59. data/doc-api/files/kwartz/binding/eruby_rb.html +115 -0
  60. data/doc-api/files/kwartz/binding/jstl_rb.html +116 -0
  61. data/doc-api/files/kwartz/binding/php_rb.html +116 -0
  62. data/doc-api/files/kwartz/binding/rails_rb.html +115 -0
  63. data/doc-api/files/kwartz/binding/struts_rb.html +117 -0
  64. data/doc-api/files/kwartz/config_rb.html +107 -0
  65. data/doc-api/files/kwartz/converter_rb.html +119 -0
  66. data/doc-api/files/kwartz/error_rb.html +107 -0
  67. data/doc-api/files/kwartz/main_rb.html +124 -0
  68. data/doc-api/files/kwartz/node_rb.html +114 -0
  69. data/doc-api/files/kwartz/parser_rb.html +117 -0
  70. data/doc-api/files/kwartz/translator_rb.html +115 -0
  71. data/doc-api/files/kwartz/util/assert-text-equal_rb.html +115 -0
  72. data/doc-api/files/kwartz/util/testcase-helper_rb.html +115 -0
  73. data/doc-api/files/kwartz_rb.html +120 -0
  74. data/doc-api/fr_class_index.html +75 -0
  75. data/doc-api/fr_file_index.html +45 -0
  76. data/doc-api/fr_method_index.html +216 -0
  77. data/doc-api/index.html +24 -0
  78. data/doc-api/rdoc-style.css +208 -0
  79. data/doc/docstyle.css +188 -0
  80. data/doc/p-pattern.html +1207 -0
  81. data/doc/reference.html +3396 -0
  82. data/doc/users-guide.html +1670 -0
  83. data/examples/breadcrumbs1/Makefile +15 -0
  84. data/examples/breadcrumbs1/breadcrumbs.eruby.plogic +27 -0
  85. data/examples/breadcrumbs1/breadcrumbs.html +12 -0
  86. data/examples/breadcrumbs1/breadcrumbs.jstl.plogic +28 -0
  87. data/examples/breadcrumbs1/breadcrumbs.php.plogic +26 -0
  88. data/examples/breadcrumbs1/main.php +12 -0
  89. data/examples/breadcrumbs1/main.rb +12 -0
  90. data/examples/breadcrumbs2/Makefile +15 -0
  91. data/examples/breadcrumbs2/breadcrumbs.eruby.plogic +22 -0
  92. data/examples/breadcrumbs2/breadcrumbs.html +14 -0
  93. data/examples/breadcrumbs2/breadcrumbs.jstl.plogic +24 -0
  94. data/examples/breadcrumbs2/breadcrumbs.php.plogic +23 -0
  95. data/examples/breadcrumbs2/main.php +12 -0
  96. data/examples/breadcrumbs2/main.rb +12 -0
  97. data/examples/pagelayout/Makefile +47 -0
  98. data/examples/pagelayout/content.eruby.plogic +44 -0
  99. data/examples/pagelayout/content.jstl.plogic +36 -0
  100. data/examples/pagelayout/content.php.plogic +37 -0
  101. data/examples/pagelayout/content1.html +36 -0
  102. data/examples/pagelayout/content2.html +29 -0
  103. data/examples/pagelayout/design.css +40 -0
  104. data/examples/pagelayout/layout.html +50 -0
  105. data/examples/pagelayout/main.php +55 -0
  106. data/examples/pagelayout/main.rb +77 -0
  107. data/examples/pagelayout/menu.eruby.plogic +14 -0
  108. data/examples/pagelayout/menu.html +13 -0
  109. data/examples/pagelayout/menu.jstl.plogic +14 -0
  110. data/examples/pagelayout/menu.php.plogic +14 -0
  111. data/examples/rails1/Makefile +36 -0
  112. data/examples/rails1/README +19 -0
  113. data/examples/rails1/application_helper.rb +31 -0
  114. data/examples/rails1/edit.html +28 -0
  115. data/examples/rails1/edit.plogic +10 -0
  116. data/examples/rails1/form.html +52 -0
  117. data/examples/rails1/form.plogic +33 -0
  118. data/examples/rails1/layout.plogic +15 -0
  119. data/examples/rails1/link_to.plogic +19 -0
  120. data/examples/rails1/list.html +48 -0
  121. data/examples/rails1/list.plogic +28 -0
  122. data/examples/rails1/new.html +27 -0
  123. data/examples/rails1/new.plogic +10 -0
  124. data/examples/rails1/reader.plogic +29 -0
  125. data/examples/rails1/show.html +40 -0
  126. data/examples/rails1/show.plogic +4 -0
  127. data/examples/rails1/writer.plogic +8 -0
  128. data/examples/table1/Makefile +15 -0
  129. data/examples/table1/main.php +11 -0
  130. data/examples/table1/main.rb +11 -0
  131. data/examples/table1/table1.eruby.plogic +21 -0
  132. data/examples/table1/table1.html +16 -0
  133. data/examples/table1/table1.jstl.plogic +21 -0
  134. data/examples/table1/table1.php.plogic +22 -0
  135. data/kwartz.gemspec +55 -0
  136. data/lib/kwartz.rb +13 -0
  137. data/lib/kwartz/assert.rb +31 -0
  138. data/lib/kwartz/binding/eperl.rb +166 -0
  139. data/lib/kwartz/binding/erubis.rb +61 -0
  140. data/lib/kwartz/binding/eruby.rb +164 -0
  141. data/lib/kwartz/binding/jstl.rb +334 -0
  142. data/lib/kwartz/binding/php.rb +167 -0
  143. data/lib/kwartz/binding/rails.rb +295 -0
  144. data/lib/kwartz/binding/struts.rb +109 -0
  145. data/lib/kwartz/config.rb +28 -0
  146. data/lib/kwartz/converter.rb +920 -0
  147. data/lib/kwartz/error.rb +41 -0
  148. data/lib/kwartz/main.rb +464 -0
  149. data/lib/kwartz/node.rb +454 -0
  150. data/lib/kwartz/parser.rb +903 -0
  151. data/lib/kwartz/translator.rb +153 -0
  152. data/lib/kwartz/util/assert-text-equal.rb +44 -0
  153. data/lib/kwartz/util/testcase-helper.rb +112 -0
  154. data/setup.rb +1331 -0
  155. data/test/test-compile.rb +36 -0
  156. data/test/test-compile.yaml +178 -0
  157. data/test/test-converter.rb +34 -0
  158. data/test/test-converter.yaml +127 -0
  159. data/test/test-directives.rb +32 -0
  160. data/test/test-directives.yaml +1411 -0
  161. data/test/test-main.rb +464 -0
  162. data/test/test-parser.rb +54 -0
  163. data/test/test-parser.yaml +394 -0
  164. data/test/test-rails.rb +28 -0
  165. data/test/test-rails.yaml +301 -0
  166. data/test/test-ruleset.rb +36 -0
  167. data/test/test-ruleset.yaml +804 -0
  168. data/test/test.rb +44 -0
  169. metadata +236 -0
@@ -0,0 +1,295 @@
1
+ ###
2
+ ### $Rev: 110 $
3
+ ### $Release: 3.0.0 $
4
+ ### copyright(c) 2004-2006 kuwata-lab.com all rights reserved
5
+ ###
6
+
7
+ require 'kwartz/converter'
8
+ #require 'kwartz/translator'
9
+ require 'kwartz/binding/eruby'
10
+
11
+
12
+
13
+ module Kwartz
14
+
15
+
16
+
17
+ ##
18
+ ## directive handler for Rails
19
+ ##
20
+ ## ex.
21
+ ## converter = Converter.new(pdata, decls, :handler=>RailsDirectiveHandler.new)
22
+ ##
23
+ ## directive examples.
24
+ ##
25
+ ## ## text_field, password_field
26
+ ## <input type="text" size="10" maxsize="20" title="text_field 'user', 'name'">
27
+ ## => <%= text_field 'user', 'name', :size=>10, :maxsize=>20 %>
28
+ ## <input type="text" name="user[name]" title="text_field :size=>10">
29
+ ## => <%= text_field "user", "name", :size=>10 %>
30
+ ## <input type="text" id="user_name" size="10" title="text_field">
31
+ ## => <%= text_field "user", "name", :size=>10 %>
32
+ ##
33
+ ## ## link_to, link_to_remote
34
+ ## <a href="#" title="link_to :action=>'list'">Show list</a>
35
+ ## => <%= link_to 'Show list', :action=>'list' %>
36
+ ##
37
+ ## ## start_link_to, start_link_to_remote
38
+ ## <a href="#" title="start_link_to :action=>'list'">Show list</a>
39
+ ## => <%= start_link_to 'action'=>'list' %>Show list</a>
40
+ ##
41
+ ## ## mail_to
42
+ ## <a href="mail:www@example.com" title="mail_to">admin</a>
43
+ ## => <%= mail_to "www@example.com", "admin" %>
44
+ ##
45
+ ## ## form_tag
46
+ ## <form action="show" title="form_tag :id=>2"> ... </form>
47
+ ## => <%= form_tag :action=>"show", :id=>2 %> ... </form>
48
+ ##
49
+ ## ## submit_tag
50
+ ## <input type="submit" value="OK" title="submit_tag">
51
+ ## => <%= submit_tag "OK" %>
52
+ ##
53
+ ## ## text_area
54
+ ## <textarea cols="30" rows="3" id="user_desc" title="text_area"></textarea>
55
+ ## => <%= text_area "user", "desc", :cols=>30, :rows=>3 %>
56
+ ## <textarea cols="30" rows="3" name="user[desc]" title="text_area"></textarea>
57
+ ## => <%= text_area "user", "desc", :cols=>30, :rows=>3 %>
58
+ ##
59
+ ## ## hidden_field
60
+ ## <input type="hidden" id="user_id" title="hidden_field">
61
+ ## => <%= hidden_field "user", "id" %>
62
+ ## <input type="hidden" name="user[id]" title="hidden_field">
63
+ ## => <%= hidden_field "user", "id" %>
64
+ ##
65
+ ## ## check_box
66
+ ## <input type="checkbox" id="user_chk1" title="check_box">
67
+ ## => <%= check_box "user", "chk1" %>
68
+ ## <input type="checkbox" name="user[chk2]" title="check_box">
69
+ ## => <%= check_box "user", "chk2" %>
70
+ ##
71
+ ## ## radio_button
72
+ ## <input type="radio" id="user_radio" value="val1" title="radio_button">
73
+ ## => <%= radio_button "user", "radio", "val1" %>
74
+ ## <input type="radio" name="user[radio]" value="val2" title="radio_button">
75
+ ## => <%= radio_button "user", "radio", "val2" %>
76
+ ##
77
+ ## ## select, collection_select, country_select, time_zone_select, date_select, datetime_select
78
+ ## <select name="user[birth]" title="date_select :start_year=>1970">
79
+ ## <option value="2000">2000</option>
80
+ ## </select>
81
+ ## => <% date_select "user", "birth", :start_year=>1970 %>
82
+ ##
83
+ ## ## image_tag, link_image_to, link_to_image
84
+ ## <img src="foo.gif" alt="text" width="20" heigth="10" title="image_tag :size=>'30x40'">
85
+ ## => <%= image_tag "foo.gif", :alt=>"text", :size=>'30x40' %>
86
+ ##
87
+
88
+ class RailsHandler < ErubyHandler
89
+
90
+
91
+ ##
92
+ ## handle directives for rails.
93
+ ##
94
+ ## everytime return true whenever directive name is unknown.
95
+ ##
96
+ def handle(directive_name, directive_arg, directive_str, stag_info, etag_info, cont_stmts, attr_info, append_exprs, stmt_list)
97
+ ret = super
98
+ return ret if ret
99
+
100
+ d_name = directive_name
101
+ d_arg = directive_arg
102
+ d_str = directive_str
103
+
104
+ ## parse 'name="user[name]"' or 'id="user_name"'
105
+ case directive_name.to_s
106
+ when /(_|\A)radio_button\z/
107
+ add_directive_object_and_method_and_value(d_arg, attr_info)
108
+ when /_field\z/, /_area\z/, /_box\z/, /(_|\A)select\z/, 'input'
109
+ add_directive_object_and_method(d_arg, attr_info)
110
+ end
111
+
112
+ ## replace whole element, or only start tag
113
+ replace_elem = directive_name.to_s !~ /\Astart_/
114
+
115
+ case directive_name
116
+
117
+ when :text_field, :password_field, :hidden_field
118
+ #add_directive_object_and_method(d_arg, attr_info)
119
+ add_directive_integer_option(d_arg, 'size', attr_info['size'])
120
+ add_directive_integer_option(d_arg, 'maxsize', attr_info['maxsize'])
121
+
122
+ when :file_field
123
+ #add_directive_object_and_method(d_arg, attr_info)
124
+ add_directive_integer_option(d_arg, 'size', attr_info['size'])
125
+
126
+ when :link_to, :link_to_remote, :link_to_unless_current
127
+ add_directive_content_as_arg(d_arg, cont_stmts)
128
+
129
+ when :anchor, :anchor_remote
130
+ replace_elem = false
131
+
132
+ when :mail_to
133
+ add_directive_content_as_arg(d_arg, cont_stmts)
134
+ add_directive_attr_as_arg(d_arg, attr_info, 'href')
135
+ d_arg.sub!(/\A\'mailto:/, "'")
136
+
137
+ when :form_tag, :start_form_tag
138
+ add_directive_attr_as_option(d_arg, attr_info, 'action')
139
+ replace_elem = false
140
+
141
+ when :text_area
142
+ #add_directive_object_and_method(d_arg, attr_info)
143
+ add_directive_integer_option(d_arg, 'cols', attr_info['cols'])
144
+ add_directive_integer_option(d_arg, 'rows', attr_info['rows'])
145
+
146
+ when :submit_tag
147
+ add_directive_attr_as_arg(d_arg, attr_info, 'value')
148
+
149
+ when :submit_to_remote
150
+ add_directive_attr_as_arg(d_arg, attr_info, 'value')
151
+ add_directive_attr_as_arg(d_arg, attr_info, 'name')
152
+
153
+ when :radio_button
154
+ #add_directive_object_and_method_and_value(d_arg, attr_info)
155
+
156
+ when :check_box
157
+ #add_directive_object_and_method(d_arg, attr_info)
158
+
159
+ when :select, :collection_select, :country_select, :time_zone_select, :date_select, :datetime_select
160
+ #add_directive_object_and_method(d_arg, attr_info)
161
+
162
+ when :image_tag, :link_image_to, :link_to_image
163
+ add_directive_attr_as_arg(d_arg, attr_info, 'src')
164
+ add_directive_str_option(d_arg, 'alt', attr_info['alt'])
165
+
166
+ else
167
+
168
+ end #case
169
+
170
+ ##
171
+ print_directive(d_name, d_arg, stag_info, etag_info, cont_stmts, attr_info, stmt_list, replace_elem)
172
+
173
+ return true # everytime return true
174
+
175
+ end
176
+
177
+
178
+ protected
179
+
180
+
181
+ def quote(str)
182
+ return "'#{str.gsub(/['\\]/, '\\\\\&')}'"
183
+ end
184
+
185
+
186
+ def add_directive_object_and_method(d_arg, attr_info)
187
+ if (/\A(\w+)\[(\w+)\]\z/ =~ attr_info['name']) || (/\A([a-zA-A0-9]+)_(\w+)\z/ =~ attr_info['id'])
188
+ object = $1 ; method = $2
189
+ d_arg[0,0] = "#{quote(object)}, #{quote(method)}#{d_arg.empty? ? '' : ', '}"
190
+ end
191
+ end
192
+
193
+
194
+ def add_directive_object_and_method_and_value(d_arg, attr_info)
195
+ object = method = ''
196
+ if (/\A(\w+)\[(\w+)\]\z/ =~ attr_info['name']) || (/\A([a-zA-z0-9]+)_(\w+?)_[a-zA-z0-9]+\z/ =~ attr_info['id'])
197
+ object = $1 ; method = $2
198
+ end
199
+ value = attr_info['value']
200
+ d_arg[0,0] = "#{quote(object)}, #{quote(method)}, #{quote(value)}#{d_arg.empty? ? '' : ', '}"
201
+ end
202
+
203
+
204
+ def add_directive_attr_as_arg(d_arg, attr_info, attr_name)
205
+ if (v = attr_info[attr_name]) && !v.empty?
206
+ d_arg[0,0] = "#{quote(v)}#{d_arg.empty? ? '' : ', '}"
207
+ end
208
+ end
209
+
210
+
211
+ def add_directive_attr_as_option(d_arg, attr_info, attr_name)
212
+ if (s = attr_info[attr_name]) && !d_arg.index(attr_name)
213
+ d_arg << ", " unless d_arg.empty?
214
+ d_arg << "'#{attr_name}'=>#{quote(s)}"
215
+ end
216
+ end
217
+
218
+
219
+ def add_directive_content_as_arg(d_arg, cont_stmts)
220
+ if d_arg.empty? || d_arg[0] == ?: || d_arg[0] == ?{
221
+ print_stmt = cont_stmts[0]
222
+ label = print_stmt.args[0]
223
+ d_arg[0,0] = "#{quote(label)}#{d_arg.empty? ? '' : ', '}" if label
224
+ end
225
+ end
226
+
227
+
228
+ def add_directive_integer_option(directive_arg, attr_name, attr_value)
229
+ if attr_value && attr_value =~ /\A\d+\z/
230
+ directive_arg << ', ' unless directive_arg.empty?
231
+ directive_arg << ":#{attr_name}=>#{attr_value.to_i}"
232
+ end
233
+ end
234
+
235
+
236
+ def add_directive_expr_option(directive_arg, attr_name, attr_value)
237
+ if attr_value
238
+ directive_arg << ', ' unless directive_arg.empty?
239
+ directive_arg << ":#{attr_name}=>#{attr_value}"
240
+ end
241
+ end
242
+
243
+
244
+ def add_directive_str_option(directive_arg, attr_name, attr_value)
245
+ if attr_value
246
+ directive_arg << ', ' unless directive_arg.empty?
247
+ directive_arg << ":#{attr_name}=>#{quote(attr_value.to_s)}"
248
+ end
249
+ end
250
+
251
+
252
+ def print_directive(d_name, d_arg, stag_info, etag_info, cont_stmts, attr_info, stmt_list, replace_elem=true)
253
+ head_space = stag_info.head_space
254
+ tail_space = (etag_info || stag_info).tail_space
255
+ args = []
256
+ args << head_space if head_space
257
+ args << NativeExpression.new("#{d_name} #{d_arg}")
258
+ args << tail_space if tail_space
259
+ stmt_list << PrintStatement.new(args)
260
+ unless replace_elem
261
+ stmt_list.concat(cont_stmts)
262
+ stmt_list << PrintStatement.new([etag_info.tag_text])
263
+ end
264
+ end
265
+
266
+
267
+ end #class
268
+ Handler.register_class('rails', RailsHandler)
269
+
270
+
271
+
272
+ ##
273
+ ## translator for rails
274
+ ##
275
+ class RailsTranslator < BaseTranslator
276
+
277
+
278
+ RAILS_EMBED_PATTERNS = [
279
+ '<% ', ' -%>', # statement (chop newline)
280
+ '<%= ', ' %>', # expression
281
+ '<%=h ', ' %>', # escaped expression
282
+ ]
283
+
284
+
285
+ def initialize(properties={})
286
+ super(RAILS_EMBED_PATTERNS, properties)
287
+ end
288
+
289
+
290
+ end
291
+ Translator.register_class('rails', RailsTranslator)
292
+
293
+
294
+
295
+ end #module
@@ -0,0 +1,109 @@
1
+ ###
2
+ ### $Rev: 111 $
3
+ ### $Release: 3.0.0 $
4
+ ### copyright(c) 2004-2006 kuwata-lab.com all rights reserved
5
+ ###
6
+
7
+ require 'kwartz/assert'
8
+ require 'kwartz/converter'
9
+ require 'kwartz/translator'
10
+ require 'kwartz/binding/jstl'
11
+
12
+
13
+
14
+ module Kwartz
15
+
16
+
17
+
18
+ ##
19
+ ## [experimental] directive handler for Struts
20
+ ##
21
+ class StrutsHandler < JstlHandler # :nodoc:
22
+
23
+
24
+
25
+ def handle(directive_name, directive_arg, directive_str, stag_info, etag_info, cont_stmts, attr_info, append_exprs, stmt_list)
26
+ ret = super
27
+ return ret if ret
28
+
29
+ d_name = directive_name
30
+ d_arg = directive_arg
31
+ d_str = directive_str
32
+
33
+ case directive_name
34
+
35
+ when :struts
36
+ case tag = stag_info.tagname
37
+ when 'input' ; tag = attr_info['type'] || 'text' ; attr_info.delete('type')
38
+ when 'a' ; tag = 'link'
39
+ when 'script' ; tag = 'javascript'
40
+ end
41
+ tag == :struts and raise convert_error("#{d_str}: unknown directive.", stag_info.linenum)
42
+ return self.handle(tag.intern, d_arg, directive_str, stag_info, etag_info,
43
+ cont_stmts, attr_info, append_exprs, stmt_list)
44
+
45
+ else
46
+ convert_mapping = {
47
+ 'name'=>'property',
48
+ 'class'=>'cssClass'
49
+ }
50
+ convert_mapping.each do |html_aname, struts_aname|
51
+ next unless attr_info[html_aname]
52
+ attr_info[struts_aname] = attr_info[html_aname]
53
+ attr_info.delete(html_aname)
54
+ end
55
+ opts = eval "_evaluate_options(#{d_arg})"
56
+ opts.each do |name, value|
57
+ attr_info[name.to_s] = value.is_a?(Symbol) ? "${#{value}}" : value
58
+ end
59
+ tagname = "html:#{d_name}"
60
+ stag_info.tagname = tagname
61
+ etag_info.tagname = tagname if etag_info
62
+ stag_info.is_empty = true if !etag_info
63
+ stmt_list << build_print_stmt(stag_info, attr_info, append_exprs)
64
+ stmt_list.concat(cont_stmts)
65
+ stmt_list << build_print_stmt(etag_info, nil, nil) if etag_info
66
+
67
+ end #case
68
+ return true
69
+
70
+ end #def
71
+
72
+
73
+ end #class
74
+ Handler.register_class('struts', StrutsHandler)
75
+
76
+
77
+
78
+ ##
79
+ ## translator for php
80
+ ##
81
+ class StrutsTranslator < JstlTranslator
82
+
83
+
84
+ def initialize(properties={})
85
+ super
86
+ self.header << '<%@ taglib uri="/tags/struts-html" prefix="html" %>' << @nl
87
+ #self.header << '<%@ taglib uri="/tags/struts-bean" prefix="bean" %>' << @nl
88
+ #self.header << '<%@ taglib uri="/tags/struts-logic" prefix="logic" %>' << @nl
89
+ end
90
+
91
+
92
+ def translate_native_expr(expr)
93
+ assert unless expr.is_a?(NativeExpression)
94
+ flag_escape = expr.escape?
95
+ flag_escape = @escape if flag_escape == nil
96
+ if flag_escape == false
97
+ @sb << @expr_l << expr.code << @expr_r # ex. <c:out value="${expr}" escapeXml="false"/>
98
+ else
99
+ @sb << @escape_l << expr.code << @escape_r # ex. <c:out value="${expr}"/>
100
+ end
101
+ end
102
+
103
+
104
+ end
105
+ Translator.register_class('struts', StrutsTranslator)
106
+
107
+
108
+
109
+ end #module
@@ -0,0 +1,28 @@
1
+ ###
2
+ ### $Rev: 110 $
3
+ ### $Release: 3.0.0 $
4
+ ### copyright(c) 2004-2006 kuwata-lab.com all rights reserved
5
+ ###
6
+
7
+
8
+ module Kwartz
9
+
10
+
11
+ module Config
12
+
13
+
14
+ PROPERTY_ESCAPE = nil # escape when true, not escape when false, handler depend when nil
15
+ PROPERTY_ODD = "'odd'"
16
+ PROPERTY_EVEN = "'even'"
17
+ PROPERTY_LANG = 'eruby'
18
+ PROPERTY_DATTR = 'title'
19
+ PROPERTY_DELSPAN = false # delete dummy <span> tag or not
20
+ #
21
+ NO_ETAGS = [ 'input', 'img' ,'br', 'hr', 'meta', 'link' ]
22
+ #ALLOW_DUPLICATE_ID = false
23
+
24
+
25
+ end
26
+
27
+
28
+ end
@@ -0,0 +1,920 @@
1
+ ###
2
+ ### $Rev: 117 $
3
+ ### $Release: 3.0.0 $
4
+ ### copyright(c) 2004-2006 kuwata-lab.com all rights reserved
5
+ ###
6
+
7
+ require 'strscan'
8
+
9
+ require 'kwartz/assert'
10
+ require 'kwartz/error'
11
+ require 'kwartz/node'
12
+ require 'kwartz/config'
13
+
14
+ require 'abstract'
15
+
16
+
17
+ module Kwartz
18
+
19
+
20
+ class ConvertError < KwartzError
21
+
22
+
23
+ def initialize(message, filename, linenum)
24
+ super(message)
25
+ @filename = filename
26
+ @linenum = linenum
27
+ end
28
+
29
+ attr_accessor :linenum
30
+
31
+
32
+ def to_s
33
+ s = super
34
+ return "#{@filename}:#{@linenum}: #{s}"
35
+ #return "#{s}(line #{@linenum})"
36
+ end
37
+
38
+
39
+ end
40
+
41
+
42
+
43
+ class TagInfo
44
+
45
+
46
+ def initialize(matched, linenum=nil)
47
+ @prev_text = matched[1]
48
+ @tag_text = matched[2]
49
+ @head_space = matched[3]
50
+ @is_etag = matched[4] == '/'
51
+ @tagname = matched[5]
52
+ @attr_str = matched[6]
53
+ @extra_space = matched[7]
54
+ @is_empty = matched[8] == '/'
55
+ @tail_space = matched[9]
56
+ @linenum = linenum
57
+ end
58
+
59
+
60
+ attr_accessor :prev_text, :tag_text, :head_space, :is_etag, :tagname, :attr_str, :extra_space, :is_empty, :tail_space
61
+ attr_accessor :linenum
62
+ alias is_etag? is_etag
63
+ alias is_empty? is_empty
64
+
65
+
66
+ def tagname=(tagname)
67
+ @tagname = tagname
68
+ rebuild_tag_text()
69
+ tagname
70
+ end
71
+
72
+
73
+ def rebuild_tag_text(attr_info=nil)
74
+ if attr_info
75
+ sb = ''
76
+ attr_info.each do |space, aname, avalue|
77
+ sb << "#{space}#{aname}=\"#{avalue}\""
78
+ end
79
+ @attr_str = sb
80
+ end
81
+ @tag_text = "#{@head_space}<#{@is_etag ? '/' : ''}#{@tagname}#{@attr_str}#{@extra_space}#{@is_empty ? '/' : ''}>#{@tail_space}"
82
+ end
83
+
84
+
85
+ def _inspect
86
+ return [ @prev_text, @head_space, @is_etag, @tagname, @attr_str, @extra_space, @is_empty, @tail_space ]
87
+ end
88
+
89
+
90
+ end
91
+
92
+
93
+
94
+ class AttrInfo
95
+
96
+
97
+ def initialize(attr_str)
98
+ @names = []
99
+ @values = {}
100
+ @spaces = {}
101
+ attr_str.scan(/(\s+)([-:_\w]+)="([^"]*?)"/) do |space, name, value|
102
+ @names << name unless @values.key?(name)
103
+ @values[name] = value
104
+ @spaces[name] = space
105
+ end
106
+ @directive = nil
107
+ @linenum = nil
108
+ end
109
+ attr_reader :names, :values, :spaces
110
+ attr_accessor :directive, :linenum
111
+
112
+
113
+ def [](name)
114
+ @values[name]
115
+ end
116
+
117
+
118
+ def []=(name, value)
119
+ @names << name unless @values.key?(name)
120
+ @values[name] = value
121
+ @spaces[name] = ' ' unless @spaces.key?(name)
122
+ end
123
+
124
+
125
+ def each
126
+ @names.each do |name|
127
+ space = @spaces[name]
128
+ value = @values[name]
129
+ yield(space, name, value)
130
+ end
131
+ end
132
+
133
+
134
+ def delete(name)
135
+ if @values.key?(name)
136
+ @names.delete(name)
137
+ @values.delete(name)
138
+ @spaces.delete(name)
139
+ end
140
+ end
141
+
142
+
143
+ def empty?
144
+ return @names.empty?
145
+ end
146
+
147
+
148
+ end
149
+
150
+
151
+
152
+ class ElementInfo
153
+
154
+
155
+ def initialize(name, stag_info, etag_info, cont_stmts, attr_info, append_exprs)
156
+ @name = name # String
157
+ @stag_info = stag_info # TagInfo
158
+ @etag_info = etag_info # TagInfo
159
+ @cont_stmts = cont_stmts # list of Statement
160
+ @attr_info = attr_info # AttrInfo
161
+ @append_exprs = append_exprs # list of NativeExpression
162
+ @logic = [ ExpandStatement.new(:elem, @name) ]
163
+ @merged = nil
164
+ end
165
+
166
+ attr_accessor :name, :stag_info, :etag_info, :cont_stmts, :attr_info, :append_exprs, :logic
167
+ attr_reader :stag_expr, :cont_expr, :etag_expr, :elem_expr
168
+
169
+
170
+ def merged?
171
+ @merged
172
+ end
173
+
174
+
175
+ def self.create(values={})
176
+ self.new(values[:name], values[:stag], values[:etag], values[:cont], values[:attr], values[:append])
177
+ end
178
+
179
+
180
+ def merge(elem_ruleset)
181
+ return unless elem_ruleset.name == @name
182
+ @merged = elem_ruleset
183
+ @stag_expr = _to_native_expr(elem_ruleset.stag)
184
+ @cont_expr = _to_native_expr(elem_ruleset.cont || elem_ruleset.value)
185
+ @etag_expr = _to_native_expr(elem_ruleset.etag)
186
+ @elem_expr = _to_native_expr(elem_ruleset.elem)
187
+ if @cont_expr
188
+ @cont_stmts = [ PrintStatement.new([@cont_expr]) ]
189
+ @stag_info.tail_space = ''
190
+ @etag_info.head_space = ''
191
+ @etag_info.rebuild_tag_text()
192
+ end
193
+ elem_ruleset.remove.each do |aname|
194
+ @attr_info.delete(aname)
195
+ end if elem_ruleset.remove
196
+ elem_ruleset.attrs.each do |aname, avalue|
197
+ @attr_info[aname] = _to_native_expr(avalue)
198
+ end if elem_ruleset.attrs
199
+ elem_ruleset.append.each do |expr|
200
+ (@append_exprs ||= []) << _to_native_expr(expr)
201
+ end if elem_ruleset.append
202
+ @tagname = elem_ruleset.tagname
203
+ @logic = elem_ruleset.logic if elem_ruleset.logic
204
+ end
205
+
206
+
207
+ private
208
+
209
+
210
+ def _to_native_expr(value)
211
+ return value && value.is_a?(String) ? NativeExpression.new(value) : value
212
+ end
213
+
214
+
215
+ end
216
+
217
+
218
+
219
+ ##
220
+ ## helper module for Converter and Handler
221
+ ##
222
+ ## Handler and Converter class include this module.
223
+ ##
224
+ module ConverterHelper # :nodoc:
225
+
226
+
227
+ ## set @despan and @dattr
228
+ def include_properties(properties)
229
+ @dattr = properties[:dattr] || Config::PROPERTY_DATTR # default: 'title'
230
+ @delspan = properties.key?(:delspan) ? properties[:delspan] : Config::PROPERTY_DELSPAN # delete dummy <span> tag or not
231
+ end
232
+
233
+
234
+ ## return ConvertError
235
+ def convert_error(message, linenum)
236
+ return ConvertError.new(message, @filename, linenum)
237
+ end
238
+
239
+
240
+ ## raise errror if etag_info is null
241
+ def error_if_empty_tag(stag_info, etag_info, d_name, d_arg)
242
+ unless etag_info
243
+ raise convert_error("'#{d_name}:#{d_arg}': #{d_name} directive is not available with empty tag.", stag_info.linenum)
244
+ end
245
+ end
246
+
247
+
248
+ ## create print statement from text
249
+ def create_text_print_stmt(text)
250
+ return PrintStatement.new([text])
251
+ #return new PritnStatement.new([TextExpression.new(text)])
252
+ end
253
+
254
+
255
+ ## create array of String and NativeExpression for PrintStatement
256
+ def build_print_args(taginfo, attr_info, append_exprs)
257
+ return [] if taginfo.tagname.nil?
258
+ #if taginfo.tagname.nil?
259
+ # if (!attr_info || attr_info.empty?) && (!append_exprs || append_exprs.empty?)
260
+ # return []
261
+ # else
262
+ # taginfo.tagname = 'span'
263
+ # end
264
+ #end
265
+ unless attr_info || append_exprs
266
+ return [taginfo.tag_text]
267
+ end
268
+ args = []
269
+ t = taginfo
270
+ sb = "#{t.head_space}<#{t.is_etag ? '/' : ''}#{t.tagname}"
271
+ attr_info.each do |space, aname, avalue|
272
+ sb << "#{space}#{aname}=\""
273
+ if avalue.is_a?(NativeExpression)
274
+ args << sb # TextExpression.new(sb)
275
+ args << avalue
276
+ sb = ''
277
+ else
278
+ sb << avalue
279
+ end
280
+ sb << '"'
281
+ end if attr_info
282
+ if append_exprs && !append_exprs.empty?
283
+ unless sb.empty?
284
+ args << sb # TextExpression.new(sb)
285
+ sb = ''
286
+ end
287
+ args.concat(append_exprs)
288
+ end
289
+ sb << "#{t.extra_space}#{t.is_empty ? '/' : ''}>#{t.tail_space}"
290
+ args << sb # TextExpression.new(sb)
291
+ return args
292
+ end
293
+
294
+
295
+ ## create PrintStatement for TagInfo
296
+ def build_print_stmt(taginfo, attr_info, append_exprs)
297
+ args = build_print_args(taginfo, attr_info, append_exprs)
298
+ return PrintStatement.new(args)
299
+ end
300
+
301
+
302
+ ## create PrintStatement for NativeExpression
303
+ def build_print_expr_stmt(native_expr, stag_info, etag_info)
304
+ head_space = (stag_info || etag_info).head_space
305
+ tail_space = (etag_info || stag_info).tail_space
306
+ args = []
307
+ args << head_space if head_space # TexExpression.new(head_space)
308
+ args << native_expr
309
+ args << tail_space if tail_space # TextExpression.new(tail_space)
310
+ return PrintStatement.new(args)
311
+ end
312
+
313
+
314
+ end
315
+
316
+
317
+
318
+ ##
319
+ ## .[abstract] expand ExpandStatement and ElementInfo
320
+ ##
321
+ ## Handler class includes this module.
322
+ ##
323
+ module ElementExpander
324
+ include Assertion
325
+
326
+
327
+ ## .[abstract] get ElementRuleset
328
+ def get_element_ruleset(name)
329
+ not_implemented
330
+ end
331
+
332
+
333
+ ## .[abstract] get ElementInfo
334
+ def get_element_info(name)
335
+ not_implemented
336
+ end
337
+
338
+
339
+ ## expand ElementInfo
340
+ def expand_element_info(elem_info, stmt_list, content_only=false)
341
+ #elem_ruleset = @ruleset_table[elem_info.name]
342
+ elem_ruleset = get_element_ruleset(elem_info.name)
343
+ if elem_ruleset && !elem_info.merged?
344
+ elem_info.merge(elem_ruleset)
345
+ end
346
+ logic = content_only ? [ ExpandStatement.new(:cont, elem_info.name) ] : elem_info.logic
347
+ logic.each do |stmt|
348
+ expand_statement(stmt, stmt_list, elem_info)
349
+ end
350
+ #if content_only
351
+ # stmt = ExpandStatement.new(:cont, elem_info.name)
352
+ # expand_statement(stmt, stmt_list, elem_info)
353
+ #else
354
+ # element.logic.each do |stmt|
355
+ # expand_statement(stmt, stmt_list, elem_info)
356
+ # end
357
+ #end
358
+ end
359
+
360
+
361
+ ## expand ExpandStatement
362
+ def expand_statement(stmt, stmt_list, elem_info)
363
+
364
+ if stmt.is_a?(ExpandStatement)
365
+ e = elem_info
366
+
367
+ ## delete dummy '<span>' tag
368
+ if @delspan && e.stag_info.tagname == 'span' && e.attr_info.empty? && e.append_exprs.nil?
369
+ e.stag_info.tagname = e.etag_info.tagname = nil
370
+ end
371
+
372
+ case stmt.kind
373
+
374
+ when :stag
375
+ assert unless elem_info
376
+ if e.stag_expr
377
+ assert unless e.stag_expr.is_a?(NativeExpression)
378
+ stmt_list << build_print_expr_stmt(e.stag_expr, e.stag_info, nil)
379
+ else
380
+ stmt_list << build_print_stmt(e.stag_info, e.attr_info, e.append_exprs)
381
+ end
382
+
383
+ when :etag
384
+ assert unless elem_info
385
+ if e.etag_expr
386
+ assert unless e.etag_expr.is_a?(NativeExpression)
387
+ stmt_list << build_print_expr_stmt(e.etag_expr, nil, e.etag_info)
388
+ elsif e.etag_info # e.etag_info is nil when <br>, <input>, <hr>, <img>, <meta>
389
+ stmt_list << build_print_stmt(e.etag_info, nil, nil)
390
+ end
391
+
392
+ when :cont
393
+ if e.cont_expr
394
+ assert unless e.cont_expr.is_a?(NativeExpression)
395
+ stmt_list << PrintStatement.new([e.cont_expr])
396
+ else
397
+ elem_info.cont_stmts.each do |cont_stmt|
398
+ expand_statement(cont_stmt, stmt_list, nil)
399
+ end
400
+ end
401
+
402
+ when :elem
403
+ assert unless elem_info
404
+ if e.elem_expr
405
+ assert unless e.elem_expr.is_a?(NativeExpression)
406
+ stmt_list << build_print_expr_stmt(e.elem_expr, e.stag_info, e.etag_info)
407
+ else
408
+ stmt.kind = :stag
409
+ expand_statement(stmt, stmt_list, elem_info)
410
+ stmt.kind = :cont
411
+ expand_statement(stmt, stmt_list, elem_info)
412
+ stmt.kind = :etag
413
+ expand_statement(stmt, stmt_list, elem_info)
414
+ stmt.kind = :elem
415
+ end
416
+
417
+ when :element, :content
418
+ content_only = stmt.kind == :content
419
+ #elem_info = @elements[stmt.name]
420
+ elem_info = get_element_info(stmt.name)
421
+ unless elem_info
422
+ raise convert_error("element '#{stmt.name}' is not found.", nil)
423
+ end
424
+ expand_element_info(elem_info, stmt_list, content_only)
425
+
426
+ else
427
+ assert
428
+ end #case
429
+ else
430
+ stmt_list << stmt
431
+ end #if
432
+ end
433
+
434
+
435
+ end #module
436
+
437
+
438
+
439
+ ##
440
+ ## .[abstract] handle directives
441
+ ##
442
+ class Handler
443
+ include Assertion
444
+ include ConverterHelper
445
+ include ElementExpander
446
+
447
+
448
+ def initialize(elem_rulesets=[], properties={})
449
+ @elem_rulesets = elem_rulesets
450
+ #@elem_ruleset_table = elem_rulesets.inject({}) { |table, ruleset| table[ruleset.name] = ruleset; table }
451
+ @elem_ruleset_table = {} ; elem_rulesets.each { |ruleset| @elem_ruleset_table[ruleset.name] = ruleset }
452
+ @elem_info_table = {}
453
+ include_properties(properties) # @delspan and @dattr
454
+ @odd = properties[:odd] || Config::PROPERTY_ODD # "'odd'"
455
+ @even = properties[:even] || Config::PROPERTY_EVEN # "'even'"
456
+ @filename = nil
457
+ end
458
+ attr_reader :odd, :even
459
+ attr_accessor :converter, :filename
460
+
461
+
462
+ def get_element_ruleset(name) # for ElementExpander module and Converter class
463
+ @elem_ruleset_table[name]
464
+ end
465
+
466
+
467
+ def get_element_info(name) # for ElementExpander module
468
+ @elem_info_table[name]
469
+ end
470
+
471
+
472
+ protected
473
+
474
+
475
+ ## .[abstract] directive pattern, which is used to detect directives.
476
+ def directive_pattern
477
+ not_implemented
478
+ #return /\A(\w+):\s*(.*)/
479
+ end
480
+
481
+
482
+ ## .[abstract] mapping pattern, which is used to parse 'attr' directive.
483
+ def mapping_pattern
484
+ not_implemented
485
+ #return /\A'([-:\w]+)'\s+(.*)/
486
+ end
487
+
488
+
489
+ ## .[abstract] directive format, which is used at has_directive?() method
490
+ def directive_format
491
+ not_implemented
492
+ #return '%s: %s'
493
+ end
494
+
495
+
496
+ public
497
+
498
+
499
+ ## handle directives ('stag', 'etag', 'elem', 'cont'(='value'))
500
+ ##
501
+ ## return true if directive name is one of 'stag', 'etag', 'elem', 'cont', and 'value',
502
+ ## else return false.
503
+ def handle(directive_name, directive_arg, directive_str, stag_info, etag_info, cont_stmts, attr_info, append_exprs, stmt_list)
504
+ d_name = directive_name
505
+ d_arg = directive_arg
506
+ d_str = directive_str
507
+
508
+ case directive_name
509
+
510
+ when nil
511
+ assert unless !attr_info.empty? || !append_exprs.empty?
512
+ stmt_list << build_print_stmt(stag_info, attr_info, append_exprs)
513
+ stmt_list.concat(cont_stmts)
514
+ stmt_list << build_print_stmt(etag_info, nil, nil) if etag_info # when empty-tag
515
+
516
+ when :dummy
517
+ # nothing
518
+
519
+ when :id, :mark
520
+ unless directive_arg =~ /\A(\w+)\z/ || directive_arg =~ /\A'(\w+)'\z/
521
+ raise convert_error("'#{d_str}': invalid marking name.", stag_info.linenum)
522
+ end
523
+ name = $1
524
+ elem_info = ElementInfo.new(name, stag_info, etag_info, cont_stmts, attr_info, append_exprs)
525
+ if @elem_info_table[name]
526
+ #unless Config::ALLOW_DUPLICATE_ID
527
+ previous_linenum = @elem_info_table[name].stag_info.linenum
528
+ raise convert_error("'#{d_str}': id '#{name}' is already used at line #{previous_linenum}.", stag_info.linenum)
529
+ #end
530
+ else
531
+ @elem_info_table[name] = elem_info
532
+ end
533
+ #stmt_list << ExpandStatement.new(:element, name) # lazy expantion
534
+ expand_element_info(elem_info, stmt_list)
535
+
536
+ when :stag, :Stag, :STAG
537
+ error_if_empty_tag(stag_info, etag_info, d_name, d_arg)
538
+ flag_escape = d_name == :stag ? nil : (d_name == :Stag)
539
+ expr = NativeExpression.new(d_arg, flag_escape)
540
+ stmt_list << build_print_expr_stmt(expr, stag_info, nil)
541
+ stmt_list.concat(cont_stmts)
542
+ stmt_list << build_print_stmt(etag_info, nil, nil)
543
+
544
+ when :etag, :Etag, :ETAG
545
+ error_if_empty_tag(stag_info, etag_info, d_name, d_arg)
546
+ flag_escape = d_name == :etag ? nil : (d_name == :Etag)
547
+ expr = NativeExpression.new(d_arg, flag_escape)
548
+ stmt_list << build_print_stmt(stag_info, attr_info, append_exprs)
549
+ stmt_list.concat(cont_stmts)
550
+ stmt_list << build_print_expr_stmt(expr, nil, etag_info)
551
+
552
+ when :elem, :Elem, :ELEM
553
+ flag_escape = d_name == :elem ? nil : (d_name == :Elem)
554
+ expr = NativeExpression.new(d_arg, flag_escape)
555
+ stmt_list << build_print_expr_stmt(expr, stag_info, etag_info)
556
+
557
+ when :cont, :Cont, :CONT, :value, :Value, :VALUE
558
+ error_if_empty_tag(stag_info, etag_info, d_name, d_arg)
559
+ stag_info.tail_space = etag_info.head_space = nil # delete spaces
560
+ args = build_print_args(stag_info, attr_info, append_exprs)
561
+ flag_escape = (d_name == :cont || d_name == :value) ? nil : (d_name == :Cont || d_name == :Value)
562
+ args << NativeExpression.new(d_arg, flag_escape)
563
+ #args << etag_info.tag_text
564
+ args << etag_info.tag_text if etag_info.tagname
565
+ stmt_list << PrintStatement.new(args)
566
+
567
+ when :attr, :Attr, :ATTR
568
+ unless d_arg =~ self.mapping_pattern() # ex. /\A'([-:\w]+)'\s+(.*)\z/
569
+ raise convert_error("'#{d_str}': invalid attr pattern.", stag_info.linenum)
570
+ end
571
+ aname = $1; avalue = $2
572
+ flag_escape = d_name == :attr ? nil : (d_name == :Attr)
573
+ attr_info[aname] = NativeExpression.new(avalue, flag_escape)
574
+
575
+ when :append, :Append, :APPEND
576
+ flag_escape = d_name == :append ? nil : (d_name == :Append)
577
+ append_exprs << NativeExpression.new(d_arg, flag_escape)
578
+
579
+ when :replace_element_with_element, :replace_element_with_content,
580
+ :replace_content_with_element, :replace_content_with_content
581
+ arr = d_name.to_s.split(/_/)
582
+ replace_cont = arr[1] == 'content'
583
+ with_content = arr[3] == 'content'
584
+ name = d_arg
585
+ #
586
+ error_if_empty_tag(stag_info, etag_info, d_name, d_arg) if replace_cont
587
+ stmt_list << build_print_stmt(stag_info, attr_info, append_exprs) if replace_cont
588
+ #stmt_list << ExpandStatement.new(:element, name)
589
+ elem_info = @elem_info_table[name]
590
+ unless elem_info
591
+ raise convert_error("'#{d_str}': element '#{name}' not found.", stag_info.linenum)
592
+ end
593
+ expand_element_info(elem_info, stmt_list, with_content)
594
+ stmt_list << build_print_stmt(etag_info, nil, nil) if replace_cont
595
+
596
+ when :replace_element_with, :replace_content_with, :replace, :placeholder
597
+ unless d_arg =~ /\A_?(element|content)\(["']?(\w+)["']?\)\z/
598
+ raise convert_error("'#{d_str}': invalid #{d_name} format.", stag_info.linenum)
599
+ end
600
+ kind = $1
601
+ name = $2
602
+ replace_cont = d_name == :replace_content_with || d_name == :placeholder
603
+ with_content = kind == 'content'
604
+ #
605
+ error_if_empty_tag(stag_info, etag_info, d_name, d_arg) if replace_cont
606
+ stmt_list << build_print_stmt(stag_info, attr_info, append_exprs) if replace_cont
607
+ #stmt_list << ExpandStatement.new(:element, name)
608
+ elem_info = @elem_info_table[name]
609
+ unless elem_info
610
+ raise convert_error("'#{d_str}': element '#{name}' not found.", stag_info.linenum)
611
+ end
612
+ expand_element_info(elem_info, stmt_list, with_content)
613
+ stmt_list << build_print_stmt(etag_info, nil, nil) if replace_cont
614
+ else
615
+ return false
616
+ end #case
617
+
618
+ return true
619
+
620
+ end
621
+
622
+
623
+ def extract(elem_name, content_only=false)
624
+ elem_info = @elem_info_table[elem_name]
625
+ elem_info or raise convert_error("element '#{elem_name}' not found.", nil)
626
+ stmt_list = []
627
+ expand_element_info(elem_info, stmt_list, content_only)
628
+ #stmt_list << build_print_stmt(etag_info, nil, nil)
629
+ return stmt_list
630
+ end
631
+
632
+
633
+ @@class_table = {}
634
+
635
+
636
+ def self.register_class(lang, klass)
637
+ @@class_table[lang] = klass
638
+ end
639
+
640
+
641
+ def self.get_class(lang)
642
+ return @@class_table[lang]
643
+ end
644
+
645
+
646
+ end #class
647
+
648
+
649
+
650
+ ##
651
+ ## .[abstract] covnert presentation data into list of Statement.
652
+ ##
653
+ class Converter
654
+ include ConverterHelper
655
+
656
+
657
+ def initialize(handler, properties={})
658
+ @handler = handler
659
+ @handler.converter = self
660
+ end
661
+
662
+ attr_reader :handler #, :dattr, :input
663
+
664
+
665
+ ## .[abstract] convert string into list of Statement.
666
+ def convert(input, filename='')
667
+ not_implemented
668
+ end
669
+
670
+
671
+ @@class_table = {}
672
+
673
+
674
+ def self.register_class(style, klass)
675
+ @@class_table[style] = klass
676
+ end
677
+
678
+
679
+ def self.get_class(style)
680
+ return @@class_table[style]
681
+ end
682
+
683
+
684
+ end
685
+
686
+
687
+
688
+ ##
689
+ ## convert presentation data (html) into a list of Statement.
690
+ ## notice that TextConverter class hanlde html file as text format, not html format.
691
+ ##
692
+ class TextConverter < Converter
693
+
694
+
695
+ def initialize(handler, properties={})
696
+ super
697
+ include_properties(properties) # set @delspan and @dattr
698
+ end
699
+
700
+
701
+ ## called from convert() and initialize converter object
702
+ def reset(input, filename)
703
+ @scanner = StringScanner.new(input)
704
+ @filename = filename
705
+ @handler.filename = filename
706
+ @rest = nil
707
+ @linenum = 1
708
+ @linenum_delta = 0
709
+ end
710
+ protected :reset
711
+
712
+ attr_reader :rest, :linenum
713
+
714
+
715
+ def convert(input, filename='')
716
+ reset(input, filename)
717
+ stmt_list = []
718
+ doc_ruleset = @handler.get_element_ruleset('DOCUMENT')
719
+ stmt_list += doc_ruleset.begin if doc_ruleset && doc_ruleset.begin
720
+ #stmt_list << NativeStatement.new(doc_ruleset.head.chomp, nil) if doc_ruleset && doc_ruleset.head
721
+ _convert(stmt_list)
722
+ stmt_list += doc_ruleset.end if doc_ruleset && doc_ruleset.end
723
+ #stmt_list << NativeStatement.new(doc_ruleset.tail.chomp, nil) if doc_ruleset && doc_ruleset.tail
724
+ return stmt_list
725
+ end
726
+
727
+
728
+ protected
729
+
730
+
731
+ #FETCH_PATTERN= /([ \t]*)<(\/?)([-:_\w]+)((?:\s+[-:_\w]+="[^"]*?")*)(\s*)(\/?)>([ \t]*\r?\n?)/ #"
732
+ @@fetch_pattern = /(.*?)((^[ \t]*)?<(\/?)([-:_\w]+)((?:\s+[-:_\w]+="[^"]*?")*)(\s*)(\/?)>([ \t]*\r?\n)?)/m #"
733
+
734
+
735
+ def self.fetch_pattern=(regexp)
736
+ @@fetch_pattern = regexp
737
+ end
738
+
739
+
740
+ private
741
+
742
+
743
+ def fetch
744
+ str = @scanner.scan(@@fetch_pattern)
745
+ unless str
746
+ @rest = @scanner.scan(/.*/m)
747
+ return nil
748
+ end
749
+ taginfo = TagInfo.new(@scanner)
750
+ @linenum += (@linenum_delta + taginfo.prev_text.count("\n"))
751
+ @linenum_delta = taginfo.tag_text.count("\n")
752
+ taginfo.linenum = linenum
753
+ return taginfo
754
+ end
755
+
756
+
757
+ def _convert(stmt_list, start_tag_info=nil, start_attr_info=nil)
758
+ start_tagname = start_tag_info ? start_tag_info.tagname : nil
759
+ start_linenum = @linenum
760
+
761
+ ##
762
+ while taginfo = fetch()
763
+ #tag_text, prev_text, head_space, is_etag, tagname, attr_str, extra_space, is_empty, tail_space = taginfo.to_a
764
+
765
+ prev_text = taginfo.prev_text
766
+ stmt_list << create_text_print_stmt(prev_text) if prev_text && !prev_text.empty?
767
+
768
+ if taginfo.is_etag? # end tag
769
+
770
+ if taginfo.tagname == start_tagname
771
+ etag_info = taginfo
772
+ return etag_info
773
+ else
774
+ stmt_list << create_text_print_stmt(taginfo.tag_text)
775
+ end
776
+
777
+ elsif taginfo.is_empty? || skip_etag?(taginfo) # empty tag
778
+
779
+ attr_info = AttrInfo.new(taginfo.attr_str)
780
+ if has_directive?(attr_info, taginfo)
781
+ stag_info = taginfo
782
+ etag_info = nil
783
+ cont_stmts = []
784
+ handle_directive(stag_info, etag_info, cont_stmts, attr_info, stmt_list)
785
+ else
786
+ stmt_list << create_text_print_stmt(taginfo.tag_text)
787
+ end
788
+
789
+ else # start tag
790
+
791
+ attr_info = AttrInfo.new(taginfo.attr_str)
792
+ if has_directive?(attr_info, taginfo)
793
+ stag_info = taginfo
794
+ cont_stmts = []
795
+ etag_info = _convert(cont_stmts, taginfo)
796
+ handle_directive(stag_info, etag_info, cont_stmts, attr_info, stmt_list)
797
+ elsif taginfo.tagname == start_tagname
798
+ stag_info = taginfo
799
+ stmt_list << create_text_print_stmt(stag_info.tag_text)
800
+ etag_info = _convert(stmt_list, stag_info)
801
+ stmt_list << create_text_print_stmt(etag_info.tag_text)
802
+ else
803
+ stmt_list << create_text_print_stmt(taginfo.tag_text)
804
+ end
805
+
806
+ end #if
807
+
808
+ end #while
809
+
810
+ if start_tag_info
811
+ raise convert_error("'<#{start_tagname}>' is not closed.", start_tag_info.linenum)
812
+ end
813
+
814
+ stmt_list << create_text_print_stmt(@rest) if @rest
815
+ nil
816
+
817
+ end #def
818
+
819
+
820
+ def handle_directive(stag_info, etag_info, cont_stmts, attr_info, stmt_list)
821
+ directive_name = directive_arg = directive_str = nil
822
+ append_exprs = nil
823
+
824
+ ## handle 'attr:' and 'append:' directives
825
+ d_str = nil
826
+ attr_info.directive.split(/;/).each do |d_str|
827
+ d_str.strip!
828
+ unless d_str =~ @handler.directive_pattern # ex. /\A(\w+):\s*(.*)\z/
829
+ raise convert_error("'#{d_str}': invalid directive pattern", stag_info.linenum)
830
+ end
831
+ d_name = $1.intern # directive name
832
+ d_arg = $2 || '' # directive arg
833
+ case d_name
834
+ when :attr, :Attr, :ATTR
835
+ @handler.handle(d_name, d_arg, d_str, stag_info, etag_info,
836
+ cont_stmts, attr_info, append_exprs, stmt_list)
837
+ when :append, :Append, :APPEND
838
+ append_exprs ||= []
839
+ @handler.handle(d_name, d_arg, d_str, stag_info, etag_info,
840
+ cont_stmts, attr_info, append_exprs, stmt_list)
841
+ else
842
+ if directive_name
843
+ raise convert_error("'#{d_str}': not available with '#{directive_name}' directive.", stag_info.linenum)
844
+ end
845
+ directive_name = d_name
846
+ directive_arg = d_arg
847
+ directive_str = d_str
848
+ end #case
849
+ end if attr_info.directive
850
+
851
+ ## remove dummy <span> tag
852
+ if @delspan && stag_info.tagname == 'span' && attr_info.empty? && append_exprs.nil? && directive_name != :id
853
+ stag_info.tagname = etag_info.tagname = nil
854
+ end
855
+
856
+ ## handle other directives
857
+ ret = @handler.handle(directive_name, directive_arg, directive_str, stag_info, etag_info,
858
+ cont_stmts, attr_info, append_exprs, stmt_list)
859
+ if directive_name && !ret
860
+ raise convert_error("'#{directive_str}': unknown directive.", stag_info.linenum)
861
+ end
862
+
863
+ end
864
+
865
+
866
+ ## detect whether directive is exist or not
867
+ def has_directive?(attr_info, taginfo)
868
+ ## title attribute
869
+ val = attr_info[@dattr] # ex. @dattr == 'title'
870
+ if val && val.is_a?(String) && !val.empty?
871
+ if val[0] == ?\ ;
872
+ val[0,1] = '' # delete a space
873
+ taginfo.rebuild_tag_text(attr_info)
874
+ #return false
875
+ elsif val =~ @handler.directive_pattern() # ex. /\A(\w+):\s*(.*)/
876
+ attr_info.delete(@dattr)
877
+ attr_info.directive = val
878
+ return true
879
+ else
880
+ raise convert_error("'#{@dattr}=\"#{val}\"': invalid directive pattern.", taginfo.linenum)
881
+ end
882
+ end
883
+ ## id attribute
884
+ val = attr_info['id']
885
+ if val
886
+ case val
887
+ when /\A\w+\z/
888
+ attr_info.directive = @handler.directive_format() % ['mark', val]
889
+ return true
890
+ #when @handler.directive_pattern() # ex. /\A\w+:/
891
+ # attr_info.delete('id')
892
+ # attr_info.directive = val
893
+ # return true
894
+ when /\A(mark|dummy):(\w+)\z/,
895
+ /\A(replace_(?:element|content)_with_(?:element|content)):(\w+)\z/
896
+ attr_info.directive = @handler.directive_format() % [$1, $2]
897
+ attr_info.delete('id')
898
+ return true
899
+ end
900
+ end
901
+ return false
902
+ end
903
+
904
+
905
+ skip_etags = Config::NO_ETAGS # %w[input img br hr meta link]
906
+ #@@skip_etag_table = skip_etags.inject({}) { |table, tagname| table[tagname] = true; table }
907
+ @@skip_etag_table = {} ; skip_etags.each { |tagname| @@skip_etag_table[tagname] = true }
908
+
909
+
910
+ def skip_etag?(taginfo)
911
+ return @@skip_etag_table[taginfo.tagname]
912
+ end
913
+
914
+
915
+ end #class
916
+ Converter.register_class('text', TextConverter)
917
+
918
+
919
+
920
+ end #moduel