roda-cj 0.9.2 → 0.9.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.
@@ -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