bike 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. data/LICENSE +19 -0
  2. data/README.rdoc +124 -0
  3. data/bin/bike +35 -0
  4. data/lib/_error.rb +14 -0
  5. data/lib/_field.rb +260 -0
  6. data/lib/_i18n.rb +144 -0
  7. data/lib/_parser.rb +256 -0
  8. data/lib/_path.rb +86 -0
  9. data/lib/_storage/_storage.rb +215 -0
  10. data/lib/_storage/file.rb +201 -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/bike.rb +396 -0
  32. data/lib/meta/_meta.rb +20 -0
  33. data/lib/meta/group.rb +19 -0
  34. data/lib/meta/id.rb +59 -0
  35. data/lib/meta/owner.rb +21 -0
  36. data/lib/meta/timestamp.rb +118 -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 +196 -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 +73 -0
  95. data/skel/skin/index.html +39 -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/qux/index.html +8 -0
  111. data/t/skin/foo/qux/moo/index.html +6 -0
  112. data/t/skin/foo/sub-20100306_0001.yaml +3 -0
  113. data/t/skin/index.yaml +3 -0
  114. data/t/skin/t_attachment/index.html +13 -0
  115. data/t/skin/t_contact/done.html +6 -0
  116. data/t/skin/t_contact/index.html +9 -0
  117. data/t/skin/t_file/index.html +16 -0
  118. data/t/skin/t_img/index.html +14 -0
  119. data/t/skin/t_img/test.jpg +0 -0
  120. data/t/skin/t_select/index.html +9 -0
  121. data/t/skin/t_store/index.html +9 -0
  122. data/t/skin/t_summary/20100326_0001.yaml +3 -0
  123. data/t/skin/t_summary/create.html +9 -0
  124. data/t/skin/t_summary/index.html +9 -0
  125. data/t/skin/t_summary/summary.html +9 -0
  126. data/t/t.rb +27 -0
  127. data/t/test_bike.rb +768 -0
  128. data/t/test_call.rb +1281 -0
  129. data/t/test_checkbox.rb +273 -0
  130. data/t/test_field.rb +330 -0
  131. data/t/test_file.rb +900 -0
  132. data/t/test_i18n.rb +325 -0
  133. data/t/test_id.rb +215 -0
  134. data/t/test_img.rb +328 -0
  135. data/t/test_meta.rb +57 -0
  136. data/t/test_parser.rb +1516 -0
  137. data/t/test_password.rb +188 -0
  138. data/t/test_radio.rb +226 -0
  139. data/t/test_role.rb +249 -0
  140. data/t/test_select.rb +182 -0
  141. data/t/test_set_complex.rb +527 -0
  142. data/t/test_set_dynamic.rb +1504 -0
  143. data/t/test_set_folder.rb +515 -0
  144. data/t/test_set_permit.rb +246 -0
  145. data/t/test_set_static.rb +468 -0
  146. data/t/test_storage.rb +915 -0
  147. data/t/test_text.rb +125 -0
  148. data/t/test_textarea.rb +138 -0
  149. data/t/test_timestamp.rb +473 -0
  150. data/t/test_workflow.rb +367 -0
  151. metadata +347 -0
