vanilla 1.14.1 → 1.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/Rakefile +3 -2
  2. data/bin/vanilla +35 -6
  3. data/lib/vanilla/app.rb +6 -1
  4. data/lib/vanilla/console.rb +17 -6
  5. data/lib/vanilla.rb +1 -1
  6. data/pristine_app/Gemfile +3 -0
  7. data/pristine_app/Gemfile.lock +32 -0
  8. data/pristine_app/README +36 -0
  9. data/pristine_app/config.ru +26 -0
  10. data/pristine_app/public/vanilla.css +15 -0
  11. data/pristine_app/soups/base/layout.snip +18 -0
  12. data/pristine_app/soups/base/start.snip +19 -0
  13. data/pristine_app/soups/dynasnips/current_snip.rb +29 -0
  14. data/{lib/vanilla → pristine_app/soups}/dynasnips/debug.rb +5 -3
  15. data/{lib/vanilla → pristine_app/soups}/dynasnips/index.rb +2 -0
  16. data/{lib/vanilla → pristine_app/soups}/dynasnips/link_to.rb +2 -0
  17. data/pristine_app/soups/dynasnips/link_to_current_snip.rb +14 -0
  18. data/pristine_app/soups/dynasnips/page_title.rb +9 -0
  19. data/{lib/vanilla → pristine_app/soups}/dynasnips/pre.rb +6 -4
  20. data/{lib/vanilla → pristine_app/soups}/dynasnips/raw.rb +8 -5
  21. data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/comments.rb +3 -1
  22. data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/kind.rb +0 -0
  23. data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/rand.rb +2 -0
  24. data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/url_to.rb +0 -0
  25. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/bad_dynasnip.snip +0 -0
  26. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/hello_world.snip +0 -0
  27. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/markdown_example.snip +0 -0
  28. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/snip.snip +0 -0
  29. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/soup.snip +1 -3
  30. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/test.snip +0 -0
  31. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/textile_example.snip +0 -0
  32. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/tutorial-another-snip.snip +0 -0
  33. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/tutorial-basic-snip-inclusion.snip +0 -0
  34. data/pristine_app/soups/tutorial/tutorial-dynasnips.snip.markdown +56 -0
  35. data/pristine_app/soups/tutorial/tutorial-layout.snip +56 -0
  36. data/pristine_app/soups/tutorial/tutorial-links.snip +4 -0
  37. data/pristine_app/soups/tutorial/tutorial-renderers.snip.markdown +77 -0
  38. data/{lib/vanilla/snips/tutorial/vanilla-rb-tutorial.snip → pristine_app/soups/tutorial/tutorial.snip.markdown} +17 -21
  39. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/vanilla-rb.snip +0 -0
  40. data/{lib/vanilla/snips → pristine_app/soups}/tutorial/vanilla.snip +0 -0
  41. data/pristine_app/tmp/restart.txt +0 -0
  42. data/test/test_helper.rb +1 -1
  43. data/test/vanilla_app_test.rb +3 -3
  44. data/test/vanilla_presenting_test.rb +9 -2
  45. metadata +76 -73
  46. data/README_FOR_APP +0 -38
  47. data/config.example.yml +0 -7
  48. data/config.ru +0 -11
  49. data/lib/tasks/vanilla.rake +0 -75
  50. data/lib/vanilla/dynasnips/current_snip.rb +0 -32
  51. data/lib/vanilla/dynasnips/link_to_current_snip.rb +0 -16
  52. data/lib/vanilla/dynasnips/title.rb +0 -7
  53. data/lib/vanilla/snips/system/layout.snip +0 -19
  54. data/lib/vanilla/snips/system/start.snip +0 -25
  55. data/lib/vanilla/snips/system/system.snip +0 -17
  56. data/public/hatch.png +0 -0
data/Rakefile CHANGED
@@ -2,7 +2,8 @@ require "rubygems"
2
2
  require "rake/gempackagetask"
3
3
  require "rake/rdoctask"
4
4
 
5
- load File.join(File.dirname(__FILE__), *%w[lib tasks vanilla.rake])
5
+ require "bundler/setup"
6
+ require "vanilla"
6
7
 
7
8
  task :default => :test
8
9
 
@@ -35,7 +36,7 @@ if Object.const_defined?(:Gem)
35
36
  s.rdoc_options = %w(--main README)
36
37
 
37
38
  # Add any extra files to include in the gem
