kwartz 3.0.0

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