ramaze 0.3.0 → 0.3.5

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.
Files changed (122) hide show
  1. data/Rakefile +3 -2
  2. data/bin/ramaze +9 -3
  3. data/doc/AUTHORS +6 -2
  4. data/doc/CHANGELOG +272 -66
  5. data/doc/GPL +12 -13
  6. data/doc/README.html +729 -0
  7. data/doc/changes.txt +5757 -0
  8. data/doc/changes.xml +5759 -0
  9. data/doc/meta/announcement.txt +48 -39
  10. data/doc/tutorial/todolist.mkd +10 -12
  11. data/examples/blog/start.rb +1 -0
  12. data/examples/caching.rb +1 -0
  13. data/examples/element.rb +3 -0
  14. data/examples/hello.rb +1 -3
  15. data/examples/identity.rb +5 -8
  16. data/examples/layout.rb +1 -0
  17. data/examples/linking.rb +1 -0
  18. data/examples/memleak_detector.rb +1 -0
  19. data/examples/nitro_form.rb +1 -0
  20. data/examples/rammit/start.rb +1 -0
  21. data/examples/rapaste/Rakefile +7 -0
  22. data/examples/rapaste/{src/controller.rb → controller/paste.rb} +28 -3
  23. data/examples/rapaste/{src/model.rb → model/paste.rb} +0 -4
  24. data/examples/rapaste/public/css/display.css +17 -0
  25. data/examples/rapaste/spec/rapaste.rb +2 -2
  26. data/examples/rapaste/start.rb +9 -4
  27. data/examples/rapaste/{template → view}/copy.xhtml +0 -0
  28. data/examples/rapaste/{template → view}/index.xhtml +0 -0
  29. data/examples/rapaste/{template → view}/layout.xhtml +3 -0
  30. data/examples/rapaste/{template → view}/list.xhtml +4 -3
  31. data/examples/rapaste/view/search.xhtml +41 -0
  32. data/examples/rapaste/{template → view}/view.xhtml +0 -0
  33. data/examples/simple.rb +3 -3
  34. data/examples/templates/template/external.amrita +9 -9
  35. data/examples/templates/template/external.redcloth +19 -0
  36. data/examples/templates/template_amrita2.rb +40 -7
  37. data/examples/templates/template_erubis.rb +3 -3
  38. data/examples/templates/template_ezamar.rb +1 -3
  39. data/examples/templates/template_haml.rb +1 -3
  40. data/examples/templates/template_liquid.rb +3 -3
  41. data/examples/templates/template_markaby.rb +1 -3
  42. data/examples/templates/template_nagoro.rb +1 -3
  43. data/examples/templates/template_redcloth.rb +59 -0
  44. data/examples/templates/template_remarkably.rb +1 -3
  45. data/examples/templates/template_xslt.rb +1 -4
  46. data/examples/todolist/src/controller/main.rb +1 -1
  47. data/examples/todolist/start.rb +1 -2
  48. data/examples/upload/start.rb +19 -0
  49. data/examples/upload/view/index.xhtml +25 -0
  50. data/examples/whywiki/start.rb +1 -3
  51. data/examples/wikore/start.rb +3 -0
  52. data/examples/wiktacular/mkd/newpagename/current.mkd +1 -0
  53. data/examples/wiktacular/mkd/newpagename/current.mkd.bak +1 -0
  54. data/examples/wiktacular/start.rb +1 -0
  55. data/lib/proto/controller/main.rb +0 -3
  56. data/lib/proto/public/js/jquery.js +106 -93
  57. data/lib/proto/spec/main.rb +2 -5
  58. data/lib/proto/start.rb +0 -3
  59. data/lib/ramaze.rb +3 -2
  60. data/lib/ramaze/action.rb +6 -10
  61. data/lib/ramaze/adapter/lsws.rb +19 -0
  62. data/lib/ramaze/contrib/email.rb +84 -0
  63. data/lib/ramaze/contrib/email.rb-darcs-backup0 +81 -0
  64. data/lib/ramaze/contrib/gettext.rb +1 -0
  65. data/lib/ramaze/contrib/gettext/parser.rb +46 -0
  66. data/lib/ramaze/contrib/route.rb +3 -36
  67. data/lib/ramaze/controller.rb +4 -6
  68. data/lib/ramaze/controller/resolve.rb +28 -1
  69. data/lib/ramaze/dispatcher.rb +1 -1
  70. data/lib/ramaze/dispatcher/file.rb +17 -0
  71. data/lib/ramaze/global/globalstruct.rb +7 -4
  72. data/lib/ramaze/helper/auth.rb +1 -1
  73. data/lib/ramaze/helper/identity.rb +25 -15
  74. data/lib/ramaze/helper/link.rb +29 -8
  75. data/lib/ramaze/helper/maruku.rb +7 -0
  76. data/lib/ramaze/helper/partial.rb +25 -10
  77. data/lib/ramaze/route.rb +56 -0
  78. data/lib/ramaze/snippets/metaid.rb +17 -0
  79. data/lib/ramaze/spec/helper.rb +0 -2
  80. data/lib/ramaze/spec/helper/mock_http.rb +6 -0
  81. data/lib/ramaze/spec/helper/pretty_output.rb +5 -1
  82. data/lib/ramaze/store/default.rb +3 -1
  83. data/lib/ramaze/template.rb +1 -1
  84. data/lib/ramaze/template/amrita2.rb +21 -15
  85. data/lib/ramaze/template/bijou.rb +39 -0
  86. data/lib/ramaze/template/builder.rb +28 -0
  87. data/lib/ramaze/template/redcloth.rb +24 -0
  88. data/lib/ramaze/template/sass.rb +3 -1
  89. data/lib/ramaze/tool/create.rb +2 -1
  90. data/lib/ramaze/tool/localize.rb +6 -1
  91. data/lib/ramaze/trinity/request.rb +8 -0
  92. data/lib/ramaze/trinity/session.rb +8 -5
  93. data/lib/ramaze/version.rb +1 -1
  94. data/rake_tasks/gem.rake +0 -1
  95. data/rake_tasks/maintenance.rake +4 -1
  96. data/spec/contrib/route.rb +14 -63
  97. data/spec/examples/linking.rb +2 -2
  98. data/spec/examples/templates/template_redcloth.rb +28 -0
  99. data/spec/ramaze/controller/subclass.rb +21 -0
  100. data/spec/ramaze/dispatcher/file.rb +31 -0
  101. data/spec/ramaze/helper/link.rb +46 -0
  102. data/spec/ramaze/helper/partial.rb +22 -1
  103. data/spec/ramaze/helper/template/locals.xhtml +1 -0
  104. data/spec/ramaze/helper/template/recursive_locals.xhtml +7 -0
  105. data/spec/ramaze/params.rb +8 -0
  106. data/spec/ramaze/request.rb +14 -0
  107. data/spec/ramaze/route.rb +107 -0
  108. data/spec/ramaze/session.rb +4 -2
  109. data/spec/ramaze/template/amrita2.rb +21 -7
  110. data/spec/ramaze/template/amrita2/external.amrita +6 -0
  111. data/spec/ramaze/template/amrita2/sum.amrita +1 -1
  112. data/spec/ramaze/template/bijou.rb +25 -0
  113. data/spec/ramaze/template/builder.rb +55 -0
  114. data/spec/ramaze/template/builder/external.rxml +3 -0
  115. data/spec/ramaze/template/haml.rb +15 -0
  116. data/spec/ramaze/template/haml/locals.haml +1 -0
  117. data/spec/ramaze/template/redcloth.rb +38 -0
  118. data/spec/ramaze/template/redcloth/external.redcloth +1 -0
  119. metadata +472 -442
  120. data/examples/rapaste/rapaste.sqlite +0 -0
  121. data/spec/ramaze/template/amrita2/data.amrita +0 -6
  122. data/spec/ramaze/template/amrita2/index.amrita +0 -1
