bike 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,9 +3,11 @@
3
3
  Bike is the easiest web application framework ever.
4
4
  You can make various apps such like blog, forum, contact form by putting single (or several) HTML file with a bit of special markups. The view rules. There is no model definition, no server restart, and no coding at all.
5
5
 
6
- == Wiki
6
+ == Sites
7
7
 
8
- http://github.com/afunai/bike/wiki
8
+ * Home: http://github.com/afunai/bike
9
+ * Docs: http://github.com/afunai/bike/wiki
10
+ * Demo: http://runo.heroku.com/examples/index.html
9
11
 
10
12
  == Features
11
13
 
@@ -16,7 +18,7 @@ http://github.com/afunai/bike/wiki
16
18
  * You can make nested apps inside an app (e.g. blog comments inside a blog entry).
17
19
  * Authentication / Authorization / User admin are built in by default.
18
20
  * Storage can be plain YAML files (default), or any RDB via Sequel.
19
- * Bike itself is a Rack application.
21
+ * Bike can be deployed anywhere as it is a simple Rack application.
20
22
 
21
23
  == Quick Start
22
24
 
@@ -28,9 +30,6 @@ Open a command line terminal. Type:
28
30
 
29
31
  gem install bike
30
32
 
31
- If you want to make thumbnails for submitted images, you have to install QuickMagick as well.
32
- http://rubyforge.org/projects/quickmagick/
33
-
34
33
  === Step 2 - Initialize a Bike Directory
35
34
 
36
35
  In a command line terminal, go to an empty directory where you want to build Bike projects.
@@ -46,7 +45,6 @@ This will create a "bike" directory, which includes:
46
45
 
47
46
  === Step 3 - Start a Test Server
48
47
 
49
- In the terminal, change to the newly created "bike" directory.
50
48
  Type:
51
49
 
52
50
  bike run
@@ -55,24 +53,20 @@ Type:
55
53
 
56
54
  Now open this URL with your browser.
57
55
 
58
- http://localhost:9292/
56
+ http://localhost:9292/
59
57
 
60
58
  You will see the default homepage of Bike.
61
- There is some links to examples such like Blog, Contact Form, Forum, etc. Just see what can be done by plain HTML files.
59
+ There is some links to examples such like Blog, Contact Form, Forum, etc. See what can be done by plain HTML files.
62
60
 
63
61
  === Step 5 - Create Your Own App
64
62
 
65
- Let's call our app "fab".
66
- It is a web-based forum where logged in users can submit their own articles, and everybody can read them.
67
- We put links to signup / login at bottom of the app.
68
-
69
63
  Create a new directory under bike/skin/:
70
64
 
71
- mkdir skin/fab/
65
+ mkdir skin/myapp/
72
66
 
73
67
  Then create a new HTML file with your favorite editor:
74
68
 
75
- edit skin/fab/index.html
69
+ edit skin/myapp/index.html
76
70
 
77
71
  The content is: (You can just copy & paste, of course)
78
72
 
@@ -102,12 +96,9 @@ The content is: (You can just copy & paste, of course)
102
96
 
103
97
  === Step 6 - That's it!
104
98
 
105
- See the URL:
106
-
107
- http://localhost:9292/fab/
99
+ http://localhost:9292/myapp/index.html
108
100
 
109
- You have just created your first app. Open a bottle of your favorite drink and make yourself comfortable.
110
- When you need more complicated tricks, HTMLs under skin/examples/ will be your help. Also, you should check out the wiki: http://github.com/afunai/bike/wiki
101
+ You have just created your first app. Log in with root/root to try it out. Have a nice ride!
111
102
 
112
103
  == Note on Patches/Pull Requests
113
104
 
@@ -37,7 +37,7 @@ _html
37
37
  def _g_submit_preview_delete(arg)