38
- s.files = %w(config.example.yml config.ru Rakefile README README_FOR_APP) + Dir.glob("{test,lib,bin,public}/**/*")
39
+ s.files = %w(Rakefile README) + Dir.glob("{test,lib,bin,pristine_app}/**/*")
39
40
  s.executables = ['vanilla']
40
41
  s.require_paths = ["lib"]
41
42
 
data/bin/vanilla CHANGED
@@ -1,9 +1,38 @@
1
1
  #!/usr/bin/env ruby
2
- require 'rubygems'
3
- require 'rake'
4
- load File.join(File.dirname(__FILE__), *%w[.. lib tasks vanilla.rake])
5
2
 
6
- mkdir(ARGV[0])
7
- cd(ARGV[0])
3
+ def create(new_app_dir)
4
+ require 'fileutils'
5
+ pristine_app = File.expand_path("../../pristine_app", __FILE__)
6
+ FileUtils.cp_r(pristine_app, new_app_dir)
7
+ FileUtils.mkdir(File.join(new_app_dir, "tmp"))
8
+ require 'vanilla'
9
+ File.open(File.join(new_app_dir, "Gemfile"), "w") do |f|
10
+ f.write "source :rubygems\n\n# Vanilla itself.\ngem 'vanilla', '#{Vanilla::VERSION}'"
11
+ end
12
+ puts File.readlines(File.join(new_app_dir, "README"))[0..16].join
13
+ end
8
14
 
9
- Rake::Task['vanilla:setup'].invoke
15
+ def console
16
+ $LOAD_PATH << "lib"
17
+ require "rubygems"
18
+ require "bundler/setup"
19
+ require "irb"
20
+ require "vanilla/console"
21
+ ARGV.clear
22
+ puts "The Soup is simmering."
23
+ IRB.start
24
+ end
25
+
26
+ def upgrade
27
+ # TODO
28
+ puts "TODO, but should be easier thanks to multi-space soup."
29
+ end
30
+
31
+ case ARGV[0]
32
+ when "console"
33
+ console
34
+ when "upgrade"
35
+ upgrade
36
+ else
37
+ create(ARGV[0])
38
+ end
data/lib/vanilla/app.rb CHANGED
@@ -49,7 +49,12 @@ module Vanilla
49
49
  def formatted_render(snip, part=nil, format=nil)
50
50
  case format
51
51
  when 'html', nil
52
- render(layout_for(snip))
52
+ layout = layout_for(snip)
53
+ if layout == snip
54
+ "Rendering of the current layout would result in infinite recursion."
55
+ else
56
+ render(layout)
57
+ end
53
58
  when 'raw', 'css', 'js'
54
59
  Renderers::Raw.new(self).render(snip, part)
55
60
  when 'text', 'atom', 'xml'
@@ -1,12 +1,23 @@
1
1
  require 'vanilla'
2
- require 'irb'
2
+
3
+ module Vanilla
4
+ class RackShim
5
+ def run(app)
6
+ app # return it
7
+ end
8
+ def use(*args)
9
+ # ignore
10
+ end
11
+ def get_binding
12
+ binding
13
+ end
14
+ end
15
+ end
3
16
 
4
17
  def app(reload=false)
5
18
  if !@__vanilla_console_app || reload
6
- config = YAML.parse_file(ENV['VANILLA_CONFIG']) rescue {}
7
- @__vanilla_console_app = Vanilla::App.new(config)
19
+ shim_binding = Vanilla::RackShim.new.get_binding
20
+ @__vanilla_console_app = eval File.read("config.ru"), shim_binding
8
21
  end
9
22
  @__vanilla_console_app
10
- end
11
-
12
- puts "The Soup is simmering."
23
+ end
data/lib/vanilla.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Vanilla
2
- VERSION = "1.14.1"
2
+ VERSION = "1.15"
3
3
 
4
4
  autoload :Renderers, "vanilla/renderers"
