runo 0.1.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 (149) hide show
  1. data/LICENSE +19 -0
  2. data/README.rdoc +120 -0
  3. data/bin/runo +35 -0
  4. data/lib/_error.rb +14 -0
  5. data/lib/_field.rb +260 -0
  6. data/lib/_i18n.rb +141 -0
  7. data/lib/_parser.rb +243 -0
  8. data/lib/_path.rb +86 -0
  9. data/lib/_storage/_storage.rb +213 -0
  10. data/lib/_storage/file.rb +200 -0
  11. data/lib/_storage/sequel.rb +174 -0
  12. data/lib/_storage/temp.rb +73 -0
  13. data/lib/_widget/action_create.rb +23 -0
  14. data/lib/_widget/action_login.rb +22 -0
  15. data/lib/_widget/action_signup.rb +16 -0
  16. data/lib/_widget/action_update.rb +16 -0
  17. data/lib/_widget/crumb.rb +24 -0
  18. data/lib/_widget/done.rb +16 -0
  19. data/lib/_widget/login.rb +25 -0
  20. data/lib/_widget/me.rb +31 -0
  21. data/lib/_widget/message.rb +51 -0
  22. data/lib/_widget/navi.rb +88 -0
  23. data/lib/_widget/submit.rb +49 -0
  24. data/lib/_widget/view_ym.rb +77 -0
  25. data/lib/_workflow/_workflow.rb +89 -0
  26. data/lib/_workflow/attachment.rb +50 -0
  27. data/lib/_workflow/blog.rb +28 -0
  28. data/lib/_workflow/contact.rb +23 -0
  29. data/lib/_workflow/forum.rb +26 -0
  30. data/lib/_workflow/register.rb +39 -0
  31. data/lib/meta/_meta.rb +20 -0
  32. data/lib/meta/group.rb +19 -0
  33. data/lib/meta/id.rb +59 -0
  34. data/lib/meta/owner.rb +21 -0
  35. data/lib/meta/timestamp.rb +118 -0
  36. data/lib/runo.rb +396 -0
  37. data/lib/scalar/checkbox.rb +68 -0
  38. data/lib/scalar/file.rb +144 -0
  39. data/lib/scalar/img.rb +112 -0
  40. data/lib/scalar/password.rb +58 -0
  41. data/lib/scalar/radio.rb +47 -0
  42. data/lib/scalar/select.rb +47 -0
  43. data/lib/scalar/text.rb +38 -0
  44. data/lib/scalar/textarea.rb +35 -0
  45. data/lib/scalar/textarea_pre.rb +14 -0
  46. data/lib/scalar/textarea_wiki.rb +173 -0
  47. data/lib/set/_set.rb +195 -0
  48. data/lib/set/dynamic.rb +177 -0
  49. data/lib/set/static.rb +102 -0
  50. data/lib/set/static_folder.rb +96 -0
  51. data/locale/en/index.po +242 -0
  52. data/locale/index.pot +243 -0
  53. data/locale/ja/index.po +242 -0
  54. data/locale/lazy_parser.rb +54 -0
  55. data/skel/config.ru +27 -0
  56. data/skel/skin/_users/00000000_frank-avatar.jpg +0 -0
  57. data/skel/skin/_users/00000000_frank-avatar_small.jpg +0 -0
  58. data/skel/skin/_users/00000000_frank.yaml +12 -0
  59. data/skel/skin/_users/00000000_root-avatar.jpg +0 -0
  60. data/skel/skin/_users/00000000_root-avatar_small.jpg +0 -0
  61. data/skel/skin/_users/00000000_root.yaml +11 -0
  62. data/skel/skin/_users/css/users.css +21 -0
  63. data/skel/skin/_users/css/users.less +25 -0
  64. data/skel/skin/_users/done.html +42 -0
  65. data/skel/skin/_users/index.html +46 -0
  66. data/skel/skin/_users/index.yaml +3 -0
  67. data/skel/skin/_users/summary.html +40 -0
  68. data/skel/skin/css/base.css +93 -0
  69. data/skel/skin/css/base.less +139 -0
  70. data/skel/skin/css/coax.css +199 -0
  71. data/skel/skin/css/coax.less +244 -0
  72. data/skel/skin/examples/blog/20091214_0001.yaml +8 -0
  73. data/skel/skin/examples/blog/20100630_0001.yaml +8 -0
  74. data/skel/skin/examples/blog/20100630_0002.yaml +14 -0
  75. data/skel/skin/examples/blog/20100701_0001.yaml +8 -0
  76. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f.jpg +0 -0
  77. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f_small.jpg +0 -0
  78. data/skel/skin/examples/blog/20100701_0002.yaml +19 -0
  79. data/skel/skin/examples/blog/frank/20100701_0001.yaml +10 -0
  80. data/skel/skin/examples/blog/frank/index.yaml +4 -0
  81. data/skel/skin/examples/blog/index.html +51 -0
  82. data/skel/skin/examples/blog/rss.xml +18 -0
  83. data/skel/skin/examples/contact/20100701_0001-file.txt +1 -0
  84. data/skel/skin/examples/contact/20100701_0001.yaml +15 -0
  85. data/skel/skin/examples/contact/20100701_0002.yaml +8 -0
  86. data/skel/skin/examples/contact/20100701_0003.yaml +9 -0
  87. data/skel/skin/examples/contact/index.html +47 -0
  88. data/skel/skin/examples/contact/js/contact.js +13 -0
  89. data/skel/skin/examples/contact/summary.html +54 -0
  90. data/skel/skin/examples/forum/20100701_0001.yaml +41 -0
  91. data/skel/skin/examples/forum/20100701_0002.yaml +25 -0
  92. data/skel/skin/examples/forum/index.html +68 -0
  93. data/skel/skin/examples/forum/summary.html +47 -0
  94. data/skel/skin/examples/index.html +75 -0
  95. data/skel/skin/index.html +41 -0
  96. data/skel/skin/js/base.js +50 -0
  97. data/t/locale/de/index.po +19 -0
  98. data/t/locale/en-GB/index.po +25 -0
  99. data/t/locale/ja/index.po +30 -0
  100. data/t/skin/_users/00000000_test.yaml +3 -0
  101. data/t/skin/_users/index.html +13 -0
  102. data/t/skin/foo/20091120_0001.yaml +7 -0
  103. data/t/skin/foo/bar/20091120_0001.yaml +5 -0
  104. data/t/skin/foo/bar/index.yaml +5 -0
  105. data/t/skin/foo/baz/css/baz.css +1 -0
  106. data/t/skin/foo/css/foo.css +1 -0
  107. data/t/skin/foo/index.html +14 -0
  108. data/t/skin/foo/index.yaml +7 -0
  109. data/t/skin/foo/not_css/foo.css +1 -0
  110. data/t/skin/foo/sub-20100306_0001.yaml +3 -0
  111. data/t/skin/index.yaml +3 -0
  112. data/t/skin/t_attachment/index.html +13 -0
  113. data/t/skin/t_contact/done.html +6 -0
  114. data/t/skin/t_contact/index.html +9 -0
  115. data/t/skin/t_file/index.html +16 -0
  116. data/t/skin/t_img/index.html +14 -0
  117. data/t/skin/t_img/test.jpg +0 -0
  118. data/t/skin/t_select/index.html +9 -0
  119. data/t/skin/t_store/index.html +9 -0
  120. data/t/skin/t_summary/20100326_0001.yaml +3 -0
  121. data/t/skin/t_summary/create.html +9 -0
  122. data/t/skin/t_summary/index.html +9 -0
  123. data/t/skin/t_summary/summary.html +9 -0
  124. data/t/t.rb +27 -0
  125. data/t/test_checkbox.rb +273 -0
  126. data/t/test_field.rb +330 -0
  127. data/t/test_file.rb +900 -0
  128. data/t/test_id.rb +215 -0
  129. data/t/test_img.rb +328 -0
  130. data/t/test_meta.rb +57 -0
  131. data/t/test_parser.rb +1266 -0
  132. data/t/test_password.rb +188 -0
  133. data/t/test_radio.rb +226 -0
  134. data/t/test_role.rb +249 -0
  135. data/t/test_runo.rb +742 -0
  136. data/t/test_runo_call.rb +1286 -0
  137. data/t/test_runo_i18n.rb +318 -0
  138. data/t/test_select.rb +182 -0
  139. data/t/test_set_complex.rb +527 -0
  140. data/t/test_set_dynamic.rb +1504 -0
  141. data/t/test_set_folder.rb +515 -0
  142. data/t/test_set_permit.rb +246 -0
  143. data/t/test_set_static.rb +445 -0
  144. data/t/test_storage.rb +915 -0
  145. data/t/test_text.rb +125 -0
  146. data/t/test_textarea.rb +138 -0
  147. data/t/test_timestamp.rb +473 -0
  148. data/t/test_workflow.rb +367 -0
  149. metadata +345 -0