38
38
  if (
39
39
  permit_get?(arg.merge(:action => :delete)) &&
40
- collect_item(arg[:conds]).find {|item| item[:id] !~ Bike::REX::ID_NEW } &&
40
+ collect_item(arg[:conds]).any? {|item| item[:id] !~ Bike::REX::ID_NEW } &&
41
41
  arg[:orig_action] != :preview
42
42
  )
43
43
  <<_html
@@ -92,17 +92,13 @@ module Bike::Set
92
92
  def _get(arg)
93
93
  if respond_to?("_g_#{arg[:action]}", true)
94
94
  _get_by_method arg
95
- elsif summary?(arg) && action_tmpl = my[:tmpl][:summary]
96
- _get_by_tmpl(arg, action_tmpl)
97
- elsif action_tmpl = my[:tmpl][arg[:sub_action]] || my[:tmpl][arg[:action]]
98
- _get_by_tmpl(arg, action_tmpl)
99
95
  else
100
- _get_by_tmpl(arg, my[:tmpl][:index])
96
+ _get_by_tmpl(arg, action_tmpl(arg))
101
97
  end
102
98
  end
103
99
 
104
100
  def _get_by_tmpl(arg, tmpl = '')
105
- tmpl.gsub(/@\((.+?)\)/) {
101
+ tmpl.to_s.gsub(/@\((.+?)\)/) {
106
102
  tag = $&
107
103
  steps = $1.split '-'
108
104
  id = steps.pop
@@ -169,6 +165,18 @@ module Bike::Set
169
165
  }
170
166
  end
171
167
 
168
+ def action_tmpl(arg)
169
+ if summary?(arg) && my[:tmpl][:summary]
170
+ my[:tmpl][:summary]
171
+ elsif action_tmpl = my[:tmpl][arg[:sub_action]] || my[:tmpl][arg[:action]]
172
+ action_tmpl
173
+ elsif [:create, :update, :delete, :login].include? arg[:action]
174
+ my[:tmpl][:form] || my[:tmpl][:index]
175
+ else
176
+ my[:tmpl][:read] || my[:tmpl][:index]
177
+ end
178
+ end
179
+
172
180
  def summary?(arg)
173
181
  [:read, nil].include?(arg[:action]) && !arg[:sub_action]
174
182
  end
@@ -10,44 +10,25 @@ class Bike::Set::Static::Folder < Bike::Set::Static
10
10
  end
11
11
 
12
12
  def initialize(meta = {})
13
- meta[:dir] = meta[:parent] ? ::File.join(meta[:parent][:dir], meta[:id]) : meta[:id]
14
- meta[:html] = load_html(meta[:dir], meta[:parent])
15
- super
16
-
17
- ::Dir.glob(::File.join(Bike['skin_dir'], my[:html_dir].to_s, '*.html')).each {|f|
18
- action = ::File.basename(f, '.*').intern
19
- merge_tmpl(@meta, Bike::Parser.parse_html(::File.read(f), action)) if action != :index
20
- }
21
- ::Dir.glob(::File.join(Bike['skin_dir'], my[:html_dir].to_s, '*.xml')).each {|f|
22
- action = ::File.basename(f, '.*').intern
23
- merge_tmpl(@meta, Bike::Parser.parse_xml(::File.read(f), action)) if action != :index
24
- }
13
+ @meta = meta
14
+ @meta.merge! load_html
15
+ @meta.merge! load_yaml
25
16
 
26
17
  @meta[:tmpl].values.each {|tmpl|
27
- tmpl.sub!(/<head>([\s\n]*)/i) {
28
- "#{$&}<base href=\"@(href)\" />#{$1}"
29
- }
30
- } if @meta[:tmpl]
18
+ tmpl.sub!(/<head>([\s\n]*)/i) { "#{$&}<base href=\"@(href)\" />#{$1}" }
19
+ }
31
20
 
32
- @meta.merge! load_yaml(my[:dir], my[:parent])
21
+ @item_object = {}
33
22
  end
34
23
 
35
24
  def meta_dir