@@ -0,0 +1,39 @@
1
+ # Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'bijou'
5
+
6
+ module Ramaze
7
+ module Template
8
+
9
+ # Is responsible for compiling a template using the Bijou templating engine.
10
+ # Can be found at: http://bijou.rubyforge.org/
11
+
12
+ class Bijou < Template
13
+
14
+ ENGINES[self] = %w[ bijou rbb ]
15
+
16
+ class << self
17
+
18
+ # Transform via Haml templating engine
19
+
20
+ def transform action
21
+ compiled = wrap_compile(action)
22
+ context = ::Bijou::Context.new(::Bijou::Config.new)
23
+ # context.container_callback = method(:container_callback)
24
+ # context.component_callback = method(:component_callback)
25
+ ::Bijou::Processor.execute(context, compiled, 'GeneralView', {})
26
+ end
27
+
28
+ # Instantiates Haml::Engine with the template and haml_options trait from
29
+ # the controller.
30
+
31
+ def compile(action, template)
32
+ parser = ::Bijou::Parser.new
33
+ parser.parse('GeneralView', template)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,28 @@
1
+ require 'builder'
2
+
3
+ module Ramaze
4
+ module Template
5
+
6
+ class Builder < Template
7
+ ENGINES[self] = %w[ builder rxml ]
8
+
9
+ class << self
10
+ def transform action
11
+ if response = Response.current
12
+ response['Content-Type'] = "application/xml"
13
+ end
14
+
15
+ template = wrap_compile(action)
16
+ action.instance.instance_eval(template, action.template || __FILE__)
17
+ end
18
+
19
+ def compile action, template
20
+ "xml = ::Builder::XmlMarkup.new(:indent => 2)\n" +
21
+ template +
22
+ "\nxml.target!\n"
23
+ end
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ require 'redcloth'
2
+
3
+ module Ramaze
4
+ module Template
5
+
6
+ # Is responsible for compiling a template using the RedCloth templating engine.
7
+ # Can be found at: http://whytheluckystiff.net/ruby/redcloth/
8
+
9
+ class RedCloth < Erubis
10
+ ENGINES[self] = %w[ redcloth ]
11
+
12
+ class << self
13
+ def transform(action)
14
+ restrictions = action.controller.trait[:redcloth_options] || []
15
+ rules = action.controller.trait[:redcloth_options] || []
16
+
17
+ # Erubis -> RedCloth -> HTML
18
+ redcloth = ::RedCloth.new(super, restrictions)
19
+ redcloth.to_html(*rules)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -18,7 +18,9 @@ module Ramaze
18
18
  # Transform via Sass templating engine