@@ -0,0 +1,30 @@
1
+ # just a test.
2
+ # Copyright (C) 2010 Akira FUNAI
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR Akira FUNAI, 2010.
5
+ #
6
+
7
+ "Project-Id-Version: 0.01\n"
8
+ "POT-Creation-Date: 2010-05-06 15:11+0900\n"
9
+ "PO-Revision-Date: 2010-05-06 15:11+0900\n"
10
+ "Last-Translator: Akira FUNAI <akira@funai.com>\n"
11
+ "Language-Team: none <nobody@example.com>\n"
12
+ "MIME-Version: 1.0\n"
13
+ "Content-Type: text/plain; charset=UTF-8\n"
14
+ "Content-Transfer-Encoding: 8bit\n"
15
+ "Plural-Forms: nplurals=1; plural=0;\n"
16
+
17
+ #: t.rb:1234
18
+ msgid "color"
19
+ msgstr "色"
20
+ # msgstr "mmm"
21
+
22
+ #: t.rb:2234
23
+ #, fuzzy
24
+ msgid "sound"
25
+ msgstr "音"
26
+
27
+ #: t.rb:2345
28
+ msgid "one color"
29
+ msgid_plural "%{n} colors"
30
+ msgstr[0] "%{n}色"
@@ -0,0 +1,3 @@
1
+ ---
2
+ _id: test
3
+ password: ulrR7VSYJHTs6
@@ -0,0 +1,13 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <dl id="main" class="app-blog">
6
+ <dt>id: $(_id = meta-id 32 1..32)</dt>
7
+ <dd>
8
+ password: $(password = password 12)
9
+ avatar: $(avatar = img 72*72 0...320000)
10
+ </dd>
11
+ </dl>
12
+ </body>
13
+ </html>
@@ -0,0 +1,7 @@
1
+ _owner: frank
2
+ name: FZ
3
+ comment: oops.
4
+ replies:
5
+ 20091201_0001:
6
+ _owner: carl
7
+ reply: foo.
@@ -0,0 +1,5 @@
1
+ ---
2
+ _owner: carl
3
+ replies:
4
+ 20091208_0001:
5
+ reply: wow.
@@ -0,0 +1,5 @@
1
+ ---
2
+ label: 'Bar Folder'
3
+ group:
4
+ - carl
5
+ - don
@@ -0,0 +1 @@
1
+ #moo {}
@@ -0,0 +1 @@
1
+ #foo {bar: baz;}
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li>
7
+ $(name = text 32 1..32 :'foo'): $(comment = text 64 1..64 :'bar!')
8
+ <ul id="files" class="app-attachment"><li>$(file=text)</li></ul>
9
+ <ul id="replies" class="app-blog"><li>$(reply=text)</li></ul>
10
+ </li>
11
+ </ul>
12
+ <ul id="sub" class="app-blog"><li>$(article=text)</li></ul>
13
+ </body>
14
+ </html>
@@ -0,0 +1,7 @@
1
+ ---
2
+ label: 'Foo Folder'
3
+ admin: frank
4
+ group:
5
+ - roy
6
+ - jim
7
+
@@ -0,0 +1 @@
1
+ #foo {bar: baz;}
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="abc" class="app-blog"><li></li></ul>
6
+ <ul id="sub" class="app-blog"><li></li></ul>
7
+ </body>
8
+ </html>
@@ -0,0 +1,6 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <p>moo!</p>
5
+ </body>
6
+ </html>
@@ -0,0 +1,3 @@
1
+ ---
2
+ _owner: root
3
+ article: qux
@@ -0,0 +1,3 @@
1
+ ---
2
+ label: 'Root'
3
+
@@ -0,0 +1,13 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li title="tArticle, tArticles">
7
+ $(comment=text)
8
+ <ul id="files" class="app-attachment"><li>$(file=text 1..16)</li></ul>
9
+ <ul id="replies" class="app-blog"><li>$(reply=text)</li></ul>
10
+ </li>
11
+ </ul>
12
+ </body>
13
+ </html>
@@ -0,0 +1,6 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <p>thank you!</p>
5
+ </body>
6
+ </html>
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="main" class="app-contact">
6
+ <li>$(name = text 32 1..32 :'foo'): $(comment = text 64 1..64 :'bar!')</li>
7
+ </ul>
8
+ </body>
9
+ </html>
@@ -0,0 +1,16 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li>
7
+ $(_timestamp = meta-timestamp can_edit)
8
+ $(foo = file 0..50)
9
+ $(bar = file 0..50)
10
+ <ul id="baz" class="app-attachment">
11
+ $(qux = file 1..50)
12
+ </ul>
13
+ </li>
14
+ </ul>
15
+ </body>
16
+ </html>
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li>
7
+ $(foo = img 32*32 1..5000 crop)
8
+ <ul id="baz" class="app-attachment">
9
+ $(qux = img 16*16 1..5000 crop)
10
+ </ul>
11
+ </li>
12
+ </ul>
13
+ </body>
14
+ </html>
Binary file
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li>$(name = text 32 1..32 :'foo'): $(comment = text 64 1..64 :'bar!')</li>
7
+ </ul>
8
+ </body>
9
+ </html>
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head><title>@(label)</title></head>
3
+ <body>
4
+ <h1>@(label)</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li>$(name = text 32 1..32 :'foo'): $(comment = text 64 1..64 :'bar!')</li>
7
+ </ul>
8
+ </body>
9
+ </html>
@@ -0,0 +1,3 @@
1
+ ---
2
+ name: frank
3
+ comment: hi.
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head><title>create</title></head>
3
+ <body>
4
+ <h1>create</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li>main-create</li>
7
+ </ul>
8
+ </body>
9
+ </html>
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head><title>index</title></head>
3
+ <body>
4
+ <h1>index</h1>
5
+ <ul id="main" class="app-blog">
6
+ <li>$(name = text 32 1..32 :'foo'): $(comment = text 64 1..64 :'bar!')</li>
7
+ </ul>
8
+ </body>
9
+ </html>
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head><title>summary</title></head>
3
+ <body>
4
+ <h1>summary</h1>
5
+ <table id="main" class="app-blog">
6
+ <tr><td>$(name)</td><td>$(comment)</td></tr>
7
+ </table>
8
+ </body>
9
+ </html>
data/t/t.rb ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ # Author:: Akira FUNAI
5
+ # Copyright:: Copyright (c) 2009 Akira FUNAI
6
+
7
+ require 'test/unit'
8
+ require 'rubygems'
9
+ require 'mocha'
10
+ require 'rack'
11
+
12
+ t_dir = ::File.dirname __FILE__
13
+
14
+ $LOAD_PATH.unshift t_dir
15
+ $LOAD_PATH.unshift(::File.expand_path('../lib', t_dir))
16
+ require 'bike'
17
+
18
+ Bike.config(
19
+ 'skin_dir' => './t/skin',
20
+ 'storage' => {
21
+ 'default' => 'File',
22
+ 'File' => {'data_dir' => './t/data'},
23
+ 'Sequel' => {'uri' => 'sqlite:/'},
24
+ }
25
+ )
26
+
27
+ Bike::I18n.bindtextdomain('index', ::File.join(t_dir, 'locale'))
@@ -0,0 +1,768 @@
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_Bike < Test::Unit::TestCase
9
+
10
+ def setup
11
+ end
12
+
13
+ def teardown
14
+ end
15
+
16
+ def test_session
17
+ assert(
18
+ Bike.session.respond_to?(:[]),
19
+ 'Bike.session should be a Session or Hash'
20
+ )
21
+ end
22
+
23
+ def test_client
24
+ Bike.client = nil
25
+ assert_equal(
26
+ 'nobody',
27
+ Bike.client,
28
+ 'Bike.client should return nobody before login'
29
+ )
30
+
31
+ Bike.client = 'frank'
32
+ assert_equal(
33
+ 'frank',
34
+ Bike.client,
35
+ 'Bike.client should return the user who logged in'
36
+ )
37
+
38
+ Bike.client = nil
39
+ assert_equal(
40
+ 'nobody',
41
+ Bike.client,
42
+ 'Bike.client should return nobody after logout'
43
+ )
44
+ end
45
+
46
+ def test_rebuild_params
47
+ bike = Bike.new
48
+
49
+ hash = bike.instance_eval {
50
+ rebuild_params(
51
+ '.action' => 'update'
52
+ )
53
+ }
54
+ assert_equal(
55
+ {:action => :update},
56
+ hash,
57
+ 'Bike#rebuild_params should be able to rebuild special symbols'
58
+ )
59
+
60
+ hash = bike.instance_eval {
61
+ rebuild_params(
62
+ '.action-update' => 'submit'
63
+ )
64
+ }
65
+ assert_equal(
66
+ {:action => :update},
67
+ hash,
68
+ 'Bike#rebuild_params should be able to rebuild special symbols'
69
+ )
70
+
71
+ hash = bike.instance_eval {
72
+ rebuild_params(
73
+ 'noo' => 'what?',
74
+ 'noo.action-update' => 'submit',
75
+ 'noo.conds-id' => '4567'
76
+ )
77
+ }
78
+ assert_equal(
79
+ {
80
+ 'noo' => {
81
+ :self => 'what?',
82
+ :action => :update,
83
+ :conds => {:id => '4567'},
84
+ },
85
+ },
86
+ hash,
87
+ 'Bike#rebuild_params should rebuild both the special symbols and regular items'
88
+ )
89
+
90
+ hash = bike.instance_eval {
91
+ rebuild_params(
92
+ 'moo.conds-p' => '9',
93
+ 'moo-4567-addr.conds-zip-upper' => '110'
94
+ )
95
+ }
96
+ assert_equal(
97
+ {
98
+ 'moo' => {
99
+ :conds => {:p => '9'},
100
+ '4567' => {
101
+ 'addr' => {
102
+ :conds => {:'zip-upper' => '110'},
103
+ },
104
+ },
105
+ },
106
+ },
107
+ hash,
108
+ 'Bike#rebuild_params should be able to rebuild any combination of symbols and items'
109
+ )
110
+
111
+ hash = bike.instance_eval {
112
+ rebuild_params(
113
+ 'foo-bar.conds-id' => '1234',
114
+ 'foo-bar.conds-p' => ['42'],
115
+ 'foo-bar.action' => 'update',
116
+ 'foo-baz' => ['boo', 'bee'],
117
+ 'foo' => 'oops',
118
+ 'qux.action-create' => 'submit',
119
+ 'qux.status-public' => 'oops'
120
+ )
121
+ }
122
+ assert_equal(
123
+ {
124
+ 'foo' => {
125
+ :self => 'oops',
126
+ 'bar' => {
127
+ :action => :update,
128
+ :conds => {
129
+ :id => '1234',
130
+ :p => ['42'],
131
+ },
132
+ },
133
+ 'baz' => ['boo', 'bee'],
134
+ },
135
+ 'qux' => {
136
+ :action => :create,
137
+ :status => :public,
138
+ },
139
+ },
140
+ hash,
141
+ 'Bike#rebuild_params should be able to rebuild any combination of symbols and items'
142
+ )
143
+ end
144
+
145
+ def test_steps_of
146
+ assert_equal(
147
+ ['foo', 'bar'],
148
+ Bike::Path.steps_of('/foo/bar/'),
149
+ 'Bike::Path.steps_of should be able to extract item steps from path_info'
150
+ )
151
+ assert_equal(
152
+ ['foo', 'bar'],
153
+ Bike::Path.steps_of('/foo/bar/create.html'),
154
+ 'Bike::Path.steps_of should ignore the pseudo-filename'
155
+ )
156
+ assert_equal(
157
+ ['foo'],
158
+ Bike::Path.steps_of('/foo/bar'),
159
+ 'Bike::Path.steps_of should ignore the last step without a following slash'
160
+ )
161
+ assert_equal(
162
+ ['foo', 'bar'],
163
+ Bike::Path.steps_of('/foo//bar/baz=123/'),
164
+ 'Bike::Path.steps_of should distinguish item steps from conds'
165
+ )
166
+ assert_equal(
167
+ ['foo', 'bar'],
168
+ Bike::Path.steps_of('/1234567890.123456/foo/bar/'),
169
+ 'Bike::Path.steps_of should distinguish item steps from a tid'
170
+ )
171
+ end
172
+
173
+ def test_steps_of_with_empty_steps
174
+ assert_equal(
175
+ [],
176
+ Bike::Path.steps_of(''),
177
+ 'Bike::Path.steps_of should return empty array when there is no item steps'
178
+ )
179
+ assert_equal(
180
+ [],
181
+ Bike::Path.steps_of('/'),
182
+ 'Bike::Path.steps_of should return empty array when there is no item steps'
183
+ )
184
+ assert_equal(
185
+ [],
186
+ Bike::Path.steps_of('/index.html'),
187
+ 'Bike::Path.steps_of should return empty array when there is no item steps'
188
+ )
189
+ end
190
+
191
+ def test_steps_of_with_cond_d
192
+ assert_equal(
193
+ ['foo', 'bar'],
194
+ Bike::Path.steps_of('/foo/bar/2009/'),
195
+ 'Bike::Path.steps_of should distinguish item steps from ambiguous conds[:d]'
196
+ )
197
+ assert_equal(
198
+ ['foo', 'bar'],
199
+ Bike::Path.steps_of('/foo/bar/1970/'),
200
+ 'Bike::Path.steps_of should distinguish item steps from ambiguous conds[:d]'
201
+ )
202
+ assert_equal(
203
+ ['foo', 'bar', '3001'],
204
+ Bike::Path.steps_of('/foo/bar/3001/'),
205
+ 'Bike::Path.steps_of should be patched in the next millennium :-)'
206
+ )
207
+ end
208
+
209
+ def test_conds_of
210
+ assert_equal(
211
+ {},
212
+ Bike::Path.conds_of('/foo/bar/'),
213
+ 'Bike::Path.conds_of should return empty hash when there is no conds'
214
+ )
215
+ assert_equal(
216
+ {
217
+ :baz => '123',
218
+ :qux => '456',
219
+ },
220
+ Bike::Path.conds_of('/foo/bar/baz=123/qux=456/'),
221
+ 'Bike::Path.conds_of should be able to extract conds from path_info'
222
+ )
223
+ assert_equal(
224
+ {
225
+ :baz => '123',
226
+ :qux => '456',
227
+ },
228
+ Bike::Path.conds_of('/foo/bar/baz=123/qux=456/create.html'),
229
+ 'Bike::Path.conds_of should ignore the pseudo-filename'
230
+ )
231
+ assert_equal(
232
+ {
233
+ :baz => '1234',
234
+ },
235
+ Bike::Path.conds_of('/foo/bar//baz=1234//qux=4567'),
236
+ 'Bike::Path.conds_of should ignore the item steps and the last step without a slash'
237
+ )
238
+ end
239
+
240
+ def test_conds_of_with_empty_conds
241
+ assert_equal(
242
+ {},
243
+ Bike::Path.conds_of(''),
244
+ 'Bike::Path.conds_of should return empty hash when there is no conds'
245
+ )
246
+ assert_equal(
247
+ {},
248
+ Bike::Path.conds_of('/'),
249
+ 'Bike::Path.conds_of should return empty hash when there is no conds'
250
+ )
251
+ assert_equal(
252
+ {},
253
+ Bike::Path.conds_of('/index.html'),
254
+ 'Bike::Path.conds_of should return empty hash when there is no conds'
255
+ )
256
+ end
257
+
258
+ def test_conds_of_with_cond_d
259
+ assert_equal(
260
+ {
261
+ :d => '200911',
262
+ :baz => '1234',
263
+ :qux => '4567',
264
+ },
265
+ Bike::Path.conds_of('/foo/bar/200911/baz=1234/qux=4567/'),
266
+ 'Bike::Path.conds_of should be able to distinguish ambiguous conds[:d]'
267
+ )
268
+ assert_equal(
269
+ {
270
+ :baz => '1234',
271
+ :qux => '4567',
272
+ },
273
+ Bike::Path.conds_of('/foo/bar/20091129_0001/baz=1234/qux=4567/'),
274
+ 'Bike::Path.conds_of should ignore the full-formatted id'
275
+ )
276
+ end
277
+
278
+ def test_conds_of_with_cond_id
279
+ assert_equal(
280
+ ['foo', 'bar'],
281
+ Bike::Path.steps_of('/foo/bar/20091205/9/baz=1234/qux=4567/'),
282
+ 'Bike::Path.steps_of should ignore conds[:id]'
283
+ )
284
+ assert_equal(
285
+ {
286
+ :id => '20091205_0009',
287
+ :baz => '1234',
288
+ :qux => '4567',
289
+ },
290
+ Bike::Path.conds_of('/foo/bar/20091205/9/baz=1234/qux=4567/'),
291
+ 'Bike::Path.conds_of should extract conds[:id] from the path sequence'
292
+ )
293
+ end
294
+
295
+ def test_action_of
296
+ assert_equal(
297
+ :create,
298
+ Bike::Path.action_of('/foo/bar/create.html'),
299
+ 'Bike::Path.action_of should extract the action from path_info'
300
+ )
301
+
302
+ assert_nil(
303
+ Bike::Path.action_of('/foo/bar/index.html'),
304
+ 'Bike::Path.action_of should return nil if the pseudo-filename is index.*'
305
+ )
306
+ assert_nil(
307
+ Bike::Path.action_of('/foo/bar/'),
308
+ 'Bike::Path.action_of should return nil if no pseudo-filename is given'
309
+ )
310
+ assert_nil(
311
+ Bike::Path.action_of('/foo/bar/_detail.html'),
312
+ "Bike::Path.action_of should return nil if the pseudo-filename begins with '_'"
313
+ )
314
+ end
315
+
316
+ def test_sub_action_of
317
+ assert_equal(
318
+ :detail,
319
+ Bike::Path.sub_action_of('/foo/bar/read_detail.html'),
320
+ 'Bike::Path.sub_action_of should extract the sub_action from path_info'
321
+ )
322
+ assert_nil(
323
+ Bike::Path.sub_action_of('/foo/bar/read.html'),
324
+ "Bike::Path.sub_action_of should return nil if the pseudo-filename does not include '_'"
325
+ )
326
+ end
327
+
328
+ def test_base_of
329
+ sd = Bike::Path.base_of '/foo/bar/main/index.html'
330
+ assert_instance_of(
331
+ Bike::Set::Dynamic,
332
+ sd,
333
+ 'Bike::Path.base_of should return a set_dynamic'
334
+ )
335
+ assert_equal(
336
+ '-foo-bar-main',
337
+ sd[:full_name],
338
+ 'Bike::Path.base_of should return a set_dynamic at the bottom of the given steps'
339
+ )
340
+
341
+ sd = Bike::Path.base_of '/foo/bar/index.html'
342
+ assert_instance_of(
343
+ Bike::Set::Dynamic,
344
+ sd,
345
+ 'Bike::Path.base_of should return a set_dynamic'
346
+ )
347
+ assert_equal(
348
+ '-foo-bar-main',
349
+ sd[:full_name],
350
+ "Bike::Path.base_of should return the item('main') if the given steps point at a folder"
351
+ )
352
+
353
+ sd = Bike::Path.base_of '/foo/qux/index.html'
354
+ assert_instance_of(
355
+ Bike::Set::Dynamic,
356
+ sd,
357
+ "Bike::Path.base_of should return an available set_dynamic if there is no 'main' in the folder"
358
+ )
359
+ assert_equal(
360
+ '-foo-qux-abc',
361
+ sd[:full_name],
362
+ "Bike::Path.base_of should return the first set_dynamic if there is no 'main' in the folder"
363
+ )
364
+
365
+ sd = Bike::Path.base_of '/foo/bar/20091120_0001/comment/index.html'
366
+ assert_instance_of(
367
+ Bike::Text,
368
+ sd,
369
+ 'Bike::Path.base_of should return a text if designated'
370
+ )
371
+
372
+ sd = Bike::Path.base_of '/foo/bar/20091120_0001/files/index.html'
373
+ assert_instance_of(
374
+ Bike::Set::Dynamic,
375
+ sd,
376
+ 'Bike::Path.base_of should return a set_dynamic'
377
+ )
378
+ assert_equal(
379
+ '-foo-bar-main-20091120_0001-files',
380
+ sd[:full_name],
381
+ "Bike::Path.base_of should be able to dive into any depth from the folder"
382
+ )
383
+
384
+ sd = Bike::Path.base_of '/foo/bar/20091120_0002/files/index.html'
385
+ assert_nil(
386
+ sd,
387
+ 'Bike::Path.base_of should return nil if there is no set_dynamic at the steps'
388
+ )
389
+ end
390
+
391
+ def test_base_of_empty_folder
392
+ f = Bike::Path.base_of '/foo/qux/moo/index.html'
393
+ assert_instance_of(
394
+ Bike::Set::Static::Folder,
395
+ f,
396
+ 'Bike::Path.base_of should return an folder if there is no SD in it'
397
+ )
398
+ assert_equal(
399
+ '-foo-qux-moo',
400
+ f[:full_name],
401
+ 'Bike::Path.base_of should return an folder if there is no SD in it'
402
+ )
403
+ end
404
+
405
+ def test_path_of
406
+ assert_equal(
407
+ '20091224/123/',
408
+ Bike::Path.path_of(:id => '20091224_0123'),
409
+ 'Bike::Path.path_of should return a special combination of pseudo-steps for conds[:id]'
410
+ )
411
+ assert_equal(
412
+ '20091224/123/',
413
+ Bike::Path.path_of(:d => '2009', :id => '20091224_0123'),
414
+ 'Bike::Path.path_of should ignore the other conds if there is conds[:id]'
415
+ )
416
+
417
+ assert_equal(
418
+ '20091224/123/',
419
+ Bike::Path.path_of(:id => ['20091224_0123']),
420
+ 'Bike::Path.path_of should return a special combination of pseudo-steps for conds[:id]'
421
+ )
422
+ assert_equal(
423
+ 'id=20091224_0123,20100222_1234/',
424
+ Bike::Path.path_of(:id => ['20091224_0123', '20100222_1234']),
425
+ 'Bike::Path.path_of should return multiple ids as a comma-separated form'
426
+ )
427
+ assert_equal(
428
+ '',
429
+ Bike::Path.path_of(:id => []),
430
+ 'Bike::Path.path_of should return an empty string when given an empty conds[:id]'
431
+ )
432
+
433
+ assert_equal(
434
+ 'id=carl/',
435
+ Bike::Path.path_of(:id => '00000000_carl'),
436
+ "Bike::Path.path_of should use '/id=xxx/' form for a short id"
437
+ )
438
+ assert_equal(
439
+ 'id=20091224_0123,carl/',
440
+ Bike::Path.path_of(:id => ['20091224_0123', '00000000_carl']),
441
+ "Bike::Path.path_of should use short ids in a comma-separated form"
442
+ )
443
+
444
+ assert_equal(
445
+ 'foo=bar/',
446
+ Bike::Path.path_of(:foo => 'bar'),
447
+ 'Bike::Path.path_of should return a path of which steps represent the conds'
448
+ )
449
+ assert_equal(
450
+ 'foo=bar/p=123/',
451
+ Bike::Path.path_of(:p => 123, :foo => 'bar'),
452
+ 'Bike::Path.path_of should return the step for conds[:p] at the tail end'
453
+ )
454
+ assert_equal(
455
+ 'foo=bar/order=desc/p=123/',
456
+ Bike::Path.path_of(:p => 123, :order =>'desc', :foo => 'bar'),
457
+ 'Bike::Path.path_of should return the step for conds[:order] at the tail end'
458
+ )
459
+
460
+ assert_equal(
461
+ 'foo=bar/',
462
+ Bike::Path.path_of(:p => 1, :foo => 'bar'),
463
+ 'Bike::Path.path_of should omit the step for conds[:p] when conds[:p] == 1'
464
+ )
465
+ assert_equal(
466
+ 'p=1/',
467
+ Bike::Path.path_of(:p => 1),
468
+ 'Bike::Path.path_of should not omit the step for conds[:p] when there is no other conds'
469
+ )
470
+
471
+ assert_equal(
472
+ 'foo=1,2,3/',
473
+ Bike::Path.path_of(:foo => [1, 2, 3]),
474
+ 'Bike::Path.path_of should return multiple values as a comma-separated form'
475
+ )
476
+ end
477
+
478
+ def test_params_from_request
479
+ bike = Bike.new
480
+
481
+ env = Rack::MockRequest.env_for(
482
+ 'http://example.com/foo/bar/main/qux=456/read_detail.html?acorn=round',
483
+ {
484
+ :method => 'post',
485
+ :script_name => '',
486
+ :input => 'coax=true&some-doors=open',
487
+ }
488
+ )
489
+ req = Rack::Request.new env
490
+ params = bike.instance_eval {
491
+ params_from_request req
492
+ }
493
+ assert_equal(
494
+ {
495
+ :conds => {:qux => '456'},
496
+ :action => :read,
497
+ :sub_action => :detail,
498
+ 'acorn' => 'round',
499
+ 'coax' => 'true',
500
+ 'some' => {'doors' => 'open'},
501
+ },
502
+ params,
503
+ 'Bike#params_from_request should build params from req.path_info and req.params'
504
+ )
505
+
506
+ env = Rack::MockRequest.env_for(
507
+ 'http://example.com/foo/bar/qux=456/index.html?acorn=round',
508
+ {
509
+ :method => 'post',
510
+ :script_name => '',
511
+ :input => 'coax=true&some-doors=open',
512
+ }
513
+ )
514
+ req = Rack::Request.new env
515
+ params = bike.instance_eval {
516
+ params_from_request req
517
+ }
518
+ assert_equal(
519
+ {
520
+ :conds => {:qux => '456'},
521
+ :action => nil,
522
+ :sub_action => nil,
523
+ 'acorn' => 'round',
524
+ 'coax' => 'true',
525
+ 'some' => {'doors' => 'open'},
526
+ },
527
+ params,
528
+ 'Bike#params_from_request should build params from req.path_info and req.params'
529
+ )
530
+
531
+ env = Rack::MockRequest.env_for(
532
+ 'http://example.com/foo/bar/20091120_0001/files/qux=456/index.html?acorn=round',
533
+ {
534
+ :method => 'post',
535
+ :script_name => '',
536
+ :input => 'coax=true&some-doors=open',
537
+ }
538
+ )
539
+ req = Rack::Request.new env
540
+ params = bike.instance_eval {
541
+ params_from_request req
542
+ }
543
+ assert_equal(
544
+ {
545
+ :conds => {:qux => '456'},
546
+ :action => nil,
547
+ :sub_action => nil,
548
+ 'acorn' => 'round',
549
+ 'coax' => 'true',
550
+ 'some' => {'doors' => 'open'},
551
+ },
552
+ params,
553
+ 'Bike#params_from_request should attach the params from path_info to the base SD'
554
+ )
555
+
556
+ env = Rack::MockRequest.env_for(
557
+ 'http://example.com/foo/bar/qux=456/index.html?acorn=round',
558
+ {
559
+ :method => 'post',
560
+ :script_name => '',
561
+ :input => 'some-doors=open&some.action-open=submit',
562
+ }
563
+ )
564
+ req = Rack::Request.new env
565
+ params = bike.instance_eval {
566
+ params_from_request req
567
+ }
568
+ assert_equal(
569
+ {
570
+ :conds => {:qux => '456'},
571
+ :action => nil,
572
+ :sub_action => nil,
573
+ 'acorn' => 'round',
574
+ 'some' => {'doors' => 'open', :action => :open},
575
+ },
576
+ params,
577
+ 'Bike#params_from_request should build params from req.path_info and req.params'
578
+ )
579
+
580
+ env = Rack::MockRequest.env_for(
581
+ 'http://example.com/foo/bar/update.html',
582
+ {
583
+ :method => 'post',
584
+ :script_name => '',
585
+ :input => '.action=open_sesami',
586
+ }
587
+ )
588
+ req = Rack::Request.new env
589
+ params = bike.instance_eval {
590
+ params_from_request req
591
+ }
592
+ assert_equal(
593
+ {
594
+ :conds => {},
595
+ :action => :open,
596
+ :sub_action => :sesami,
597
+ },
598
+ params,
599
+ 'Bike#params_from_request should override path_info by :input'
600
+ )
601
+
602
+ env = Rack::MockRequest.env_for(
603
+ 'http://example.com/foo/bar/update.html',
604
+ {
605
+ :method => 'post',
606
+ :script_name => '',
607
+ :input => '.action-open_sesami=submit',
608
+ }
609
+ )
610
+ req = Rack::Request.new env
611
+ params = bike.instance_eval {
612
+ params_from_request req
613
+ }
614
+ assert_equal(
615
+ {
616
+ :conds => {},
617
+ :action => :open,
618
+ :sub_action => :sesami,
619
+ },
620
+ params,
621
+ 'Bike#params_from_request should override path_info by :input'
622
+ )
623
+ end
624
+
625
+ def test_current
626
+ Bike.current[:foo] = 'main foo'
627
+ main_current = Bike.current
628
+
629
+ t = Thread.new {
630
+ assert_not_equal(
631
+ main_current,
632
+ Bike.current,
633
+ 'Bike.current should be unique per a thread'
634
+ )
635
+ assert_not_equal(
636
+ 'main foo',
637
+ Bike.current[:foo],
638
+ 'Bike.current should be unique per a thread'
639
+ )
640
+ Bike.current[:foo] = 'child foo'
641
+ }
642
+ t.join
643
+
644
+ assert_equal(
645
+ 'main foo',
646
+ Bike.current[:foo],
647
+ 'Bike.current should be unique per a thread'
648
+ )
649
+ end
650
+
651
+ def test_login
652
+ Bike.client = nil
653
+ res = Bike.new.send(
654
+ :login,
655
+ Bike::Set::Static::Folder.root.item('foo', 'main'),
656
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}, 'dest_action' => 'update'}
657
+ )
658
+ assert_equal(
659
+ 'test',
660
+ Bike.client,
661
+ 'Bike#login should set Bike.client given a valid pair of user/password'
662
+ )
663
+ assert_match(
664
+ %r{/foo/20100222/123/update.html},
665
+ res[1]['Location'],
666
+ 'Bike#login should return a proper location header'
667
+ )
668
+ end
669
+
670
+ def test_login_default_action
671
+ Bike.client = nil
672
+ res = Bike.new.send(
673
+ :login,
674
+ Bike::Set::Static::Folder.root.item('foo', 'main'),
675
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}}
676
+ )
677
+ assert_match(
678
+ %r{/foo/20100222/123/index.html},
679
+ res[1]['Location'],
680
+ "Bike#login should set 'index' as the default action of a location"
681
+ )
682
+ end
683
+
684
+ def test_login_with_wrong_account
685
+ Bike.client = nil
686
+
687
+ assert_raise(
688
+ Bike::Error::Forbidden,
689
+ 'Bike#login should raise Error::Forbidden given a non-existent user'
690
+ ) {
691
+ Bike.new.send(
692
+ :login,
693
+ Bike::Set::Static::Folder.root.item('foo', 'main'),
694
+ {'id' => 'non-existent', 'pw' => 'test'}
695
+ )
696
+ }
697
+ assert_equal(
698
+ 'nobody',
699
+ Bike.client,
700
+ 'Bike#login should not set Bike.client with a non-existent user'
701
+ )
702
+
703
+ assert_raise(
704
+ Bike::Error::Forbidden,
705
+ 'Bike#login should raise Error::Forbidden given a empty password'
706
+ ) {
707
+ Bike.new.send(
708
+ :login,
709
+ Bike::Set::Static::Folder.root.item('foo', 'main'),
710
+ {'id' => 'test', 'pw' => nil}
711
+ )
712
+ }
713
+ assert_equal(
714
+ 'nobody',
715
+ Bike.client,
716
+ 'Bike#login should not set Bike.client with an empty password'
717
+ )
718
+
719
+ assert_raise(
720
+ Bike::Error::Forbidden,
721
+ 'Bike#login should raise Error::Forbidden given a wrong password'
722
+ ) {
723
+ res = Bike.new.send(
724
+ :login,
725
+ Bike::Set::Static::Folder.root.item('foo', 'main'),
726
+ {
727
+ 'id' => 'test',
728
+ 'pw' => 'wrong',
729
+ :conds => {:id => '20100222_0123'},
730
+ 'dest_action' => 'update'
731
+ }
732
+ )
733
+ }
734
+ assert_equal(
735
+ 'nobody',
736
+ Bike.client,
737
+ 'Bike#login should not set Bike.client with a wrong password'
738
+ )
739
+ end
740
+
741
+ def test_logout
742
+ Bike.client = 'frank'
743
+ res = Bike.new.send(
744
+ :logout,
745
+ Bike::Set::Static::Folder.root.item('foo', 'main'),
746
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}}
747
+ )
748
+ assert_equal(
749
+ 'nobody',
750
+ Bike.client,
751
+ 'Bike#logout should clear Bike.client'
752
+ )
753
+ assert_match(
754
+ %r{/foo/20100222/123/index.html},
755
+ res[1]['Location'],
756
+ 'Bike#logout should return a proper location header'
757
+ )
758
+ end
759
+
760
+ def test_libdir
761
+ assert_match(
762
+ %r{^.*/lib$},
763
+ Bike.libdir,
764
+ 'Bike#libdir should return the lib/ directory where the bike.rb is in'
765
+ )
766
+ end
767
+
768
+ end