36
- @meta[:dir]
37
- end
38
-
39
- def meta_html_dir
40
- if ::File.readable? ::File.join(Bike['skin_dir'], my[:dir], 'index.html')
41
- my[:dir]
42
- elsif my[:parent]
43
- my[:parent][:html_dir]
44
- end
25
+ my[:parent] ? ::File.join(my[:parent][:dir], my[:id]) : my[:id]
45
26
  end
46
27
 
47
28
  private
48
29
 
49
30
  def _get(arg)
50
- if arg['main'] && action_tmpl = my[:tmpl][arg['main'][:action]]
31
+ if arg['main'] && action_tmpl = action_tmpl(arg['main'])
51
32
  _get_by_tmpl(arg, action_tmpl)
52
33
  else
53
34
  super
@@ -66,17 +47,42 @@ class Bike::Set::Static::Folder < Bike::Set::Static
66
47
  super
67
48
  end
68
49
 
69
- def load_html(dir, parent, action = :index)
70
- html_file = ::File.join Bike['skin_dir'], dir, "#{action}.html"
71
- if ::File.exists? html_file
72
- ::File.read html_file
73
- elsif parent
74
- parent[:html]
50
+ def load_html
51
+ files = ::Dir[::File.join Bike['skin_dir'], my[:dir], '*.{html,xml}'].sort
52
+
53
+ if model_file = files.find {|f| ['form', 'index'].include? ::File.basename(f, '.*') }
54
+ html = ::File.read model_file
55
+ action = ::File.basename(model_file, '.*').intern
56
+ meta = {:html => html}
57
+ meta.merge! Bike::Parser.parse_html(html, action, (::File.extname(model_file) == '.xml'))
58
+
59
+ files.delete model_file
60
+ files.each {|f|
61
+ html = ::File.read f
62
+ action = ::File.basename(f, '.*').intern
63
+ merge_tmpl(
64
+ meta,
65
+ Bike::Parser.parse_html(html, action, (::File.extname(f) == '.xml'))
66
+ )
67
+ }
68
+
69
+ meta
70
+ elsif my[:parent]
71
+ {
72
+ :label => my[:parent][:label],
73
+ :item => my[:parent][:item],
74
+ :tmpl => my[:parent][:tmpl],
75
+ }
76
+ else
77
+ {
78
+ :item => {},
79
+ :tmpl => {},
80
+ }
75
81
  end
76
82
  end
77
83
 
78
- def load_yaml(dir, parent)
79
- yaml_file = ::File.join(Bike['skin_dir'], dir, 'index.yaml')
84
+ def load_yaml
85
+ yaml_file = ::File.join(Bike['skin_dir'], my[:dir], 'index.yaml')
80
86
  meta = ::File.exists?(yaml_file) ? YAML.load_file(yaml_file) : {}
81
87
  meta.keys.inject({}) {|m, k|
82
88
  m[k.intern] = meta[k]
@@ -0,0 +1 @@
1
+ <html><ul class="app-boo"></ul></html>
@@ -0,0 +1 @@
1
+ <xml class="dummy">boo</xml>
@@ -0,0 +1 @@
1
+ <form>
@@ -0,0 +1 @@
1
+ <index>
@@ -0,0 +1 @@
1
+ <index>
@@ -0,0 +1 @@
1
+ <read>
@@ -39,22 +39,6 @@ class TC_Set_Folder < Test::Unit::TestCase
39
39
  )
40
40
  end
41
41
 
42
- def test_meta_html_dir
43
- folder = Bike::Set::Static::Folder.root.item('foo')
44
- assert_equal(
45
- '/foo',
46
- folder[:html_dir],
47
- "Folder#meta_html_dir should return meta_dir if there is 'index.html'"
48
- )
49
-
50
- folder = Bike::Set::Static::Folder.root.item('foo', 'bar')
51
- assert_equal(
52
- '/foo',
53
- folder[:html_dir],
54
- "Folder#meta_html_dir should return parent[:html_dir] if there is no 'index.html' in [:dir]"
55
- )
56
- end
57
-
58
42
  def test_meta_href