5
5
  autoload :App, "vanilla/app"
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gem 'vanilla', :path => File.expand_path("../..", __FILE__)
@@ -0,0 +1,32 @@
1
+ PATH
2
+ remote: /Users/james/Code/lazyatom/vanilla-rb
3
+ specs:
4
+ vanilla (1.15)
5
+ BlueCloth (>= 1.0.0)
6
+ RedCloth (>= 4.1.1)
7
+ haml
8
+ rack (>= 0.9.1)
9
+ ratom (>= 0.3.5)
10
+ soup (>= 1.0.6)
11
+ treetop (>= 1.4.1)
12
+
13
+ GEM
14
+ remote: http://rubygems.org/
15
+ specs:
16
+ BlueCloth (1.0.1)
17
+ RedCloth (4.2.7)
18
+ haml (3.0.25)
19
+ libxml-ruby (2.0.2)
20
+ polyglot (0.3.1)
21
+ rack (1.2.2)
22
+ ratom (0.6.7)
23
+ libxml-ruby (>= 1.1.2)
24
+ soup (1.0.6)
25
+ treetop (1.4.9)
26
+ polyglot (>= 0.3.1)
27
+
28
+ PLATFORMS
29
+ ruby
30
+
31
+ DEPENDENCIES
32
+ vanilla!
@@ -0,0 +1,36 @@
1
+ WELCOME IN VANILLA
2
+ Vanilla
3
+ vanilla
4
+ .........vanillaaaaaAAAAAAAAAAA
5
+
6
+ What you've got:
7
+
8
+ Gemfile - specifying your dependencies
9
+ config.ru - this is the rack configuration, which is used to start
10
+ the application by your webserver
11
+ soup/ - the default soup directory, where your snips are stored
12
+
13
+
14
+ For an overview of vanilla, start your site and look at the tutorial:
15
+
16
+ $ rackup # then open http://localhost:9292/tutorial
17
+
18
+
19
+ You can edit any file in the soup directory using your favourite editor,
20
+ and the changes will be reflected automatically. The snip files are
21
+ slightly modified YAML files. Here's an example, which you might save
22
+ in a file called 'soup.snip':
23
+
24
+
25
+ Soup is a data store supporting the {link_to snip}-space that
26
+ {link_to vanilla-rb} expects.
27
+
28
+ It's hosted on github [here](http://github.com/lazyatom/soup).
29
+
30
+ :created_at: 2011-05-23 14:14:16 +01:00
31
+ :updated_at: 2009-05-23 15:23:22 +01:00
32
+ :render_as: Markdown
33
+
34
+
35
+ The 'content' of the snip is at the top of the file, followed by the
36
+ rest of the snip attributes on lines starting with ':'.
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ $:.unshift File.join(File.dirname(__FILE__), *%w[lib])
4
+
5
+ require 'vanilla'
6
+
7
+ # You can partition your snips into subdirectories to keep things tidy. This
8
+ # doesn't affect their URL structure on the site (everything is flat).
9
+ soups = [
10
+ "soups/base",
11
+ "soups/dynasnips"
12
+ ]
13
+
14
+ # If you don't want the tutorial on your site, remove this and delete the directory
15
+ soups << "soups/tutorial"
16
+
17
+ # This is a dumping ground of ideas at the moment
18
+ # soups << "soups/extras"
19
+
20
+ app = Vanilla::App.new(:soups => soups)
21
+
22
+ # If you running your site under a proper webserver, you probably don't need this.
23
+ require 'vanilla/static'
24
+ use Vanilla::Static, File.join(File.dirname(__FILE__), 'public')
25
+
26
+ run app
@@ -0,0 +1,15 @@
1
+ #controls {
2
+ padding-left: 0;
3
+ }
4
+
5
+ #controls li {
6
+ background: #eee;
7
+ display: inline;
8
+ padding: 0.2em 0.5em;
9
+ }
10
+
11
+ pre {
12
+ margin-left: 1em;
13
+ background-color: #ddd;
14
+ padding: 1em;
15
+ }
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+ <html lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
5
+ <title>{page_title}</title>
6
+ <link rel="stylesheet" href="/vanilla.css" type="text/css" media="screen" title="no title" charset="utf-8">
7
+ </head>
8
+ <body>
9
+ <ul id="controls">
10
+ <li><a href="/">home</a></li>
11
+ <li>{link_to index}</li>
12
+ <li>you are viewing: {link_to_current_snip}</li>
13
+ </ul>
14
+ <div id="content">
15
+ {current_snip}
16
+ </div>
17
+ </body>
18
+ </html>
@@ -0,0 +1,19 @@
1
+ <h1>Welcome to Vanilla.rb</h1>
2
+
3
+ <p>Vanilla.rb is a web-experiment (a <em>websperiment</em>?) about storing and reusing data on a website. It can also function as a <a href="http://www.wikipedia.com/wiki/Bliki">bliki</a>.</p>
4
+
5
+ <p>From a technical perspective, vanilla is a Ruby rack application, and should play well within the rack ecosystem. It uses a simple document store called `soup` to store data.</p>
6
+
7
+ <h2>What now?</h2>
8
+
9
+ <p>If this is your first time using vanilla, you should investigate the {link_to tutorial} for some orientation.</p>
10
+
11
+ <h2>What next?</h2>
12
+
13
+ <p>This is the {link_to start} snip, which is the default home page. You can find this content in `start.snip`.</p>
14
+
15
+ <p>You should replace this content with whatever you want on your site's home page.</p>
16
+
17
+ <p>Once your site is ready to run, you'll probably want to remove the tutorial; you can do this by editing the configuration in `config.ru`, and deleting the `soups/tutorial` directory.</p>
18
+
19
+ <p>Good luck!</p>
@@ -0,0 +1,29 @@
1
+ require 'vanilla/dynasnip'
2
+
3
+ class CurrentSnip < Dynasnip
4
+ usage %|
5
+ The current_snip dyna normally returns the result of rendering the snip named by the
6
+ 'snip' value in the parameters. This way, it can be used in templates to place the currently
7
+ requested snip, in its rendered form, within the page.
8
+
9
+ It can also be used to determine an attribute of the current snip in a consistent way:
10
+
11
+ {current_snip name}
12
+
13
+ will output the name of the current snip.
14
+ |
15
+
16
+ def handle(attribute=nil)
17
+ if attribute
18
+ app.request.snip.__send__(attribute)
19
+ else
20
+ if app.request.snip
21
+ app.render(app.request.snip, app.request.part)
22
+ else
23
+ app.response.status = 404
24
+ %{Couldn't find snip "#{app.request.snip_name}"}
25
+ end
26
+ end
27
+ end
28
+ self
29
+ end
@@ -1,13 +1,15 @@
1
1
  require 'vanilla/dynasnip'
2
+ require 'cgi'
2
3
 
3
4
  # If the dynasnip is a subclass of Dynasnip, it has access to the request hash
4
5
  # (or whatever - access to some object outside of the snip itself.)
5
6
  class Debug < Dynasnip
6
7
  def get(*args)
7
- app.request.inspect
8
+ CGI.escapeHTML(app.request.inspect)
8
9
  end
9
-
10
+
10
11
  def post(*args)
11
- "You posted! " + app.request.inspect
12
+ "You posted! " + CGI.escapeHTML(app.request.inspect)
12
13
  end
14
+ self
13
15
  end
@@ -7,4 +7,6 @@ class Index < Dynasnip
7
7
  }