19
19
 
20
20
  def transform action
21
- Response.current['Content-Type'] = "text/css"
21
+ if response = Response.current
22
+ response['Content-Type'] = "text/css"
23
+ end
22
24
  sass = wrap_compile(action)
23
25
  sass.to_css()
24
26
  end
@@ -43,7 +43,8 @@ module Ramaze
43
43
  directories, files =
44
44
  Dir[@basedir / '**' / '*'].partition{ |f| File.directory?(f) }
45
45
 
46
- create_dirs(*directories)
46
+ # gem packaging removes empty model directory, so add it in ourselves
47
+ create_dirs(*Array[ @basedir/'model', *directories ].uniq)
47
48
  copy_files(*files)
48
49
 
49
50
  puts "\nStart your new ramaze app: ruby #{project}/start.rb"
@@ -59,7 +59,12 @@ class Ramaze::Tool::Localize
59
59
  # `localize` for more information.
60
60
 
61
61
  def localize_body(body, options)
62
- locale = (session[:LOCALE] || set_session_locale).to_s
62
+ locale =
63
+ if trait[:languages].include?(response["Content-Language"])
64
+ response["Content-Language"]
65
+ else
66
+ (session[:LOCALE] || set_session_locale).to_s
67
+ end
63
68
 
64
69
  body.gsub!(trait[:regex]) do
65
70
  localize($1, locale) unless $1.to_s.empty?
@@ -69,6 +69,14 @@ module Ramaze
69
69
  Array[value, *params.values_at(*keys)]
70
70
  end
71
71
 
72
+ def to_ivs(*args)
73
+ instance = Action.current.instance
74
+ args.each do |arg|
75
+ next unless value = self[arg]
76
+ instance.instance_variable_set("@#{arg}", value)
77
+ end
78
+ end
79
+
72
80
  unless method_defined?(:rack_params)
73
81
  alias rack_params params
74
82
 
@@ -70,6 +70,10 @@ module Ramaze
70
70
 