59
43
  folder = Bike::Set::Static::Folder.root.item('t_summary')
60
44
 
@@ -73,6 +57,29 @@ class TC_Set_Folder < Test::Unit::TestCase
73
57
  )
74
58
  end
75
59
 
60
+ def test_load_html
61
+ folder = Bike::Set::Static::Folder.root.item('foo', 'boo')
62
+ assert_equal(
63
+ 'boo',
64
+ folder[:item]['main'][:workflow],
65
+ 'Folder#load_html should load [:item] from form.html if available'
66
+ )
67
+ assert_equal(
68
+ "<html>$(main.message)$(main)</html>\n",
69
+ folder[:tmpl][:form],
70
+ 'Folder#load_html should load [:tmpl][:form] from form.html'
71
+ )
72
+ assert_nil(
73
+ folder[:tmpl][:index],
74
+ 'Folder#load_html should leave [:tmpl][:index] empty if there is no index.html'
75
+ )
76
+ assert_equal(
77
+ "<xml>boo</xml>\n",
78
+ folder[:tmpl][:rss],
79
+ 'Folder#load_html should load [:tmpl] from *.xml if available'
80
+ )
81
+ end
82
+
76
83
  def test_load_yaml
77
84
  folder = Bike::Set::Static::Folder.new(:id => 'foo', :parent => nil)
78
85
  assert_equal(
@@ -412,6 +419,42 @@ _html
412
419
  )
413
420
  end
414
421
 
422
+ def test_get_by_tmpl_with_form_action
423
+ folder = Bike::Set::Static::Folder.root.item('t_tmpl_form')
424
+
425
+ [:create, :update, :delete, :login].each {|action|
426
+ assert_equal(
427
+ "<form>\n",
428
+ folder.get('main' => {:action => action}),
429
+ "Folder#_get_by_tmpl should use tmpl[:form] if arg['main'][:action] is :#{action}"
430
+ )
431
+ }
432
+
433
+ assert_equal(
434
+ "<index>\n",
435
+ folder.get('main' => {:action => :read}),
436
+ 'Folder#_get_by_tmpl should not use tmpl[:form] for read actions'
437
+ )
438
+ end
439
+
440
+ def test_get_by_tmpl_with_read_action
441
+ folder = Bike::Set::Static::Folder.root.item('t_tmpl_read')
442
+
443
+ [:read, :summary, :foo, nil].each {|action|
444
+ assert_equal(
445
+ "<read>\n",
446
+ folder.get('main' => {:action => action}),
447
+ "Folder#_get_by_tmpl should use tmpl[:read] if arg['main'][:action] is :#{action}"
448
+ )
449
+ }
450
+
451
+ assert_equal(
452
+ "<index>\n",
453
+ folder.get('main' => {:action => :create}),
454
+ 'Folder#_get_by_tmpl should not use tmpl[:read] for form actions'
455
+ )
456
+ end
457
+
415
458
  def test_g_login
416
459
  folder = Bike::Set::Static::Folder.root.item('t_contact')
417
460
 
@@ -242,7 +242,7 @@ _html
242
242
  )
243
243
  end
244
244
 
245
- def test_get_tmpl_non_existing_meta
245
+ def test_get_by_tmpl_non_existing_meta
246
246
  ss = Bike::Set::Static.new(:html => '')
247
247
  assert_equal(
248
248
  'foo @(foo-bar) foo',
@@ -256,7 +256,7 @@ _html
256
256
  )
257
257
  end
258
258
 
259
- def test_get_tmpl_non_existing_item
259
+ def test_get_by_tmpl_non_existing_item
260
260
  ss = Bike::Set::Static.new(:html => '')
261
261
  assert_equal(
262
262
  'foo $(foo) foo',
@@ -265,6 +265,72 @@ _html
265
265
  )