8
8
  "<ol>#{list}</ol>"
9
9
  end
10
+
11
+ self
10
12
  end
@@ -11,4 +11,6 @@ would insert a link to the blah snip.|
11
11
  def handle(snip_name, link_text=snip_name, part=nil)
12
12
  link_to(link_text, snip_name, part)
13
13
  end
14
+
15
+ self
14
16
  end
@@ -0,0 +1,14 @@
1
+ require 'vanilla/dynasnip'
2
+
3
+ class LinkToCurrentSnip < Dynasnip
4
+ usage %|
5
+ Renders a link to the current snip, or the snip currently being edited
6
+ (if we're currently editing)
7
+ |
8
+
9
+ def handle(*args)
10
+ link_to app.request.snip_name
11
+ end
12
+
13
+ self
14
+ end
@@ -0,0 +1,9 @@
1
+ require 'vanilla/dynasnip'
2
+
3
+ class PageTitle < Dynasnip
4
+ def handle
5
+ app.request.snip.page_title || app.request.snip.name
6
+ end
7
+
8
+ self
9
+ end
@@ -5,15 +5,17 @@ class ShowContentInPreTag < Dynasnip
5
5
 
6
6
  usage %|
7
7
  Wraps the contents of the given snip in &lt;pre&gt; tags, e.g.
8
-
8
+
9
9
  {pre my_snip}
10
-
10
+
11
11
  You can specify a part to render in pre tags, should you wish:
12
-
12
+
13
13
  {pre my_snip,specific_part}
14
14
  |
15
-
15
+
16
16
  def handle(snip_name, part=:content)
17
17
  %{<pre>#{app.soup[snip_name].__send__(part || :content)}</pre>}
18
18
  end
19
+
20
+ self
19
21
  end
@@ -1,19 +1,22 @@
1
1
  require 'vanilla/dynasnip'
2
+ require 'cgi'
2
3
 
3
4
  class ShowRawContent < Dynasnip
4
5
  snip_name "raw"
5
6
 
6
7
  usage %|
7
8
  Displays the raw contents of a snip in &lt;pre&gt; tags, e.g.
8
-
9
+
9
10
  {raw my_snip}
10
-
11
+
11
12
  You can specify a part to show, should you wish:
12
-
13
+
13
14
  {raw my_snip,specific_part}
14
15
  |
15
-
16
+
16
17
  def handle(snip_name, part=:content)
17
- %{<pre>#{Dynasnip.escape_curly_braces(app.soup[snip_name].__send__(part || :content))}</pre>}
18
+ %{#{Dynasnip.escape_curly_braces(CGI.escapeHTML(app.soup[snip_name].__send__(part || :content)))}}
18
19
  end
20
+
21
+ self
19
22
  end
@@ -64,7 +64,7 @@ class Comments < Dynasnip
64
64
  }
65
65
 
66
66
  attribute :comment_form, %{
67
- <form class="comments" action="/#{snip_name}?snip=SNIP_NAME" method="POST">
67
+ <form class="comments" action="/comments?snip=SNIP_NAME" method="POST">
68
68
  <label>Name: <input type="text" name="author"></input></label>
69
69
  <label>Email: <input type="text" name="email"></input></label>
70
70
  <label>Website: <input type="text" name="website"></input></label>
@@ -73,4 +73,6 @@ class Comments < Dynasnip
73
73
  <button>Submit</button>
74
74
  </form>
75
75
  }
76
+
77
+ self
76
78
  end
@@ -24,4 +24,6 @@ class RandomNumber < Dynasnip
24
24
  max = max.to_i
25
25
  (rand(max-min) + min)
26
26
  end
27
+
28
+ self
27
29
  end
@@ -1,5 +1,3 @@
1
1
  Soup is a data store supporting the {link_to snip}-space that {link_to vanilla-rb} expects.
2
2
 
3
- It's hosted on github <a href="http://github.com/lazyatom/soup">here</a>.
4
-
5
- :render_as: Markdown
3
+ It's hosted on github <a href="http://github.com/lazyatom/soup">here</a>.
@@ -0,0 +1,56 @@
1
+ {tutorial-links}
2
+
3
+ Dynasnips
4
+ =========
5
+
6
+ As mentioned in the general {link_to tutorial}, dynamic content is built in vanilla using "dynasnips". These are snips who content depends on more than just their content.
7
+
8
+ Typically they are rendered by the `Vanilla::Renderers::Ruby` renderer. Lets look again at the raw content of `link_to`:
9
+
10
+ {raw link_to}
11
+
12
+ As you can see, it simply refers to the Ruby class `LinkTo`, which is contained within the vanilla-rb codebase. When the Ruby renderer is called, expects the given code to evaulate to a Ruby class. It then instantiates the class, and calls a `handle` method on the instance, passing it any other arguments from the snip inclusion.
13
+
14
+ You can pass arguments to dynasnips in a number of ways. All of the following are valid:
15
+
16
+ * &#123;dynasnip apple&#125;
17
+ * &#123;dynasnip apple, banana&#125;
18
+ * &#123;dynasnip apple, big banana, cherry&#125;
19
+ * &#123;dynasnip apple, big banana, "lovely lucious cherry"&#125;
20
+ * &#123;dynasnip apple => true, banana => false&#125;
21
+ * &#123;dynasnip apple: true, banana: false&#125;
22
+
23
+ Where a simple list of arguments is given, these will be passed to the `handle` method as an array. If a ruby-hash-like syntax is used, a hash of these options will be passed.
24
+
25
+ Of course, it depends entirely on the implementation of the dynasnip what arguments it expects and accepts; some may require a flat list, while others may require hash-like named arguments.
26
+
27
+
28
+ Writing your own Dynasnips
29
+ --------------------------
30
+
31
+ While dynasnip classes can be provided as part of the vanilla codebase, it's envisioned that much of these will be created by end users in their own sites, either by refering to local classes, or defining the classes directly as the content. Here's an example of that, as the raw content of `hello_world`:
32
+
33
+ {raw hello_world}
34
+
35
+ It's important that the contents of the snip evaluate to a Ruby class; this is easy to achieve by placing `self` as the last statement in the class definition, or referencing the class at the end of the snip; both are shown above.
36
+
37
+ If we include the dynasnip here as <tt>&#123;hello\_world&#125;</tt>, gives:
38
+
39
+ > {hello_world}
40
+
41
+ Note that the `handle` method can take one (optional) argument. Lets try including it with <tt>&#123;hello\_world Dave&#125;</tt>:
42
+
43
+ > {hello_world Dave}
44
+
45
+
46
+ HTTP Verbs
47
+ ----------
48
+
49
+ By default, the Ruby renderer will attempt to call `handle` on a dynasnip instance, but if the instance responds to methods corresponding to the HTTP Verbs - `get`, `post`, `put`, or `delete` - then these methods will be called instead.
50
+
51
+ This means you can have a single dynasnip which responds differently when receiving a `POST` request - quite useful if you want to write dynasnips that generate and respond to forms, like the `comments` dynasnip in your `extras` soup directory.
52
+
53
+ There's really no limit to what you can do with dynasnips - only what you can imagine.
54
+
55
+
56
+ {tutorial-links}
@@ -0,0 +1,56 @@
1
+ {tutorial-links}
2
+
3
+ Layouts
4
+ =======
5
+
6
+ Since you almost certainly want your site to look good, one of the first things you'll want to change in your vanilla site is the layout.
7
+
8
+ When the browser requests a snip, normally vanilla will present it within a _layout_ template. This would typically include a header, a footer, and any other peripheral markup that shouldn't be within the content of the snip itself. If you're familiar with the construction of web applications, this will be exactly as you expect.
9
+
10
+ Layouts are just like any other snip - they can be sent through a renderer, and include other snips. The default layout snip is called, predictable, `layout.snip`, and here's the content:
11
+
12
+ {raw layout}
13
+
14
+ When you request `/start`, this is the snip that's actually rendered first. If this snip was just text, that's all that would be returned; however, there are some dynasnip calls in here which help us actually return the content that the user requested.
15
+
16
+
17
+ `current_snip`
18
+ --------------
19
+
20
+ The most significant is the call to `current_snip`. This figures out what snip was actually requested (e.g. if the url is `/start`, it's the {link_to start} snip), and renders it in place.
21
+
22
+ Here's the source of `current_snip`:
23
+
24
+ {raw current_snip}
25
+
26
+ The default case, as in our layout, is `app.render(app.request.snip, app.request.part)` - it delegates rendering back to the application, which then takes care of processing `start` using the right renderer and so on. This method call returns the fully rendered string, and vanilla replaces the call to the dynasnip with that output, placing our snip in the appropriate place in the layout.
27
+
28
+
29
+ Other dynas
30
+ -----------
31
+
32
+ Of course, you can put other plain content in your layout, and other dynasnips too. In the provided layout there are calls to two other dynasnips.
33
+
34
+ The first is `page_title`, which simply places a (hopefully) meaningful string in the title element of the page. Snips can set the title to be used by defining a `:page_title` attribute. As usual, the source explains it more clearly:
35
+
36
+ {raw page_title}
37
+
38
+ The second dynasnip used is `link_to_current_snip`, which returns an HTML link to the snip that's currently being rendered. I'll let you figure out how to view the source yourself.
39
+
40
+
41
+ Other layouts
42
+ -------------
43
+
44
+ Vanilla looks for a snip called `layout` by default, but this can be changed by passing in a `:default_layout` option to `Vanilla::App.new`, e.g.
45
+
46
+ Vanilla::App.new(:default_layout => "my_layout")
47
+
48
+
49
+ You can also override the layout on a per-snip basis, simply by setting the `:layout` attribute of the snip to the name of the layout snip to use instead.
50
+
51
+ Finally, if you implement a custom renderer class (see {link_to tutorial-renderers, "the renderers tutorial"}), you can also specify a layout to be used when the requested snip invokes that renderer. This can be useful if you have a particular kind of content that requires a different layout entirely.
52
+
53
+ {tutorial-links}
54
+
55
+ :render_as: Markdown
56
+ :page_title: Tutorial - Layout
@@ -0,0 +1,4 @@
1
+ {link_to tutorial}
2
+ {link_to tutorial-layout}
3
+ {link_to tutorial-renderers}
4
+ {link_to tutorial-dynasnips}