roda-cj 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ class Roda
2
+ module RodaPlugins
3
+ # The symbol_views plugin allows matching blocks to return
4
+ # symbols, and consider those symbols as views to use for the
5
+ # response body. So you can take code like:
6
+ #
7
+ # r.root do
8
+ # view :index
9
+ # end
10
+ # r.is "foo" do
11
+ # view :foo
12
+ # end
13
+ #
14
+ # and DRY it up:
15
+ #
16
+ # r.root do
17
+ # :index
18
+ # end
19
+ # r.is "foo" do
20
+ # :foo
21
+ # end
22
+ module SymbolViews
23
+ module RequestMethods
24
+ private
25
+
26
+ # If the block result is a symbol, consider the symbol a
27
+ # template name and use the template view as the body.
28
+ def block_result_body(result)
29
+ if result.is_a?(Symbol)
30
+ scope.view(result)
31
+ else
32
+ super
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ register_plugin(:symbol_views, SymbolViews)
39
+ end
40
+ end
@@ -0,0 +1,53 @@
1
+ class Roda
2
+ module RodaPlugins
3
+ # The view_subdirs plugin is designed for sites that have
4
+ # outgrown a flat view directory and use subdirectories
5
+ # for views. It allows you to set the view directory to
6
+ # use, and template names that do not contain a slash will
7
+ # automatically use that view subdirectory. Example:
8
+ #
9
+ # plugin :render
10
+ # plugin :view_subdirs
11
+ #
12
+ # route do |r|
13
+ # r.on "users" do
14
+ # set_view_subdir 'users'
15
+ #
16
+ # r.get :id do
17
+ # view 'profile' # uses ./views/users/profile.erb
18
+ # end
19
+ #
20
+ # r.get 'list' do
21
+ # view 'lists/users' # uses ./views/lists/users.erb
22
+ # end
23
+ # end
24
+ # end
25
+ #
26
+ # This plugin should be loaded after the render plugin, since
27
+ # it works by overriding parts of the render plugin.
28
+ module ViewSubdirs
29
+ module InstanceMethods
30
+ # Set the view subdirectory to use. This can be set to nil
31
+ # to not use a view subdirectory.
32
+ def set_view_subdir(v)
33
+ @_view_subdir = v
34
+ end
35
+
36
+ private
37
+
38
+ # Override the template name to use the view subdirectory if the
39
+ # there is a view subdirectory and the template name does not
40
+ # contain a slash.
41
+ def template_path(template, opts)
42
+ t = template.to_s
43
+ if (v = @_view_subdir) && t !~ /\//
44
+ template = "#{v}/#{t}"
45
+ end
46
+ super
47
+ end
48
+ end
49
+ end
50
+
51
+ register_plugin(:view_subdirs, ViewSubdirs)
52
+ end
53
+ end
data/lib/roda/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Roda
2
- RodaVersion = '0.9.2'.freeze
2
+ RodaVersion = '0.9.3'.freeze
3
3
  end
@@ -639,6 +639,22 @@ describe "request verb methods" do
639
639
  end
640
640
  end
641
641
 
642
+ describe "all matcher" do
643
+ it "should match only all all arguments match" do
644
+ app do |r|
645
+ r.is :all=>['foo', :y] do |file|
646
+ file
647
+ end
648
+ end
649
+
650
+ body("/foo/bar").should == 'bar'
651
+ status.should == 404
652
+ status("/foo").should == 404
653
+ status("/foo/").should == 404
654
+ status("/foo/bar/baz").should == 404
655
+ end
656
+ end
657
+
642
658
  describe "extension matcher" do
643
659
  it "should match given file extensions" do
644
660
  app do |r|
@@ -681,3 +697,29 @@ describe "route block that returns string" do
681
697
  body.should == '+1'
682
698
  end
683
699
  end
