innate 2009.04

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/CHANGELOG +2981 -0
  2. data/COPYING +18 -0
  3. data/MANIFEST +127 -0
  4. data/README.md +563 -0
  5. data/Rakefile +35 -0
  6. data/example/app/retro_games.rb +60 -0
  7. data/example/app/todo/layout/default.xhtml +11 -0
  8. data/example/app/todo/spec/todo.rb +63 -0
  9. data/example/app/todo/start.rb +51 -0
  10. data/example/app/todo/view/index.xhtml +39 -0
  11. data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
  12. data/example/app/whywiki_erb/spec/wiki.rb +19 -0
  13. data/example/app/whywiki_erb/start.rb +42 -0
  14. data/example/app/whywiki_erb/view/edit.erb +6 -0
  15. data/example/app/whywiki_erb/view/index.erb +12 -0
  16. data/example/custom_middleware.rb +35 -0
  17. data/example/hello.rb +11 -0
  18. data/example/howto_spec.rb +35 -0
  19. data/example/link.rb +27 -0
  20. data/example/provides.rb +31 -0
  21. data/example/session.rb +38 -0
  22. data/innate.gemspec +29 -0
  23. data/lib/innate.rb +269 -0
  24. data/lib/innate/action.rb +150 -0
  25. data/lib/innate/adapter.rb +76 -0
  26. data/lib/innate/cache.rb +134 -0
  27. data/lib/innate/cache/api.rb +128 -0
  28. data/lib/innate/cache/drb.rb +58 -0
  29. data/lib/innate/cache/file_based.rb +41 -0
  30. data/lib/innate/cache/marshal.rb +17 -0
  31. data/lib/innate/cache/memory.rb +22 -0
  32. data/lib/innate/cache/yaml.rb +17 -0
  33. data/lib/innate/current.rb +37 -0
  34. data/lib/innate/dynamap.rb +96 -0
  35. data/lib/innate/helper.rb +183 -0
  36. data/lib/innate/helper/aspect.rb +124 -0
  37. data/lib/innate/helper/cgi.rb +54 -0
  38. data/lib/innate/helper/flash.rb +36 -0
  39. data/lib/innate/helper/link.rb +94 -0
  40. data/lib/innate/helper/redirect.rb +85 -0
  41. data/lib/innate/helper/render.rb +87 -0
  42. data/lib/innate/helper/send_file.rb +26 -0
  43. data/lib/innate/log.rb +20 -0
  44. data/lib/innate/log/color_formatter.rb +43 -0
  45. data/lib/innate/log/hub.rb +73 -0
  46. data/lib/innate/middleware_compiler.rb +65 -0
  47. data/lib/innate/mock.rb +49 -0
  48. data/lib/innate/node.rb +1025 -0
  49. data/lib/innate/options.rb +37 -0
  50. data/lib/innate/options/dsl.rb +202 -0
  51. data/lib/innate/options/stub.rb +7 -0
  52. data/lib/innate/request.rb +141 -0
  53. data/lib/innate/response.rb +23 -0
  54. data/lib/innate/route.rb +110 -0
  55. data/lib/innate/session.rb +121 -0
  56. data/lib/innate/session/flash.rb +94 -0
  57. data/lib/innate/spec.rb +23 -0
  58. data/lib/innate/state.rb +27 -0
  59. data/lib/innate/state/accessor.rb +130 -0
  60. data/lib/innate/state/fiber.rb +74 -0
  61. data/lib/innate/state/thread.rb +47 -0
  62. data/lib/innate/traited.rb +85 -0
  63. data/lib/innate/trinity.rb +18 -0
  64. data/lib/innate/version.rb +3 -0
  65. data/lib/innate/view.rb +60 -0
  66. data/lib/innate/view/erb.rb +15 -0
  67. data/lib/innate/view/etanni.rb +36 -0
  68. data/lib/innate/view/none.rb +9 -0
  69. data/spec/example/app/retro_games.rb +30 -0
  70. data/spec/example/hello.rb +13 -0
  71. data/spec/example/link.rb +25 -0
  72. data/spec/example/provides.rb +16 -0
  73. data/spec/example/session.rb +22 -0
  74. data/spec/helper.rb +10 -0
  75. data/spec/innate/action/layout.rb +107 -0
  76. data/spec/innate/action/layout/file_layout.xhtml +1 -0
  77. data/spec/innate/cache/common.rb +47 -0
  78. data/spec/innate/cache/marshal.rb +5 -0
  79. data/spec/innate/cache/memory.rb +5 -0
  80. data/spec/innate/cache/yaml.rb +5 -0
  81. data/spec/innate/dynamap.rb +22 -0
  82. data/spec/innate/helper.rb +86 -0
  83. data/spec/innate/helper/aspect.rb +75 -0
  84. data/spec/innate/helper/cgi.rb +37 -0
  85. data/spec/innate/helper/flash.rb +118 -0
  86. data/spec/innate/helper/link.rb +139 -0
  87. data/spec/innate/helper/redirect.rb +160 -0
  88. data/spec/innate/helper/render.rb +133 -0
  89. data/spec/innate/helper/send_file.rb +21 -0
  90. data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
  91. data/spec/innate/helper/view/locals.xhtml +1 -0
  92. data/spec/innate/helper/view/loop.xhtml +4 -0
  93. data/spec/innate/helper/view/num.xhtml +1 -0
  94. data/spec/innate/helper/view/partial.xhtml +1 -0
  95. data/spec/innate/helper/view/recursive.xhtml +7 -0
  96. data/spec/innate/mock.rb +84 -0
  97. data/spec/innate/node/mapping.rb +37 -0
  98. data/spec/innate/node/node.rb +134 -0
  99. data/spec/innate/node/resolve.rb +82 -0
  100. data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
  101. data/spec/innate/node/view/bar.xhtml +1 -0
  102. data/spec/innate/node/view/foo.html.xhtml +1 -0
  103. data/spec/innate/node/view/only_view.xhtml +1 -0
  104. data/spec/innate/node/view/with_layout.xhtml +1 -0
  105. data/spec/innate/node/wrap_action_call.rb +83 -0
  106. data/spec/innate/options.rb +115 -0
  107. data/spec/innate/parameter.rb +154 -0
  108. data/spec/innate/provides.rb +99 -0
  109. data/spec/innate/provides/list.html.xhtml +1 -0
  110. data/spec/innate/provides/list.txt.xhtml +1 -0
  111. data/spec/innate/request.rb +77 -0
  112. data/spec/innate/route.rb +135 -0
  113. data/spec/innate/session.rb +54 -0
  114. data/spec/innate/state/fiber.rb +58 -0
  115. data/spec/innate/state/thread.rb +40 -0
  116. data/spec/innate/traited.rb +55 -0
  117. data/tasks/bacon.rake +66 -0
  118. data/tasks/changelog.rake +18 -0
  119. data/tasks/gem.rake +22 -0
  120. data/tasks/gem_installer.rake +76 -0
  121. data/tasks/grancher.rake +12 -0
  122. data/tasks/install_dependencies.rake +4 -0
  123. data/tasks/manifest.rake +4 -0
  124. data/tasks/rcov.rake +19 -0
  125. data/tasks/release.rake +51 -0
  126. data/tasks/reversion.rake +8 -0
  127. data/tasks/setup.rake +28 -0
  128. metadata +181 -0
