bike 0.2.2 → 0.2.3

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.
@@ -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