700
+
701
+ describe "hash_matcher" do
702
+ it "should enable the handling of arbitrary hash keys" do
703
+ app(:bare) do
704
+ hash_matcher(:foos){|v| consume(self.class.cached_matcher(:"foos-#{v}"){/((?:foo){#{v}})/})}
705
+ route do |r|
706
+ r.is :foos=>1 do |f|
707
+ "1#{f}"
708
+ end
709
+ r.is :foos=>2 do |f|
710
+ "2#{f}"
711
+ end
712
+ r.is :foos=>3 do |f|
713
+ "3#{f}"
714
+ end
715
+ end
716
+ end
717
+
718
+ body("/foo").should == '1foo'
719
+ body("/foofoo").should == '2foofoo'
720
+ body("/foofoofoo").should == '3foofoofoo'
721
+ status("/foofoofoofoo").should == 404
722
+ status.should == 404
723
+ end
724
+ end
725
+
@@ -0,0 +1,38 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "backtracking_array plugin" do
4
+ it "backtracks to next entry in array if later matcher fails" do
5
+ app(:backtracking_array) do |r|
6
+ r.is %w'a a/b' do |id|
7
+ id
8
+ end
9
+
10
+ r.is %w'c c/d', %w'd e' do |a, b|
11
+ "#{a}-#{b}"
12
+ end
13
+
14
+ r.is [%w'f f/g', %w'g g/h'] do |id|
15
+ id
16
+ end
17
+ end
18
+
19
+ status.should == 404
20
+
21
+ body("/a").should == 'a'
22
+ body("/a/b").should == 'a/b'
23
+ status("/a/b/").should == 404
24
+
25
+ body("/c/d").should == 'c-d'
26
+ body("/c/e").should == 'c-e'
27
+ body("/c/d/d").should == 'c/d-d'
28
+ body("/c/d/e").should == 'c/d-e'
29
+ status("/c/d/").should == 404
30
+
31
+ body("/f").should == 'f'
32
+ body("/f/g").should == 'f/g'
33
+ body("/g").should == 'g'
34
+ body("/g/h").should == 'g/h'
35
+ status("/f/g/").should == 404
36
+ status("/g/h/").should == 404
37
+ end
38
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ begin
4
+ require 'rack/csrf'
5
+ rescue LoadError
6
+ warn "rack_csrf not installed, skipping csrf plugin test"
7
+ else
8
+ describe "csrf plugin" do
9
+ it "adds csrf protection and csrf helper methods" do
10
+ app(:bare) do
11
+ use Rack::Session::Cookie, :secret=>'1'
12
+ plugin :csrf, :skip=>['POST:/foo']
13
+
14
+ route do |r|
15
+ r.get do
16
+ response['TAG'] = csrf_tag
17
+ response['METATAG'] = csrf_metatag
18
+ response['TOKEN'] = csrf_token
19
+ response['FIELD'] = csrf_field
20
+ response['HEADER'] = csrf_header
21
+ 'g'
22
+ end
23
+ r.post 'foo' do
24
+ 'bar'
25
+ end
26
+ r.post do
27
+ 'p'
28
+ end
29
+ end
30
+ end
31
+
32
+ io = StringIO.new
33
+ status('REQUEST_METHOD'=>'POST', 'rack.input'=>io).should == 403
34
+ body('/foo', 'REQUEST_METHOD'=>'POST', 'rack.input'=>io).should == 'bar'
35
+
36
+ env = proc{|h| h['Set-Cookie'] ? {'HTTP_COOKIE'=>h['Set-Cookie'].sub("; path=/; HttpOnly", '')} : {}}
37
+ s, h, b = req
38
+ s.should == 200
39
+ field = h['FIELD']
40
+ token = Regexp.escape(h['TOKEN'])
41
+ h['TAG'].should =~ /\A<input type="hidden" name="#{field}" value="#{token}" \/>\z/
42
+ h['METATAG'].should =~ /\A<meta name="#{field}" content="#{token}" \/>\z/
43
+ b.should == ['g']
44
+ s, _, b = req('/', env[h].merge('REQUEST_METHOD'=>'POST', 'rack.input'=>io, "HTTP_#{h['HEADER']}"=>h['TOKEN']))
45
+ s.should == 200
46
+ b.should == ['p']
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "json plugin" do
4
+ before do
5
+ c = Class.new do
6
+ def to_json
7
+ '[1]'
8
+ end
9
+ end
10
+
11
+ app(:bare) do
12
+ plugin :json
13
+ json_result_classes << c
14
+
15
+ route do |r|
16
+ r.is 'array' do
17
+ [1, 2, 3]
18
+ end
19
+
20
+ r.is "hash" do
21
+ {'a'=>'b'}
22
+ end
23
+
24
+ r.is 'c' do
25
+ c.new
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ it "should use a json content type for a json response" do
32
+ header('Content-Type', "/array").should == 'application/json'
33
+ header('Content-Type', "/hash").should == 'application/json'
34
+ header('Content-Type', "/c").should == 'application/json'
35
+ header('Content-Type').should == 'text/html'
36
+ end
37
+
38
+ it "should convert objects to json" do
39
+ body('/array').gsub(/\s/, '').should == '[1,2,3]'
40
+ body('/hash').gsub(/\s/, '').should == '{"a":"b"}'
41
+ body('/c').should == '[1]'
42
+ body.should == ''
43
+ end
44
+
45
+ it "should work when subclassing" do
46
+ @app = Class.new(app)
47
+ app.route{[1]}
48
+ body.should == '[1]'
49
+ end
50
+ end
@@ -1,7 +1,7 @@
1
1
  require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
2
 
3
3
  describe "pass plugin" do
4
- it "executes on no arguments" do
4
+ it "skips the current block if pass is called" do
5
5
  app(:pass) do |r|
6
6
  r.on :id do |id|
7
7
  r.pass if id == 'foo'
@@ -0,0 +1,28 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "per_thread_caching plugin" do
4
+ it "should use a per thread cache instead of a shared cache" do
5
+ app(:bare) do
6
+ plugin :per_thread_caching
7
+ @c = thread_safe_cache
8
+ def self.c; @c end
9
+ route do |r|
10
+ r.on :id do |i|
11
+ ((self.class.c[i] ||= []) << 2).join
12
+ end
13
+ end
14
+ end
15
+
16
+ (0..10).map do |n|
17
+ Thread.new do
18
+ Thread.current[:n] = n
19
+ body('/a').should == '2'
20
+ body('/a').should == '22'
21
+ body('/a').should == '222'
22
+ body('/b').should == '2'
23
+ body('/b').should == '22'
24
+ body('/b').should == '222'
25
+ end
26
+ end.map{|t| t.join}
27
+ end
28
+ end
@@ -1,7 +1,8 @@
1
1
  require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
2
 
3
3
  begin
4
- require 'tilt'
4
+ require 'tilt/erb'
5
+ require 'tilt/string'
5
6
  rescue LoadError
6
7
  warn "tilt not installed, skipping render plugin test"
7
8
  else
@@ -0,0 +1,62 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "symbol_matchers plugin" do
4
+ it "allows symbol specific regexps" do
5
+ app(:bare) do
6
+ plugin :symbol_matchers
7
+ symbol_matcher(:f, /(f+)/)
8
+
9
+ route do |r|
10
+ r.is :d do |d|
11
+ "d#{d}"
12
+ end
13
+
14
+ r.is "foo:optd" do |o|
15
+ "foo#{o.inspect}"
16
+ end
17
+
18
+ r.is "bar:opt" do |o|
19
+ "bar#{o.inspect}"
20
+ end
21
+
22
+ r.is "format:format" do |f|
23
+ "format#{f.inspect}"
24
+ end
25
+
26
+ r.is :f do |f|
27
+ "f#{f}"
28
+ end
29
+
30
+ r.is :w do |w|
31
+ "w#{w}"
32
+ end
33
+
34
+ r.is ':d/:w/:f' do |d, w, f|
35
+ "dwf#{d}#{w}#{f}"
36
+ end
37
+ end
38
+ end
39
+
40
+ status.should == 404
41
+ body("/1").should == 'd1'
42
+ body("/11232135").should == 'd11232135'
43
+ body("/a").should == 'wa'
44
+ body("/1az0").should == 'w1az0'
45
+ body("/f").should == 'ff'
46
+ body("/foo").should == 'foonil'
47
+ body("/foo/123").should == 'foo"123"'
48
+ status("/foo/bar").should == 404
49
+ status("/foo/123/a").should == 404
50
+ body("/bar").should == 'barnil'
51
+ body("/bar/foo").should == 'bar"foo"'
52
+ status("/bar/foo/baz").should == 404
53
+ body("/format").should == 'formatnil'
54
+ body("/format.json").should == 'format"json"'
55
+ status("/format.").should == 404
56
+ body("/ffffffffffffffff").should == 'fffffffffffffffff'
57
+ status("/-").should == 404
58
+ body("/1/1a/f").should == 'dwf11af'
59
+ body("/12/1azy/fffff").should == 'dwf121azyfffff'
60
+ status("/1/f/a").should == 404
61
+ end
62
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "symbol_views plugin" do
4
+ before do
5
+ app(:bare) do
6
+ plugin :symbol_views
7
+
8
+ def view(s)
9
+ "v#{s}"
10
+ end
11
+
12
+ route do |r|
13
+ r.root do
14
+ :sym
15
+ end
16
+
17
+ r.is "string" do
18
+ 'string'
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ it "should call view with the symbol" do
25
+ body.should == "vsym"
26
+ end
27
+
28
+ it "should not affect other return types" do
29
+ body("/string").should == 'string'
30
+ body("/foo").should == ''
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ begin
4
+ require 'tilt/erb'
5
+ rescue LoadError
6
+ warn "tilt not installed, skipping view_subdirs plugin test"
7
+ else
8
+ describe "view_subdirs plugin" do
9
+ before do
10
+ app(:bare) do
11
+ plugin :render
12
+ render_opts[:views] = "./spec"
13
+ plugin :view_subdirs
14
+
15
+ route do |r|
16
+ r.on "home" do
17
+ set_view_subdir 'views'
18
+ view("home", :locals=>{:name => "Agent Smith", :title => "Home"}, :layout_opts=>{:locals=>{:title=>"Home"}})
19
+ end
20
+
21
+ r.on "about" do
22
+ set_view_subdir 'views'
23
+ render("views/about", :locals=>{:title => "About Roda"})
24
+ end
25
+
26
+ r.on "path" do
27
+ render('views/about', :locals=>{:title => "Path"}, :layout_opts=>{:locals=>{:title=>"Home"}})
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ it "should use set subdir if template name does not contain a slash" do
34
+ body("/home").strip.should == "<title>Roda: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>"
35
+ end
36
+
37
+ it "should not use set subdir if template name contains a slash" do
38
+ body("/about").strip.should == "<h1>About Roda</h1>"
39
+ end
40
+
41
+ it "should not change behavior when subdir is not set" do
42
+ body("/path").strip.should == "<h1>Path</h1>"
43
+ end
44
+ end
45
+ end