71
71
  IP_COUNT_LIMIT = 1000 unless defined?(IP_COUNT_LIMIT)
72
72
 
73
+ # Holds the default cookie used for sessions
74
+
75
+ COOKIE = { :path => '/' }
76
+
73
77
  class << self
74
78
 
75
79
  # called from Ramaze::startup and adds Cache.sessions if cookies are
@@ -95,11 +99,10 @@ module Ramaze
95
99
  def initialize request
96
100
  @session_id = (request.cookies[SESSION_KEY] || random_key)
97
101
 
98
- ip = request.remote_addr
99
- IP_COUNT[ip] << @session_id
100
-
101
- if IP_COUNT[ip].size > IP_COUNT_LIMIT
102
- sessions.delete(IP_COUNT[ip].shift)
102
+ unless IP_COUNT.nil?
103
+ ip = request.remote_addr
104
+ IP_COUNT[ip] << @session_id
105
+ sessions.delete(IP_COUNT[ip].shift) if IP_COUNT[ip].size > IP_COUNT_LIMIT
103
106
  end
104
107
 
105
108
  @flash = Ramaze::SessionFlash.new
@@ -5,7 +5,7 @@ module Ramaze #:nodoc:
5
5
  module Version #:nodoc:
6
6
  MAJOR = 0
7
7
  MINOR = 3
8
- TINY = 0
8
+ TINY = 5
9
9
 
10
10
  STRING = [MAJOR, MINOR, TINY].join('.')
11
11
  end
data/rake_tasks/gem.rake CHANGED
@@ -17,7 +17,6 @@ spec =
17
17
  s.post_install_message = POST_INSTALL_MESSAGE
18
18
 
19
19
  s.add_dependency('rake', '>=0.7.3')
20
- s.add_dependency('rspec', '>=1.0.2')
21
20
  s.add_dependency('rack', '>=0.2.0')
22
21
  # s.required_ruby_version = '>= 1.8.5'
23
22
 
@@ -209,11 +209,14 @@ def authors
209
209
  'clive@crous.co.za' => 'Clive Crous',
210
210
  'comp.lang.zenix+ramaze@gmail.com' => 'zenix',
211
211
  'jesuswasramazing.10.pistos@geoshell.com' => 'Pistos',
212
+ 'jesusisramazing.10.pistos@geoshell.com' => 'Pistos',
212
213
  'manveru@weez-int.com' => 'Michael Fellinger',
213
214
  'm.fellinger@gmail.com' => 'Michael Fellinger',
214
- 'outtenr@gmail.com' => 'Carlo Zottmann',
215
+ 'outtenr@gmail.com' => 'Richard Outten',
215
216
  'rff.rff@gmail.com' => 'Gabriele Renzi',
217
+ 'skaar@waste.org' => 'skaar',
216
218
  'stephan@spaceboyz.net' => 'Stephan Maka',
219
+ 'keita.yamaguchi@gmail.com' => 'Keita Yamaguchi',
217
220
  }
218
221
 
219
222
  mapping = {}
@@ -3,20 +3,12 @@ require 'spec/helper'
3
3
  Ramaze.contrib :route
4
4
 
5
5
  class MainController < Ramaze::Controller
6
- def float(flt)
7
- "Float: #{flt}"
6
+ def text(num)
7
+ "text: #{num}"
8
8
  end
9
9
 
10
- def string(str)
11
- "String: #{str}"
12
- end
13
-
14
- def price(p)
15
- "Price: \$#{p}"
16
- end
17
-
18
- def sum(a, b)
19
- a.to_i + b.to_i
10
+ def bar
11
+ "bar"
20
12
  end
21
13
  end
22
14
 
@@ -25,61 +17,20 @@ describe 'Route' do
25
17
  ramaze
26
18
  @route = Ramaze::Contrib::Route
27
19
 