266
266
  end
267
267
 
268
+ def test_get_by_tmpl_with_form_action
269
+ ss = Bike::Set::Static.new(:html => 'index')
270
+ ss[:tmpl][:form] = 'form'
271
+ class << ss
272
+ undef_method :_g_login # test purpose only
273
+ end
274
+
275
+ [:create, :update, :delete, :login].each {|action|
276
+ assert_equal(
277
+ 'form',
278
+ ss.get(:action => action),
279
+ "Set#_get_by_tmpl should use tmpl[:form] for :#{action}"
280
+ )
281
+ }
282
+
283
+ ss[:tmpl][:read] = nil
284
+ assert_equal(
285
+ 'index',
286
+ ss.get(:action => :read),
287
+ 'Set#_get_by_tmpl should not use tmpl[:form] for read actions'
288
+ )
289
+ ss[:tmpl][:read] = 'read'
290
+ assert_equal(
291
+ 'read',
292
+ ss.get(:action => :read),
293
+ 'Set#_get_by_tmpl should not use tmpl[:form] for read actions'
294
+ )
295
+ end
296
+
297
+ def test_get_by_tmpl_without_index_action
298
+ ss = Bike::Set::Static.new(:html => '')
299
+ ss[:tmpl] = {:form => 'form'}
300
+
301
+ assert_equal(
302
+ '',
303
+ ss.get(:action => :read),
304
+ 'Set#_get_by_tmpl should not use tmpl[:form] for :read'
305
+ )
306
+ end
307
+
308
+ def test_get_by_tmpl_with_read_action
309
+ ss = Bike::Set::Static.new(:html => 'index')
310
+ ss[:tmpl][:read] = 'read'
311
+
312
+ [:read, :summary, :foo, nil].each {|action|
313
+ assert_equal(
314
+ 'read',
315
+ ss.get(:action => action),
316
+ "Set#_get_by_tmpl should use tmpl[:read] when available"
317
+ )
318
+ }
319
+
320
+ ss[:tmpl][:form] = nil
321
+ assert_equal(
322
+ 'index',
323
+ ss.get(:action => :create),
324
+ 'Set#_get_by_tmpl should not use tmpl[:read] for form actions'
325
+ )
326
+ ss[:tmpl][:form] = 'form'
327
+ assert_equal(
328
+ 'form',
329
+ ss.get(:action => :create),
330
+ 'Set#_get_by_tmpl should not use tmpl[:read] for form actions'
331
+ )
332
+ end
333
+
268
334
  def test_recursive_tmpl
269
335
  ss = Bike::Set::Static.new(:html => <<'_html')
270
336
  <li>$()</li>
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 2
9
- version: 0.2.2
8
+ - 3
9
+ version: 0.2.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Akira FUNAI
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-12 00:00:00 +09:00
17
+ date: 2010-11-02 00:00:00 +09:00
18
18
  default_executable: bike
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -244,6 +244,8 @@ files:
244
244
  - t/skin/foo/bar/20091120_0001.yaml
245
245
  - t/skin/foo/bar/index.yaml
246
246
  - t/skin/foo/baz/css/baz.css
247
+ - t/skin/foo/boo/form.html
248
+ - t/skin/foo/boo/rss.xml
247
249
  - t/skin/foo/css/foo.css
248
250
  - t/skin/foo/index.html
249
251
  - t/skin/foo/index.yaml
@@ -264,6 +266,10 @@ files:
264
266
  - t/skin/t_summary/create.html
265
267
  - t/skin/t_summary/index.html
266
268
  - t/skin/t_summary/summary.html
269
+ - t/skin/t_tmpl_form/form.html
270
+ - t/skin/t_tmpl_form/index.html
271
+ - t/skin/t_tmpl_read/index.html
272
+ - t/skin/t_tmpl_read/read.html
267
273
  - t/t.rb
268
274
  - t/test_bike.rb
269
275
  - t/test_call.rb