@@ -0,0 +1,318 @@
1
+ # encoding: UTF-8
2
+
3
+ # Author:: Akira FUNAI
4
+ # Copyright:: Copyright (c) 2009 Akira FUNAI
5
+
6
+ require "#{::File.dirname __FILE__}/t"
7
+
8
+ class TC_Runo_I18n < Test::Unit::TestCase
9
+
10
+ include Runo::I18n
11
+
12
+ def setup
13
+ Runo::I18n.domain = 'index'
14
+ Runo::I18n.po_dir = './t/locale'
15
+ end
16
+
17
+ def teardown
18
+ end
19
+
20
+ def test_lang
21
+ Runo::I18n.lang = 'ja'
22
+ assert_instance_of(
23
+ Array,
24
+ Runo::I18n.lang,
25
+ 'Runo::I18n.lang should return an array'
26
+ )
27
+ assert_equal(
28
+ ['ja'],
29
+ Runo::I18n.lang,
30
+ 'Runo::I18n.lang should return the current acceptable language-ranges'
31
+ )
32
+ end
33
+
34
+ def test_lang_case
35
+ Runo::I18n.lang = 'JA-jp'
36
+ assert_equal(
37
+ ['ja-JP'],
38
+ Runo::I18n.lang,
39
+ 'Runo::I18n.lang should be properly downcase/upcased'
40
+ )
41
+ end
42
+
43
+ def test_multiple_lang
44
+ Runo::I18n.lang = 'ja, de;q=0.5, en;q=0.8'
45
+ assert_equal(
46
+ ['ja', 'en', 'de'],
47
+ Runo::I18n.lang,
48
+ 'Runo::I18n.lang should sort the language-ranges by their quality values'
49
+ )
50
+ end
51
+
52
+ def test_same_qvalues
53
+ Runo::I18n.lang = 'ja, de;q=0.5, en;q=0.5'
54
+ assert_equal(
55
+ ['ja', 'de', 'en'],
56
+ Runo::I18n.lang,
57
+ 'Runo::I18n.lang should be sorted by their original order if the qvalues are same'
58
+ )
59
+ Runo::I18n.lang = 'ja, de, en'
60
+ assert_equal(
61
+ ['ja', 'de', 'en'],
62
+ Runo::I18n.lang,
63
+ 'Runo::I18n.lang should be sorted by their original order if the qvalues are same'
64
+ )
65
+ end
66
+
67
+ def test_po_dir
68
+ Runo::I18n.po_dir = 'foo/bar'
69
+ assert_equal(
70
+ 'foo/bar',
71
+ Runo::I18n.po_dir,
72
+ 'Runo::I18n.po_dir should be return the path to po files'
73
+ )
74
+ end
75
+
76
+ def test_domain
77
+ Runo::I18n.domain = 'foo'
78
+ assert_equal(
79
+ 'foo',
80
+ Runo::I18n.domain,
81
+ 'Runo::I18n.domain should be return the current domain'
82
+ )
83
+ end
84
+
85
+ def test_bindtextdomain
86
+ Runo::I18n.bindtextdomain('foo', 'bar/baz')
87
+ assert_equal(
88
+ 'foo',
89
+ Runo::I18n.domain,
90
+ 'Runo::I18n.bindtextdomain should set the current domain'
91
+ )
92
+ assert_equal(
93
+ 'bar/baz',
94
+ Runo::I18n.po_dir,
95
+ 'Runo::I18n.bindtextdomain should set the path to po files'
96
+ )
97
+ end
98
+
99
+ def test_msg
100
+ Runo::I18n.lang = 'ja'
101
+ assert_instance_of(
102
+ ::Hash,
103
+ Runo::I18n.msg,
104
+ 'Runo::I18n.msg should return a hash'
105
+ )
106
+ assert_equal(
107
+ {'color' => '色', 'one color' =>['%{n}色']},
108
+ Runo::I18n.msg.reject {|k, v| k == :plural },
109
+ 'Runo::I18n.msg should return a hash containing {msgid => msgstr}'
110
+ )
111
+ assert_instance_of(
112
+ ::Proc,
113
+ Runo::I18n.msg[:plural],
114
+ 'Runo::I18n.msg[:plural] should return a proc'
115
+ )
116
+
117
+ Runo::I18n.lang = 'po'
118
+ assert_equal(
119
+ {},
120
+ Runo::I18n.msg,
121
+ 'Runo::I18n.msg should be reset when the lang is updated'
122
+ )
123
+ end
124
+
125
+ def test_merge_msg!
126
+ Runo::I18n.lang = 'no'
127
+ assert_equal({}, Runo::I18n.msg)
128
+
129
+ Runo::I18n.merge_msg!('color' => 'farge')
130
+ assert_equal(
131
+ {'color' => 'farge'},
132
+ Runo::I18n.msg,
133
+ 'Runo::I18n.merge_msg! should dynamically merge a hash to the msg of the current thread'
134
+ )
135
+
136
+ Runo::I18n.merge_msg!(:plural => Proc.new { 123 })
137
+ assert_equal(
138
+ {'color' => 'farge'},
139
+ Runo::I18n.msg,
140
+ 'Runo::I18n.merge_msg! should not merge :plural'
141
+ )
142
+
143
+ Runo::I18n.lang = 'no'
144
+ assert_equal(
145
+ {},
146
+ Runo::I18n.msg,
147
+ 'Runo::I18n.merge_msg! should not affect anything other than the current thread'
148
+ )
149
+ end
150
+
151
+ def test_rex_plural_expression_ok
152
+ src = <<'_eos'.split "\n"
153
+ "Plural-Forms: nplurals=1; plural=0;"
154
+ "Plural-Forms: nplurals=2; plural=n != 1;"
155
+ "Plural-Forms: nplurals=2; plural=n>1;"
156
+ "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;"
157
+ "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;"
158
+ "Plural-Forms: nplurals=3; Plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;"
159
+ "Plural-Forms: nplurals=3; Plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;"
160
+ "Plural-Forms: nplurals=3; Plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
161
+ "Plural-Forms: nplurals=3; Plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
162
+ "Plural-Forms: nplurals=3; Plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
163
+ "Plural-Forms: nplurals=4; Plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;"
164
+ _eos
165
+ src.each {|s|
166
+ assert_match(
167
+ Runo::I18n::REX::PLURAL_EXPRESSION,
168
+ s,
169
+ 'Runo::I18n::REX::PLURAL_EXPRESSION should match'
170
+ )
171
+ }
172
+ end
173
+
174
+ def test_rex_plural_expression_ng
175
+ src = <<'_eos'.split "\n"
176
+ "Plural-Forms: nplurals=1; plural=rm '.';"
177
+ "Plural-Forms: nplurals=1; plural=Fileutils.rm_r('.');"
178
+ "Plural-Forms: nplurals=1; plural=Fileutils.rm_r '.';"
179
+ "Plural-Forms: nplurals=1; plural=Fileutils.rm_r ".";"
180
+ "Plural-Forms: nplurals=2; plural=n;"
181
+ "Plural-Forms: nplurals=2; plural=nn;"
182
+ "Plural-Forms: nplurals=3; plural=n();"
183
+ "Plural-Forms: nplurals=3; plural=n(123);"
184
+ "Plural-Forms: nplurals=3; plural=n 123;"
185
+ _eos
186
+ src.each {|s|
187
+ assert_no_match(
188
+ Runo::I18n::REX::PLURAL_EXPRESSION,
189
+ s,
190
+ 'Runo::I18n::REX::PLURAL_EXPRESSION should not match malicious expressions'
191
+ )
192
+ }
193
+ end
194
+
195
+ def test__
196
+ Runo::I18n.lang = 'ja'
197
+ assert_equal(
198
+ '色',
199
+ _('color'),
200
+ 'Runo::I18n#_() should return a string according to the msgid'
201
+ )
202
+
203
+ Runo::I18n.lang = 'en-GB'
204
+ assert_equal(
205
+ 'colour',
206
+ _('color'),
207
+ 'Runo::I18n#_() should return a string according to the msgid'
208
+ )
209
+
210
+ Runo::I18n.lang = 'no'
211
+ assert_equal(
212
+ 'color',
213
+ _('color'),
214
+ 'Runo::I18n#_() should return a msgid if the msgid is not existed in the msg'
215
+ )
216
+ end
217
+
218
+ def test_n_
219
+ Runo::I18n.lang = 'ja'
220
+ assert_equal(
221
+ '%{n}色',
222
+ n_('one color', '%{n} colors', 1),
223
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
224
+ )
225
+ assert_equal(
226
+ '%{n}色',
227
+ n_('one color', '%{n} colors', 2),
228
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
229
+ )
230
+
231
+ Runo::I18n.lang = 'en-GB'
232
+ assert_equal(
233
+ 'one colour',
234
+ n_('one color', '%{n} colors', 1),
235
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
236
+ )
237
+ assert_equal(
238
+ '%{n} colours',
239
+ n_('one color', '%{n} colors', 2),
240
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
241
+ )
242
+
243
+ Runo::I18n.lang = 'no'
244
+ assert_equal(
245
+ 'one color',
246
+ n_('one color', '%{n} colors', 1),
247
+ 'Runo::I18n#_() should return a msgid if the msgid is not existed in the msg'
248
+ )
249
+ assert_equal(
250
+ '%{n} colors',
251
+ n_('one color', '%{n} colors', 2),
252
+ 'Runo::I18n#_() should return a msgid if the msgid is not existed in the msg'
253
+ )
254
+ end
255
+
256
+ def test__with_n_
257
+ Runo::I18n.lang = 'en-GB'
258
+ assert_equal(
259
+ 'one colour',
260
+ _('one color'),
261
+ 'Runo::I18n#_() should return msgstr[0] if the msgid refer to plural msgstrs'
262
+ )
263
+ end
264
+
265
+ def test_n_with__
266
+ Runo::I18n.lang = 'en-GB'
267
+ assert_equal(
268
+ 'color',
269
+ n_('color', '%{n} colors', 1),
270
+ 'Runo::I18n#n_() should return msgid if the msgid refer to sigular msgstr'
271
+ )
272
+ end
273
+
274
+ def test_msgstr
275
+ Runo::I18n.lang = 'en-GB'
276
+
277
+ assert_instance_of(
278
+ Runo::I18n::Msgstr,
279
+ _('color'),
280
+ 'Runo::I18n#_() should return a instance of Runo::I18n::Msgstr'
281
+ )
282
+
283
+ s = n_('one color', '%{n} colors', 2)
284
+ assert_instance_of(
285
+ Runo::I18n::Msgstr,
286
+ s,
287
+ 'Runo::I18n#n_() should return a instance of Runo::I18n::Msgstr'
288
+ )
289
+ assert_equal(
290
+ '2 colours',
291
+ s % {:n => 2},
292
+ 'Runo::I18n::Msgstr#% should be able to proccess named variables'
293
+ )
294
+ assert_equal(
295
+ '2 colours',
296
+ s % [2],
297
+ "Runo::I18n::Msgstr#% should regard %{...} as '%s' if given an array"
298
+ )
299
+ assert_equal(
300
+ '2 colours',
301
+ s % 2,
302
+ "Runo::I18n::Msgstr#% should regard %{...} as '%s' if given a scalar"
303
+ )
304
+
305
+ s = n_('one color', '%{n} colors', 1)
306
+ assert_instance_of(
307
+ Runo::I18n::Msgstr,
308
+ s,
309
+ 'Runo::I18n#n_() should return a instance of Runo::I18n::Msgstr'
310
+ )
311
+ assert_equal(
312
+ 'one colour',
313
+ s % {:n => 1},
314
+ 'Runo::I18n::Msgstr#% should work with msgstrs without a placeholder'
315
+ )
316
+ end
317
+
318
+ end
@@ -0,0 +1,182 @@
1
+ # encoding: UTF-8
2
+
3
+ # Author:: Akira FUNAI
4
+ # Copyright:: Copyright (c) 2009 Akira FUNAI
5
+
6
+ require "#{::File.dirname __FILE__}/t"
7
+
8
+ class TC_Select < Test::Unit::TestCase
9
+
10
+ def setup
11
+ meta = nil
12
+ Runo::Parser.gsub_scalar("$(foo select bar, baz, qux :'baz' mandatory)") {|id, m|
13
+ meta = m
14
+ ''
15
+ }
16
+ @f = Runo::Field.instance meta
17
+ end
18
+
19
+ def teardown
20
+ end
21
+
22
+ def test_meta
23
+ assert_equal(
24
+ ['bar', 'baz', 'qux'],
25
+ @f[:options],
26
+ 'Select#initialize should set :options from the csv token'
27
+ )
28
+ assert_equal(
29
+ true,
30
+ @f[:mandatory],
31
+ 'Select#initialize should set :mandatory from the misc token'
32
+ )
33
+ assert_equal(
34
+ 'baz',
35
+ @f[:default],
36
+ 'Select#initialize should set :default from the token'
37
+ )
38
+ end
39
+
40
+ def test_meta_options_from_range
41
+ meta = nil
42
+ Runo::Parser.gsub_scalar("$(foo select 1..5)") {|id, m|
43
+ meta = m
44
+ ''
45
+ }
46
+ f = Runo::Field.instance meta
47
+ assert_equal(
48
+ ['1', '2', '3', '4', '5'],
49
+ f[:options],
50
+ 'Select#initialize should set :options from the range token'
51
+ )
52
+
53
+ meta = nil
54
+ Runo::Parser.gsub_scalar("$(foo select ..5)") {|id, m|
55
+ meta = m
56
+ ''
57
+ }
58
+ f = Runo::Field.instance meta
59
+ assert_equal(
60
+ ['0', '1', '2', '3', '4', '5'],
61
+ f[:options],
62
+ 'Select#initialize should set :options from the range token'
63
+ )
64
+
65
+ meta = nil
66
+ Runo::Parser.gsub_scalar("$(foo select 1..)") {|id, m|
67
+ meta = m
68
+ ''
69
+ }
70
+ f = Runo::Field.instance meta
71
+ assert_equal(
72
+ nil,
73
+ f[:options],
74
+ 'Select#initialize should not refer to the range token if there is no maximum'
75
+ )
76
+ end
77
+
78
+ def test_val_cast
79
+ assert_equal(
80
+ '',
81
+ @f.val,
82
+ 'Select#val_cast should cast the given val to String'
83
+ )
84
+
85
+ @f.load 123
86
+ assert_equal(
87
+ '123',
88
+ @f.val,
89
+ 'Select#val_cast should cast the given val to String'
90
+ )
91
+ end
92
+
93
+ def test_get
94
+ @f.load ''
95
+ assert_equal(
96
+ '',
97
+ @f.get,
98
+ 'Select#get should return proper string'
99
+ )
100
+ assert_equal(
101
+ <<_html,
102
+ <span class="select">
103
+ <select name="">
104
+ <option value="">please select</option>
105
+ <option>bar</option>
106
+ <option>baz</option>
107
+ <option>qux</option>
108
+ </select>
109
+ </span>
110
+ _html
111
+ @f.get(:action => :create),
112
+ 'Select#get should return proper string'
113
+ )
114
+
115
+ @f.load 'qux'
116
+ assert_equal(
117
+ 'qux',
118
+ @f.get,
119
+ 'Select#get should return proper string'
120
+ )
121
+ assert_equal(
122
+ <<_html,
123
+ <span class="select">
124
+ <select name="">
125
+ <option>bar</option>
126
+ <option>baz</option>
127
+ <option selected>qux</option>
128
+ </select>
129
+ </span>
130
+ _html
131
+ @f.get(:action => :update),
132
+ 'Select#get should return proper string'
133
+ )
134
+ end
135
+
136
+ def test_get_escape
137
+ @f[:options] = ['foo', '<bar>']
138
+ @f.load '<bar>'
139
+ assert_equal(
140
+ '&lt;bar&gt;',
141
+ @f.get,
142
+ 'Select#get should escape the special characters'
143
+ )
144
+ assert_equal(
145
+ <<_html,
146
+ <span class="select">
147
+ <select name="">
148
+ <option>foo</option>
149
+ <option selected>&lt;bar&gt;</option>
150
+ </select>
151
+ </span>
152
+ _html
153
+ @f.get(:action => :update),
154
+ 'Select#get should escape the special characters'
155
+ )
156
+ end
157
+
158
+ def test_errors
159
+ @f.load ''
160
+ @f[:mandatory] = nil
161
+ assert_equal(
162
+ [],
163
+ @f.errors,
164
+ 'Select#errors should return the errors of the current val'
165
+ )
166
+ @f[:mandatory] = true
167
+ assert_equal(
168
+ ['mandatory'],
169
+ @f.errors,
170
+ 'Select#errors should return the errors of the current val'
171
+ )
172
+
173
+ @f.load 'boo'
174
+ @f[:mandatory] = nil
175
+ assert_equal(
176
+ ['no such option'],
177
+ @f.errors,
178
+ 'Select#errors should return the errors of the current val'
179
+ )
180
+ end
181
+
182
+ end