28
- it 'should take custom lambda routers' do
29
- @route['string'] = lambda {|path, req| path if path =~ %r!^/string! }
30
- @route['string'].class.should == Proc
31
-
32
- @route['calc sum'] = lambda do |path, req|
33
- if req[:do_calc]
34
- lval, rval = req[:a, :b]
35
- rval = rval.to_i * 10
36
- "/sum/#{lval}/#{rval}"
37
- end
38
- end
39
- end
40
-
41
- it 'should be possible to define routes' do
42
- @route[%r!^/(\d+\.\d{2})$!] = "/price/%.2f"
43
- @route[%r!^/(\d+\.\d{2})$!].should == "/price/%.2f"
44
-
45
- @route[%r!^/(\d+\.\d+)!] = "/float/%.3f"
46
- @route[%r!^/(\d+\.\d+)!].should == "/float/%.3f"
47
-
48
- @route[%r!^/(\w+)!] = "/string/%s"
49
- @route[%r!^/(\w+)!].should == "/string/%s"
50
- end
51
-
52
- it 'should be used - /float' do
53
- r = get('/123.123')
54
- r.status.should == 200
55
- r.body.should == 'Float: 123.123'
56
- end
57
-
58
- it 'should be used - /string' do
59
- r = get('/foo')
60
- r.status.should == 200
61
- r.body.should == 'String: foo'
62
- end
63
-
64
- it 'should use %.3f' do
65
- r = get('/123.123456')
66
- r.status.should == 200
67
- r.body.should == 'Float: 123.123'
68
- end
69
-
70
- it 'should resolve in the order added' do
71
- r = get('/12.84')
72
- r.status.should == 200
73
- r.body.should == 'Price: $12.84'
20
+ it 'should provide backwards compat wrapper to Ramaze::Route' do
21
+ @route[ %r!^/(\d+)\.te?xt$! ] = "/text/%d"
22
+ @route[ 'foobar' ] = lambda{ |path, request|
23
+ '/bar' if path == '/foo' and request[:bar] == '1'
24
+ }
74
25
  end
75
26
 
76
- it 'should use lambda routers' do
77
- r = get('/string/abc')
27
+ it 'should work' do
28
+ r = get('/123.txt')
78
29
  r.status.should == 200
79
- r.body.should == 'String: abc'
30
+ r.body.should == 'text: 123'
80
31
 
81
- r = get('/', 'do_calc=1&a=2&b=6')
32
+ r = get('/foo', 'bar=1')
82
33
  r.status.should == 200
83
- r.body.should == '62'
34
+ r.body.should == 'bar'
84
35
  end
85
36
  end
@@ -9,10 +9,10 @@ describe 'Linking' do
9
9
  r = get('/').body
10
10
  r.should.include('<a href="/help">Help?</a>')
11
11
  end
12
-
12
+
13
13
  it 'should provide a link to another controller' do
14
14
  r = get('/help').body
15
15
  r.should.include('<a href="/link_to/another">A Different Controller</a>')
16
16
  end
17
17
 