@@ -0,0 +1,134 @@
1
+ require 'spec/helper'
2
+
3
+ Innate.options.merge!(:views => 'view', :layouts => 'view')
4
+
5
+ class SpecNode
6
+ Innate.node('/')
7
+
8
+ def foo; end
9
+ def bar; end
10
+ def one(arg) end
11
+ def two(arg1, arg2) end
12
+ def more(*args) end
13
+ def default(arg = nil) end
14
+ end
15
+
16
+ class SpecNodeProvide
17
+ Innate.node('/provide')
18
+
19
+ def foo
20
+ '#{21 * 2}'
21
+ end
22
+
23
+ def bar
24
+ '#{84 / 2}'
25
+ end
26
+ end
27
+
28
+ class SpecNodeProvideTemplate
29
+ Innate.node('/provide_template')
30
+
31
+ map_views '/'
32
+ end
33
+
34
+ class SpecNodeSub < SpecNode
35
+ map '/sub'
36
+
37
+ def bar(arg) end
38
+ end
39
+
40
+ class SpecNodeWithLayout < SpecNodeProvide
41
+ map '/layout'
42
+ layout 'with_layout'
43
+
44
+ map_layouts '/'
45
+ end
46
+
47
+ class SpecNodeWithLayoutView < SpecNodeProvide
48
+ map '/another_layout'
49
+ layout 'another_layout'
50
+
51
+ map_views 'node/another_layout'
52
+ end
53
+
54
+ class SpecNodeWithLayoutMethod < SpecNodeProvide
55
+ map '/layout_method'
56
+ layout 'layout_method'
57
+
58
+ def layout_method
59
+ '<div class="content">#{@content}</div>'
60
+ end
61
+ end
62
+
63
+ class SpecNodeIndex
64
+ Innate.node('/spec_index')
65
+
66
+ def index
67
+ "I have no parameters"
68
+ end
69
+ end
70
+
71
+ class SpecNodeAliasView < SpecNodeProvideTemplate
72
+ map '/alias_view'
73
+ map_views '/'
74
+
75
+ alias_view :aliased, :bar
76
+ end
77
+
78
+ describe 'Innate::Node' do
79
+ behaves_like :mock
80
+
81
+ should 'respond with 404 if no action was found' do
82
+ got = Innate::Mock.get('/does_not_exist')
83
+ got.status.should == 404
84
+ got.body.should == 'No action found at: "/does_not_exist"'
85
+ got['Content-Type'].should == 'text/plain'
86
+ end
87
+
88
+ should 'wrap with layout' do
89
+ got = Innate::Mock.get('/layout/bar')
90
+ got.status.should == 200
91
+ got.body.should == %(<div class="content">42</div>)
92
+ got['Content-Type'].should == 'text/html'
93
+ end
94
+
95
+ should 'find layout with view_root' do
96
+ got = Innate::Mock.get('/another_layout/bar')
97
+ got.status.should == 200
98
+ got.body.should == %(<div class="content">\n 42\n</div>)
99
+ got['Content-Type'].should == 'text/html'
100
+ end
101
+
102
+ should 'find layout from method' do
103
+ got = Innate::Mock.get('/layout_method/bar')
104
+ got.status.should == 200
105
+ got.body.should == %(<div class="content">42</div>)
106
+ got['Content-Type'].should == 'text/html'
107
+ end
108
+
109
+ should 'not get an action with wrong parameters' do
110
+ got = Innate::Mock.get('/spec_index/bar')
111
+ got.status.should == 404
112
+ got.body.should == 'No action found at: "/bar"'
113
+ end
114
+
115
+ should 'get an action view if there is no method' do
116
+ got = Innate::Mock.get('/provide_template/only_view')
117
+ got.status.should == 200
118
+ got.body.strip.should == "Only template"
119
+ got['Content-Type'].should == 'text/html'
120
+ end
121
+
122
+ should 'not get an action view with params if there is no method' do
123
+ got = Innate::Mock.get('/provide_template/only_view/param')
124
+ got.status.should == 404
125
+ got.body.strip.should == 'No action found at: "/only_view/param"'
126
+ end
127
+
128
+ should 'use alias_view' do
129
+ got = get('/alias_view/aliased')
130
+ got.status.should == 200
131
+ got.body.strip.should == "<h1>Hello, World!</h1>"
132
+ got['Content-Type'].should == 'text/html'
133
+ end
134
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec/helper'
2
+
3
+ class SpecNodeResolve
4
+ Innate.node('/')
5
+
6
+ def foo; end
7
+ def bar; end
8
+ def one(arg) end
9
+ def two(arg1, arg2) end
10
+ def more(*args) end
11
+ def default(arg = nil) end
12
+ end
13
+
14
+ class SpecNodeResolveSub < SpecNodeResolve
15
+ map '/sub'
16
+
17
+ def bar(arg) end
18
+ end
19
+
20
+ class SpecNodeResolveIndex
21
+ Innate.node('/arg')
22
+
23
+ def index(arg) end
24
+ end
25
+
26
+ describe 'Node.resolve' do
27
+ def compare(url, hash)
28
+ result = SpecNodeResolve.resolve(url)
29
+ result.should.not.be.nil
30
+ hash.each do |key, value|
31
+ result[key.to_s].should == value
32
+ end
33
+ end
34
+
35
+ should 'resolve actions with methods' do
36
+ SpecNodeResolve.resolve('/').should.be.nil
37
+ SpecNodeResolve.resolve('/index').should.be.nil
38
+
39
+ compare '/foo', :method => 'foo', :params => []
40
+ SpecNodeResolve.resolve('/foo/one/two').should.be.nil
41
+
42
+ compare '/bar', :method => 'bar', :params => []
43
+ SpecNodeResolve.resolve('/bar/one').should.be.nil
44
+
45
+ SpecNodeResolve.resolve('/one').should.be.nil
46
+ compare '/one/1', :method => 'one', :params => ['1']
47
+ SpecNodeResolve.resolve('/one/1/2').should.be.nil
48
+ SpecNodeResolve.resolve('/one/1/2/3').should.be.nil
49
+
50
+ SpecNodeResolve.resolve('/two').should.be.nil
51
+ SpecNodeResolve.resolve('/two/1').should.be.nil
52
+ compare '/two/1/2', :method => 'two', :params => %w[1 2]
53
+ SpecNodeResolve.resolve('/two/1/2/3').should.be.nil
54
+
55
+ compare '/more', :method => 'more', :params => []
56
+ compare '/more/1', :method => 'more', :params => %w[1]
57
+ compare '/more/1/2', :method => 'more', :params => %w[1 2]
58
+ compare '/more/1/2/3', :method => 'more', :params => %w[1 2 3]
59
+
60
+ compare '/default', :method => 'default', :params => []
61
+ compare '/default/1', :method => 'default', :params => %w[1]
62
+
63
+ # NOTE: these are actually bound to fail when called, but we cannot
64
+ # introspect enough to anticipate this failure
65
+ compare '/default/1/2', :method => 'default', :params => %w[1 2]
66
+ compare '/default/1/2/3', :method => 'default', :params => %w[1 2 3]
67
+ end
68
+
69
+ should 'inherit action methods from superclasses' do
70
+ SpecNodeResolveSub.resolve('/foo').should.not.be.nil
71
+ SpecNodeResolveSub.resolve('/foo/one/two').should.be.nil
72
+ end
73
+
74
+ should 'select correct method from subclasses' do
75
+ SpecNodeResolveSub.resolve('/bar/one').should.not.be.nil
76
+ SpecNodeResolveSub.resolve('/bar').should.be.nil
77
+ end
78
+
79
+ it "doesn't select index as action with index parameter if arity is 1" do
80
+ SpecNodeResolveIndex.resolve('/index').should.be.nil
81
+ end
82
+ end
@@ -0,0 +1,3 @@
1
+ <div class="content">
2
+ #{@content}
3
+ </div>
@@ -0,0 +1 @@
1
+ <h1>Hello, World!</h1>
@@ -0,0 +1 @@
1
+ <?r 10.times do |n| ?>#{n}<?r end ?>
@@ -0,0 +1 @@
1
+ Only template
@@ -0,0 +1 @@
1
+ <div class="content">#{@content}</div>
@@ -0,0 +1,83 @@
1
+ require 'spec/helper'
2
+
3
+ SPEC_WRAP_LOG = []
4
+
5
+ class SpecWrapActionCall
6
+ Innate.node '/'
7
+
8
+ def first; end
9
+ def second; end
10
+ def third; end
11
+
12
+ private
13
+
14
+ def wrap_before(action)
15
+ SPEC_WRAP_LOG << [:before, action.name]
16
+ yield
17
+ end
18
+
19
+ def wrap_after(action)
20
+ SPEC_WRAP_LOG << [:after, action.name]
21
+ yield
22
+ end
23
+ end
24
+
25
+ class SpecWrapActionCallStop
26
+ Innate.node '/stop'
27
+
28
+ def index; 'Hello'; end
29
+
30
+ def wrap_pass(action)
31
+ yield
32
+ end
33
+
34
+ def wrap_stop(action)
35
+ 'No Hello'
36
+ end
37
+ end
38
+
39
+
40
+ describe 'Node#wrap_action_call' do
41
+ behaves_like :mock
42
+
43
+ it 'executes our wrapper' do
44
+ SPEC_WRAP_LOG.clear
45
+ SpecWrapActionCall.add_action_wrapper(2.0, :wrap_after)
46
+
47
+ get('/first')
48
+ SPEC_WRAP_LOG.should == [[:after, 'first']]
49
+
50
+ get('/second')
51
+ SPEC_WRAP_LOG.should == [[:after, 'first'], [:after, 'second']]
52
+
53
+ get('/third')
54
+ SPEC_WRAP_LOG.should == [[:after, 'first'], [:after, 'second'], [:after, 'third']]
55
+ end
56
+
57
+ it 'executes wrappers in correct order' do
58
+ SPEC_WRAP_LOG.clear
59
+ SpecWrapActionCall.add_action_wrapper(1.0, :wrap_before)
60
+
61
+ get('/first')
62
+ SPEC_WRAP_LOG.should == [[:before, 'first'], [:after, 'first']]
63
+
64
+ get('/second')
65
+ SPEC_WRAP_LOG.should == [
66
+ [:before, 'first'], [:after, 'first'],
67
+ [:before, 'second'], [:after, 'second']]
68
+
69
+ get('/third')
70
+ SPEC_WRAP_LOG.should == [
71
+ [:before, 'first'], [:after, 'first'],
72
+ [:before, 'second'], [:after, 'second'],
73
+ [:before, 'third'], [:after, 'third']]
74
+ end
75
+
76
+ it 'stops in the chain when not yielded' do
77
+ SpecWrapActionCallStop.add_action_wrapper(1.0, :wrap_pass)
78
+ get('/stop').body.should == 'Hello'
79
+
80
+ SpecWrapActionCallStop.add_action_wrapper(2.0, :wrap_stop)
81
+ get('/stop').body.should == 'No Hello'
82
+ end
83
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec/helper'
2
+
3
+ Options = Innate::Options
4
+
5
+ describe Options do
6
+ @options = Innate::Options.new(:spec)
7
+
8
+ should 'create option' do
9
+ @options.o('my name', :name, 'manveru')
10
+ @options.name.should == 'manveru'
11
+ end
12
+
13
+ should 'create options with meta hash' do
14
+ @options.o('the port', :port, 7000, :cli => '-p')
15
+ @options.port.should == 7000
16
+ end
17
+
18
+ should 'get complete hash via #get' do
19
+ @options.get(:port)[:cli].should == '-p'
20
+ @options.get(:port)[:doc].should == 'the port'
21
+ end
22
+
23
+ should 'get value via []' do
24
+ @options[:port].should == 7000
25
+ end
26
+
27
+ should 'create scope' do
28
+ @options.sub(:deep)
29
+ @options.deep.should.not.be.nil
30
+ end
31
+
32
+ should 'create option in scope' do
33
+ @options.deep.o('the browser', :browser, :firefox)
34
+ @options.deep.browser.should == :firefox
35
+ end
36
+
37
+ should 'append to scope via dsl' do
38
+ @options.sub(:deep).o('hi mom', :greeting, :mom)
39
+ @options.deep.greeting.should == :mom
40
+ end
41
+
42
+ should 'sub in subscope' do
43
+ @options.sub(:deep).sub(:down).o('deep down', :me, :too)
44
+ @options.deep.down.me.should == :too
45
+ end
46
+
47
+ should 'get sub-sub option' do
48
+ @options.get(:deep, :down, :me).
49
+ should == {:value => :too, :doc => 'deep down', :trigger=> nil}
50
+ end
51
+
52
+ should 'respond with nil on getting missing option' do
53
+ @options.get(:deep, :down, :you).should.be.nil
54
+ end
55
+
56
+ should 'search in higher scope if key not found' do
57
+ @options.deep.port.should == 7000
58
+ end
59
+
60
+ should '#set_value to set a nested value directly' do
61
+ @options.set_value([:deep, :down, :me], 'me deep down')
62
+ @options.deep.down.me.should == 'me deep down'
63
+ end
64
+
65
+ should 'merge! existing options with other Enumerable' do
66
+ @options.merge!(:port => 4000, :name => 'feagliir')
67
+ @options.port.should == 4000
68
+ @options.name.should == 'feagliir'
69
+ end
70
+
71
+ should 'iterate via #each_pair' do
72
+ given_keys = [:deep, :name, :port]
73
+ given_values = [@options[:deep], @options[:name], @options[:port]]
74
+
75
+ @options.each_pair do |key, value|
76
+ given_keys.delete(key)
77
+ given_values.delete(value)
78
+ end
79
+
80
+ given_keys.should.be.empty
81
+ given_values.should.be.empty
82
+ end
83
+
84
+ should 'iterate via #each_option' do
85
+ given_keys = [:deep, :name, :port]
86
+ given_values = [@options.get(:deep), @options.get(:name), @options.get(:port)]
87
+
88
+ @options.each_option do |key, option|
89
+ given_keys.delete(key)
90
+ given_values.delete(option)
91
+ end
92
+
93
+ given_keys.should.be.empty
94
+ given_values.should.be.empty
95
+ end
96
+
97
+ should "raise when trying to assign to key that doesn't exist" do
98
+ lambda{ @options[:foo] = :bar }.should.raise(ArgumentError)
99
+ end
100
+
101
+ should 'pretty_print' do
102
+ require 'pp'
103
+ p = PP.new
104
+ @options.pretty_print(p)
105
+ p.output.should =~ /:value=>:mom/
106
+ end
107
+
108
+ should 'trigger block when option is changed' do
109
+ set = nil
110
+ @options.trigger(:port){|value| set = value }
111
+ set.should.be.nil
112
+ @options.port = 300
113
+ set.should == 300
114
+ end
115
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec/helper'
2
+
3
+ class SpecParameter
4
+ include Innate::Node
5
+ map '/'
6
+
7
+ def index
8
+ "index"
9
+ end
10
+
11
+ def no_params
12
+ "no params"
13
+ end
14
+
15
+ def single_param param
16
+ "single param (#{param})"
17
+ end
18
+
19
+ def double_param param1, param2
20
+ "double param (#{param1}, #{param2})"
21
+ end
22
+
23
+ def all_params *params
24
+ "all params (#{params.join(', ')})"
25
+ end
26
+
27
+ def at_least_one param, *params
28
+ "at least one (#{param}, #{params.join(', ')})"
29
+ end
30
+
31
+ def one_default param = 'default'
32
+ "one_default (#{param})"
33
+ end
34
+
35
+ def cat1__cat11
36
+ 'cat1: cat11'
37
+ end
38
+
39
+ def cat1__cat11__cat111
40
+ 'cat1: cat11: cat111'
41
+ end
42
+ end
43
+
44
+ class SpecParameter2
45
+ include Innate::Node
46
+ map '/jo'
47
+
48
+ def add(one, two = nil, three = nil)
49
+ "#{one}:#{two}:#{three}"
50
+ end
51
+
52
+ def keys
53
+ request.params.keys.inspect
54
+ end
55
+ end
56
+
57
+ class SpecParameter3
58
+ include Innate::Node
59
+ map '/ma'
60
+
61
+ def index(*args)
62
+ request.params['foo'].to_s.dump
63
+ end
64
+ end
65
+
66
+ describe "Simple Parameters" do
67
+ def handle(*url)
68
+ response = Innate::Mock.get(*url)
69
+ response.status.should == 200
70
+ response.body
71
+ end
72
+
73
+ it "Should respond to no parameters given" do
74
+ handle('/no_params').should == "no params"
75
+ end
76
+
77
+ it "Should respond to only / with the index" do
78
+ handle('/').should == "index"
79
+ end
80
+
81
+ it "call /bar though index doesn't take params" do
82
+ lambda{ handle('/bar') }.should.raise
83
+ end
84
+
85
+ it "action that takes a single param" do
86
+ handle('/single_param/foo').should == "single param (foo)"
87
+ end
88
+
89
+ it "action that takes two params" do
90
+ handle('/double_param/foo/bar').should == "double param (foo, bar)"
91
+ end
92
+
93
+ it "action that takes two params but we give only one" do
94
+ lambda{ handle('/double_param/foo') }.should.raise
95
+ end
96
+
97
+ it "action that takes all params" do
98
+ handle('/all_params/foo/bar/foobar').should == "all params (foo, bar, foobar)"
99
+ end
100
+
101
+ it "action that takes all params but needs at least one" do
102
+ handle('/at_least_one/foo/bar/foobar').should == "at least one (foo, bar, foobar)"
103
+ end
104
+
105
+ it "action that takes all params but needs at least one (not given here)" do
106
+ lambda{ handle('/at_least_one') }.
107
+ should.raise(ArgumentError)
108
+ end
109
+
110
+ it "one default" do
111
+ handle('/one_default').should == "one_default (default)"
112
+ end
113
+
114
+ it "one default" do
115
+ handle('/one_default/my_default').should == "one_default (my_default)"
116
+ end
117
+
118
+ it "double underscore lookup" do
119
+ handle('/cat1/cat11').should == 'cat1: cat11'
120
+ end
121
+
122
+ it "double double underscore lookup" do
123
+ handle('/cat1/cat11/cat111').should == 'cat1: cat11: cat111'
124
+ end
125
+
126
+
127
+ it "jo/add should raise with 0 parameters" do
128
+ lambda{ handle('/jo/add') }.
129
+ should.raise(ArgumentError)
130
+ end
131
+
132
+ it "add should raise with 4 parameters" do
133
+ lambda{ handle('/jo/add/1/2/3/4') }.
134
+ should.raise(ArgumentError)
135
+ end
136
+
137
+ it "add should not raise with 1-3 parameters" do
138
+ handle('/jo/add/1').should == '1::'
139
+ handle('/jo/add/1/2').should == '1:2:'
140
+ handle('/jo/add/1/2/3').should == '1:2:3'
141
+ end
142
+
143
+ it 'params should have no content without params' do
144
+ handle('/ma').should == '""'
145
+ end
146
+
147
+ it 'should have a parameter via QUERY_PARAMS' do
148
+ handle('/ma?foo=bar').should == '"bar"'
149
+ end
150
+
151
+ it 'should handle valueless params' do
152
+ handle('/jo/keys?foo').should == '["foo"]'
153
+ end
154
+ end