18
- end
18
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec/helper'
2
+
3
+ spec_require 'redcloth'
4
+ require 'examples/templates/template_redcloth'
5
+
6
+ describe 'Template RedCloth' do
7
+ behaves_like 'http'
8
+ ramaze
9
+
10
+ it '/' do
11
+ html = get('/').body.strip
12
+ html.should =~ %r(<a href=\"/\">Home</a>)
13
+ html.should =~ %r(<a href=\"/internal\">internal</a>)
14
+ html.should =~ %r(<a href=\"/external\">external</a>)
15
+ end
16
+
17
+ %w[/internal /external].each do |url|
18
+ it url do
19
+ name = url.gsub(/^\//, '')
20
+ response = get(url)
21
+ response.status.should == 200
22
+ html = response.body
23
+ html.should.not == nil
24
+ html.should =~ %r(<title>Template::RedCloth #{name}</title>)
25
+ html.should =~ %r(<h1>The #{name} Template for RedCloth</h1>)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'spec/helper'
5
+
6
+ class BaseController < Ramaze::Controller
7
+ def test() 'test' end
8
+ end
9
+
10
+ class MainController < BaseController
11
+ engine :None
12
+ end
13
+
14
+ describe 'Controller' do
15
+ behaves_like 'http'
16
+ ramaze
17
+
18
+ it 'should allow sub-classing MainController' do
19
+ get('/test').body.should == 'test'
20
+ end
21
+ end
@@ -21,4 +21,35 @@ describe 'Dispatcher::File' do
21
21
  end
22
22
  get('/favicon.ico').body.should == original
23
23
  end
24
+
25
+ it 'should send ETag' do
26
+ res = get '/test_download.css'
27
+ res.headers['ETag'].should.not.be == nil
28
+ res.headers['ETag'].length.should == 34 # "32 hash"
29
+ end
30
+
31
+ it 'should send Last-Modified' do
32
+ res = get '/test_download.css'
33
+ res.headers['Last-Modified'].should.not.be == nil
34
+ res.headers['Last-Modified'].should == File.stat(@public_root/'test_download.css').mtime.httpdate
35
+ end
36
+
37
+ it 'should respect ETag with IF_NONE_MATCHES' do
38
+ res = get '/test_download.css'
39
+ etag = res.headers['ETag']
40
+ etag.should.not.be == nil
41
+ res = get '/test_download.css', :if_none_match=>etag
42
+ res.status.should == 304
43
+ res.body.should == ''
44
+ end
45
+
46
+ it 'should respect If-Modified' do
47
+ res = get '/test_download.css'
48
+ mtime = res.headers['Last-Modified']
49
+ mtime.should.not.be == nil
50
+ res = get '/test_download.css', :if_modified_since=>mtime
51
+ res.status.should == 304
52
+ res.body.should == ''
53
+ end
54
+
24
55
  end
@@ -6,11 +6,24 @@ require 'ramaze/helper/link'
6
6
 
7
7
  class TCLink < Ramaze::Controller
8
8
  map '/'
9
+ def index; end
9
10
  end
10
11
 
12
+ class TCLink2 < Ramaze::Controller
13
+ map '/2'
14
+ def index; end
15
+ end
16
+
17
+ ramaze
18
+
11
19
  describe "A" do
12
20
  extend Ramaze::LinkHelper
13
21
 
22
+ before do
23
+ # initialize Ramaze::Controller.current for Rs()
24
+ Ramaze::Controller.handle('/')
25
+ end
26
+
14
27
  it 'should build links' do
15
28
  A('title', :href => '/').should == %(<a href="/">title</a>)
16
29
  A('title', :href => '/foo').should == %(<a href="/foo">title</a>)
@@ -21,6 +34,10 @@ describe "A" do
21
34
  a.should =~ /class="none"/
22
35
  a.should =~ /href="\/foo"/
23
36
  end
37
+
38
+ it 'should build position independend links' do
39
+ A(TCLink, :foo).should == %(<a href="/foo">foo</a>)
40
+ end
24
41
  end
25
42
 
26
43
  describe 'R' do
@@ -34,6 +51,24 @@ describe 'R' do
34
51
  end
35
52
  end
36
53
 
54
+ describe 'Rs' do
55
+ extend Ramaze::LinkHelper
56
+
57
+ it 'should build links for current controller' do
58
+ Ramaze::Controller.handle('/2')
59
+ Rs(:index).should == '/2/index'
60
+
61
+ Ramaze::Controller.handle('/')
62
+ Rs(:index).should == '/index'
63
+ end
64
+
65
+ it 'should treat Rs() like R() when Controller given' do
66
+ Ramaze::Controller.handle('/2')
67
+ Rs(TCLink, :index).should == '/2/index'
68
+ end
69
+
70
+ end
71
+
37
72
  describe 'breadcrumbs' do
38
73
  extend Ramaze::LinkHelper
39
74
 
@@ -47,4 +82,15 @@ describe 'breadcrumbs' do
47
82
  "<a href=\"/file/dir/listing/is/cool\">cool</a>"
48
83
  ].join('/')
49
84
  end
85
+
86
+ it 'should lay out breadcrumbs with href prefix' do
87
+ breadcrumbs('/file/dir/listing/is/cool', '/', '/', '/prefix/path').
88
+ should == [
89
+ "<a href=\"/prefix/path/file\">file</a>",
90
+ "<a href=\"/prefix/path/file/dir\">dir</a>",
91
+ "<a href=\"/prefix/path/file/dir/listing\">listing</a>",
92
+ "<a href=\"/prefix/path/file/dir/listing/is\">is</a>",
93
+ "<a href=\"/prefix/path/file/dir/listing/is/cool\">cool</a>"
94
+ ].join('/')
95
+ end
50
96
  end