vanilla 1.2 → 1.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/Rakefile +61 -60
  2. data/bin/vanilla +6 -35
  3. data/config.example.yml +6 -0
  4. data/config.ru +10 -0
  5. data/lib/defensio.rb +59 -0
  6. data/lib/tasks/vanilla.rake +173 -0
  7. data/lib/vanilla.rb +3 -10
  8. data/lib/vanilla/app.rb +48 -104
  9. data/lib/vanilla/console.rb +5 -19
  10. data/lib/vanilla/dynasnips/comments.rb +108 -0
  11. data/lib/vanilla/dynasnips/current_snip.rb +32 -0
  12. data/{pristine_app/soups → lib/vanilla}/dynasnips/debug.rb +3 -5
  13. data/lib/vanilla/dynasnips/edit.rb +60 -0
  14. data/lib/vanilla/dynasnips/edit_link.rb +20 -0
  15. data/{pristine_app/soups → lib/vanilla}/dynasnips/index.rb +2 -4
  16. data/{pristine_app/soups/extras → lib/vanilla/dynasnips}/kind.rb +12 -14
  17. data/{pristine_app/soups → lib/vanilla}/dynasnips/link_to.rb +0 -2
  18. data/lib/vanilla/dynasnips/link_to_current_snip.rb +16 -0
  19. data/lib/vanilla/dynasnips/login.rb +56 -0
  20. data/lib/vanilla/dynasnips/new.rb +14 -0
  21. data/lib/vanilla/dynasnips/notes.rb +42 -0
  22. data/{pristine_app/soups → lib/vanilla}/dynasnips/pre.rb +4 -6
  23. data/{pristine_app/soups/extras → lib/vanilla/dynasnips}/rand.rb +0 -2
  24. data/{pristine_app/soups → lib/vanilla}/dynasnips/raw.rb +5 -8
  25. data/{pristine_app/soups/extras → lib/vanilla/dynasnips}/url_to.rb +0 -0
  26. data/lib/vanilla/renderers/base.rb +22 -32
  27. data/lib/vanilla/renderers/bold.rb +2 -0
  28. data/lib/vanilla/renderers/erb.rb +2 -0
  29. data/lib/vanilla/renderers/markdown.rb +2 -0
  30. data/lib/vanilla/renderers/raw.rb +2 -0
  31. data/lib/vanilla/renderers/ruby.rb +5 -9
  32. data/lib/vanilla/renderers/textile.rb +2 -0
  33. data/lib/vanilla/request.rb +15 -16
  34. data/lib/vanilla/routes.rb +18 -5
  35. data/lib/vanilla/snip_reference.rb +534 -0
  36. data/lib/vanilla/snip_reference.treetop +48 -0
  37. data/lib/vanilla/snip_reference_parser.rb +99 -82
  38. data/lib/vanilla/snips/start.rb +28 -0
  39. data/lib/vanilla/snips/system.rb +77 -0
  40. data/lib/vanilla/snips/tutorial.rb +244 -0
  41. data/lib/vanilla/soup_with_timestamps.rb +21 -0
  42. data/public/hatch.png +0 -0
  43. data/public/javascripts/jquery.autogrow-textarea.js +54 -0
  44. data/public/javascripts/jquery.js +4376 -0
  45. data/public/javascripts/vanilla.js +22 -0
  46. data/spec/dynasnip_spec.rb +28 -0
  47. data/spec/renderers/base_renderer_spec.rb +40 -0
  48. data/spec/renderers/erb_renderer_spec.rb +27 -0
  49. data/spec/renderers/markdown_renderer_spec.rb +29 -0
  50. data/spec/renderers/raw_renderer_spec.rb +21 -0
  51. data/spec/renderers/ruby_renderer_spec.rb +59 -0
  52. data/spec/renderers/vanilla_app_detecting_renderer_spec.rb +35 -0
  53. data/spec/spec_helper.rb +70 -0
  54. data/spec/tmp/config.yml +2 -0
  55. data/spec/tmp/soup/current_snip.yml +15 -0
  56. data/spec/tmp/soup/system.yml +5 -0
  57. data/spec/vanilla_app_spec.rb +38 -0
  58. data/spec/vanilla_presenting_spec.rb +84 -0
  59. data/spec/vanilla_request_spec.rb +73 -0
  60. metadata +79 -170
  61. data/lib/vanilla/renderers.rb +0 -12
  62. data/lib/vanilla/renderers/haml.rb +0 -13
  63. data/lib/vanilla/static.rb +0 -28
  64. data/pristine_app/Gemfile +0 -3
  65. data/pristine_app/Gemfile.lock +0 -32
  66. data/pristine_app/README +0 -47
  67. data/pristine_app/config.ru +0 -26
  68. data/pristine_app/public/vanilla.css +0 -15
  69. data/pristine_app/soups/base/layout.snip +0 -18
  70. data/pristine_app/soups/base/start.snip +0 -19
  71. data/pristine_app/soups/dynasnips/current_snip.rb +0 -29
  72. data/pristine_app/soups/dynasnips/link_to_current_snip.rb +0 -14
  73. data/pristine_app/soups/dynasnips/page_title.rb +0 -9
  74. data/pristine_app/soups/extras/comments.rb +0 -78
  75. data/pristine_app/soups/tutorial/bad_dynasnip.snip +0 -8
  76. data/pristine_app/soups/tutorial/hello_world.snip +0 -20
  77. data/pristine_app/soups/tutorial/markdown_example.snip +0 -13
  78. data/pristine_app/soups/tutorial/snip.snip +0 -9
  79. data/pristine_app/soups/tutorial/soup.snip +0 -3
  80. data/pristine_app/soups/tutorial/test.snip +0 -30
  81. data/pristine_app/soups/tutorial/textile_example.snip +0 -11
  82. data/pristine_app/soups/tutorial/tutorial-another-snip.snip +0 -1
  83. data/pristine_app/soups/tutorial/tutorial-basic-snip-inclusion.snip +0 -1
  84. data/pristine_app/soups/tutorial/tutorial-dynasnips.snip.markdown +0 -56
  85. data/pristine_app/soups/tutorial/tutorial-layout.snip +0 -56
  86. data/pristine_app/soups/tutorial/tutorial-links.snip +0 -4
  87. data/pristine_app/soups/tutorial/tutorial-renderers.snip.markdown +0 -77
  88. data/pristine_app/soups/tutorial/tutorial.snip.markdown +0 -69
  89. data/pristine_app/soups/tutorial/vanilla-rb.snip +0 -16
  90. data/pristine_app/soups/tutorial/vanilla.snip +0 -8
  91. data/test/dynasnip_test.rb +0 -42
  92. data/test/dynasnips/link_to_current_snip_test.rb +0 -19
  93. data/test/dynasnips/link_to_test.rb +0 -27
  94. data/test/dynasnips/page_title_test.rb +0 -19
  95. data/test/renderers/base_renderer_test.rb +0 -43
  96. data/test/renderers/erb_renderer_test.rb +0 -29
  97. data/test/renderers/haml_renderer_test.rb +0 -35
  98. data/test/renderers/markdown_renderer_test.rb +0 -31
  99. data/test/renderers/raw_renderer_test.rb +0 -23
  100. data/test/renderers/ruby_renderer_test.rb +0 -59
  101. data/test/snip_inclusion_test.rb +0 -56
  102. data/test/snip_reference_parser_test.rb +0 -123
  103. data/test/test_helper.rb +0 -75
  104. data/test/vanilla_app_test.rb +0 -83
  105. data/test/vanilla_presenting_test.rb +0 -125
  106. data/test/vanilla_request_test.rb +0 -87
@@ -0,0 +1,48 @@
1
+ grammar SnipReference
2
+ rule snip_call
3
+ "{" (snip_name) (spaces argument_list)? "}" <SnipCall>
4
+ end
5
+
6
+ rule snip_name
7
+ word "." word <SnipNameWithAttribute> /
8
+ word <SnipName>
9
+ end
10
+
11
+ rule argument_list
12
+ argument (argument_separator argument_list)? <ArgumentList>
13
+ end
14
+
15
+ rule argument
16
+ unquoted_words <NormalArgument> /
17
+ quoted_word <NormalArgument>
18
+ end
19
+
20
+ rule argument_separator
21
+ "," optional_spaces
22
+ end
23
+
24
+ rule word
25
+ unquoted_word / quoted_word
26
+ end
27
+
28
+ rule unquoted_word
29
+ ([a-zA-Z0-9_\-]+)
30
+ end
31
+
32
+ rule quoted_word
33
+ "\"" (unquoted_words) "\"" <QuotedWord> /
34
+ "'" (unquoted_words) "'" <QuotedWord>
35
+ end
36
+
37
+ rule unquoted_words
38
+ [a-zA-Z0-9_\- ]+
39
+ end
40
+
41
+ rule optional_spaces
42
+ [ ]*
43
+ end
44
+
45
+ rule spaces
46
+ [ ]+
47
+ end
48
+ end
@@ -1,94 +1,111 @@
1
- require "parslet"
2
-
3
- module Vanilla
4
- class SnipReferenceParser
5
- class Reference
6
- def initialize(attributes)
7
- @attributes = attributes
8
- end
9
- def snip
10
- @attributes[:snip]
11
- end
12
- def attribute
13
- @attributes[:attribute]
14
- end
15
- def arguments
16
- @attributes[:arguments] || []
17
- end
1
+ module SnipReference
2
+ module SnipCall
3
+ def snip
4
+ elements[1].name
18
5
  end
19
-
20
- def parse(string)
21
- Reference.new(SnipTransform.new.apply(SnipParser.new.parse(string)))
6
+ def attribute
7
+ elements[1].attribute
22
8
  end
23
-
24
- class SnipParser < Parslet::Parser
25
- rule(:spaces) { match('\s').repeat(1) }
26
- rule(:spaces?) { spaces.maybe }
27
- rule(:comma) { match(',') }
28
- rule(:dot) { str(".") }
29
- rule(:squote) { str("'") }
30
- rule(:dquote) { str('"') }
31
- rule(:escaped_dquote) { str('"') }
32
- rule(:left_brace) { str("{") }
33
- rule(:right_brace) { str("}") }
34
-
35
- rule(:word) { match("[a-zA-Z0-9_\\-]").repeat(1) }
36
- rule(:quotables) { word | comma | spaces }
37
- rule(:double_quoted_string) do
38
- dquote >> (quotables | squote).repeat(1).as(:string) >> dquote
39
- end
40
- rule(:single_quoted_string) do
41
- squote >> (quotables | dquote).repeat(1).as(:string) >> squote
9
+ def arguments
10
+ if elements[2] && elements[2].elements
11
+ r = elements[2].elements[1].to_arguments
12
+ r.flatten! if r.respond_to?(:flatten!)
13
+ r
14
+ else
15
+ []
42
16
  end
43
- rule(:string) do
44
- single_quoted_string | double_quoted_string | str("nil").as(:nil) | word.as(:string)
45
- end
46
- rule(:symbol) { str(":") >> string }
47
-
48
- rule(:comma_separator) { spaces? >> comma >> spaces? }
49
- rule(:hash_separator) { spaces? >> str("=>") >> spaces? }
50
- rule(:named_separator) { spaces? >> str(":") >> spaces? }
51
-
52
- rule(:hash_arg) { (symbol | string).as(:key) >> hash_separator >> string.as(:value) }
53
- rule(:named_arg) { string.as(:key) >> named_separator >> string.as(:value) }
54
-
55
- rule(:string_arg_list) { (string.as(:string_arg) >> further_string_args.repeat).as(:string_arg_list) }
56
- rule(:further_string_args) { comma_separator >> string.as(:string_arg) }
57
-
58
- rule(:hash_arg_list) { (hash_arg.as(:hash_arg) >> further_hash_args.repeat).as(:key_value_arg_list) }
59
- rule(:further_hash_args) { comma_separator >> hash_arg.as(:hash_arg) }
60
-
61
- rule(:named_arg_list) { (named_arg.as(:named_arg) >> further_named_args.repeat).as(:key_value_arg_list) }
62
- rule(:further_named_args) { comma_separator >> named_arg.as(:named_arg) }
17
+ end
18
+ end
19
+ module SnipName
20
+ def name
21
+ text_value
22
+ end
23
+ def attribute
24
+ nil
25
+ end
26
+ end
27
+ module SnipNameWithAttribute
28
+ def name
29
+ elements[0].text_value
30
+ end
31
+ def attribute
32
+ elements[2].text_value
33
+ end
34
+ end
35
+ module QuotedWord
36
+ def text_value
37
+ elements[1].text_value
38
+ end
39
+ end
40
+ module ArgumentList
41
+ def to_arguments
42
+ args = elements[0].to_arguments
43
+ args << elements[1].elements[1].to_arguments if elements[1].elements
44
+ args
45
+ end
46
+ end
47
+ module NormalArgument
48
+ def to_arguments
49
+ [text_value]
50
+ end
51
+ end
52
+ end
63
53
 
64
- rule(:arguments) { hash_arg_list | named_arg_list | string_arg_list }
65
- rule(:snip_part) { string.as(:snip) >> (dot >> string.as(:attribute)).maybe }
54
+ require 'treetop'
55
+ require 'vanilla/snip_reference'
66
56
 
67
- rule(:snip_reference) do
68
- left_brace >> spaces? >>
69
- snip_part >> (spaces >> arguments.as(:arguments)).maybe >>
70
- spaces? >> right_brace
71
- end
72
57
 
73
- root(:snip_reference)
74
- end
58
+ if __FILE__ == $0
75
59
 
76
- class SnipTransform < Parslet::Transform
77
- rule(:nil => simple(:x)) { nil }
78
- rule(:string => simple(:x)) { x.to_s }
79
- rule(:string_arg => simple(:x)) { x }
80
- rule(:string_arg_list => simple(:x)) { [x] }
81
- rule(:string_arg_list => sequence(:x)) { x }
60
+ Treetop.load "vanilla/snip_reference"
61
+ require 'test/unit'
82
62
 
83
- class Arg
84
- def initialize(k, v); @k, @v = k, v; end
85
- def to_h; {@k.to_sym => @v}; end
63
+ class SnipReferenceParserTest < Test::Unit::TestCase
64
+ examples = {
65
+ %|{snip}| => {:snip => 'snip', :attribute => nil, :arguments => []},
66
+ %|{snip argument}| => {:snip => 'snip', :attribute => nil, :arguments => ["argument"]},
67
+ %|{"snip with spaces"}| => {:snip => 'snip with spaces', :attribute => nil, :arguments => []},
68
+ %|{snip-with-dashes}| => {:snip => 'snip-with-dashes', :attribute => nil, :arguments => []},
69
+ %|{snip_with_underscores}| => {:snip => 'snip_with_underscores', :attribute => nil, :arguments => []},
70
+ %|{"snip with spaces" argument}| => {:snip => 'snip with spaces', :attribute => nil, :arguments => ['argument']},
71
+ %|{'snip with spaces' argument}| => {:snip => 'snip with spaces', :attribute => nil, :arguments => ['argument']},
72
+ %|{snip "argument with spaces"}| => {:snip => 'snip', :attribute => nil, :arguments => ['argument with spaces']},
73
+ %|{snip 'argument with spaces'}| => {:snip => 'snip', :attribute => nil, :arguments => ['argument with spaces']},
74
+ %|{snip arg1,arg2}| => {:snip => 'snip', :attribute => nil, :arguments => ['arg1', 'arg2']},
75
+ %|{snip arg1, arg2}| => {:snip => 'snip', :attribute => nil, :arguments => ['arg1', 'arg2']},
76
+ %|{snip "argument with spaces", arg2}| => {:snip => 'snip', :attribute => nil, :arguments => ['argument with spaces', 'arg2']},
77
+ %|{"snip with spaces" arg1, arg2}| => {:snip => 'snip with spaces', :attribute => nil, :arguments => ['arg1', 'arg2']},
78
+ %|{snip.snip_attribute}| => {:snip => 'snip', :attribute => 'snip_attribute', :arguments => []},
79
+ %|{snip."spaced attribute"}| => {:snip => 'snip', :attribute => 'spaced attribute', :arguments => []},
80
+ %|{"snip with spaces".attribute}| => {:snip => 'snip with spaces', :attribute => 'attribute', :arguments => []},
81
+ %|{snip.snip_attribute arg}| => {:snip => 'snip', :attribute => 'snip_attribute', :arguments => ['arg']},
82
+ %|{snip arg with spaces}| => {:snip => 'snip', :attribute => nil, :arguments => ['arg with spaces']},
83
+ %|{snip arg with spaces, another arg}| => {:snip => 'snip', :attribute => nil, :arguments => ['arg with spaces', 'another arg']},
84
+ # %|{snip key1:value1,key2:value2}| => {:snip => 'snip', :arguments => {:key1 => 'value1', :key2 => 'value2'}},
85
+ # %|{snip key1:value1, key2:value2}| => {:snip => 'snip', :arguments => {:key}},
86
+ # %|{snip key1: value1, key2: value2}|,
87
+ # %|{snip key1 => value1, key2 => value2}|,
88
+ # %|{snip :key1 => value1, :key2 => value2}|,
89
+ # %|{snip key1:"value with spaces"}|,
90
+ # %|{snip key1 => "value with spaces"}| => {:snip => 'snip', :arguments => {:key1 => "value with spaces"}}
91
+ }
92
+
93
+ def setup
94
+ @parser = SnipReferenceParser.new
95
+ end
96
+
97
+ examples.each do |example, expected|
98
+ define_method :"test_parsing_#{example}" do
99
+ reference = @parser.parse(example)
100
+ if reference
101
+ assert_equal expected[:snip], reference.snip
102
+ assert_equal expected[:attribute], reference.attribute
103
+ assert_equal expected[:arguments], reference.arguments
104
+ else
105
+ flunk "failed to parse: #{example}"
86
106
  end
87
-
88
- rule(:hash_arg => subtree(:x)) { Arg.new(x[:key], x[:value]) }
89
- rule(:named_arg => subtree(:x)) { Arg.new(x[:key], x[:value]) }
90
- rule(:key_value_arg_list => simple(:x)) { x.to_h }
91
- rule(:key_value_arg_list => sequence(:x)) { x.inject({}) { |h, kv| h.merge(kv.to_h) } }
92
107
  end
93
108
  end
109
+ end
110
+
94
111
  end
@@ -0,0 +1,28 @@
1
+ app = Vanilla::App.new(ENV['VANILLA_CONFIG'])
2
+ start = app.snip(:name => 'start')
3
+ start.content = <<-START
4
+ Welcome to Vanilla.rb
5
+ =============
6
+
7
+ Vanilla.rb is a web-experiment (a _websperiment_?) about storing and reusing data on a website. It can also function as a [bliki](http://www.wikipedia.com/wiki/Bliki).
8
+
9
+ The fundamental building block is the 'snip', which is a malleable object that can store content and arbitrary metadata.
10
+
11
+ ---
12
+
13
+ This is the {link_to start} snip, which is the default home page.
14
+
15
+ You might want to check out the {link_to vanilla-rb-tutorial} snip.
16
+
17
+ In fact - I'll include it here for you:
18
+
19
+ {vanilla-rb-tutorial}
20
+
21
+ ---
22
+
23
+ That was the end of the tutorial snip. We're back in the start snip now. There's also the {link_to test} snip, that might be interesting.
24
+
25
+ Anyway, welcome.
26
+ START
27
+ start.render_as = "Markdown"
28
+ start.save
@@ -0,0 +1,77 @@
1
+ app = Vanilla::App.new(ENV['VANILLA_CONFIG'])
2
+ system = app.snip(:name => "system")
3
+ system.content = "You're in the system snip now. You probably want to {edit_link system,edit} it though."
4
+
5
+ system.main_template = <<-HTML
6
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
7
+ <html lang="en">
8
+ <head>
9
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
10
+ <title>{current_snip name}</title>
11
+ <script language="javascript" src="/public/javascripts/jquery.js"></script>
12
+ <script language="javascript" src="/public/javascripts/vanilla.js"></script>
13
+ <link rel="stylesheet" type="text/css" media="screen" href="<%= url_to("system", "css.css") %>" />
14
+ </head>
15
+ <body>
16
+ <div id="content">
17
+ <div id="controls">
18
+ <strong><a href="/">home</a></strong>,
19
+ <%= new_link %> ::
20
+ <strong>{link_to_current_snip}</strong> &rarr;
21
+ {edit_link}
22
+ </div>
23
+ {current_snip}
24
+ </div>
25
+ </body>
26
+ </html>
27
+ HTML
28
+
29
+ system.css = <<-CSS
30
+ body {
31
+ font-family: Helvetica;
32
+ background-color: #666;
33
+ margin: 0;
34
+ padding: 0;
35
+ }
36
+
37
+ div#content {
38
+ width: 800px;
39
+ margin: 0 auto;
40
+ background-color: #fff;
41
+ padding: 1em;
42
+ }
43
+
44
+ div#controls {
45
+ font-size: 80%;
46
+ padding-bottom: 1em;
47
+ margin-bottom: 1em;
48
+ border-bottom: 1px solid #999;
49
+ }
50
+
51
+ textarea {
52
+ width: 100%;
53
+ }
54
+
55
+ textarea.content {
56
+ min-height: 10em;
57
+ }
58
+
59
+ pre {
60
+ background-color: #f6f6f6;
61
+ border: 1px solid #ccc;
62
+ padding: 1em;
63
+ }
64
+
65
+ a.new {
66
+ background-color: #f0f0f0;
67
+ text-decoration: none;
68
+ color: #999;
69
+ padding: 0.2em;
70
+ }
71
+
72
+ a.new:hover {
73
+ text-decoration: underline;
74
+ }
75
+ CSS
76
+
77
+ system.save
@@ -0,0 +1,244 @@
1
+ app = Vanilla::App.new(ENV['VANILLA_CONFIG'])
2
+ tutorial = app.snip(:name => 'vanilla-rb-tutorial')
3
+ tutorial.render_as = "Markdown"
4
+ tutorial.content = <<-END_OF_TUTORIAL
5
+ Basic Concepts
6
+ ------------
7
+
8
+ Every piece of information displayed here is stored as a {link_to snip}. Snips, within their contents, can also reference other snips. When you request a snip, it will render into a page (or another kind of response), and also render any snips that it internally references.
9
+
10
+ For example, consider the snip {link_to tutorial-basic-snip-inclusion}:
11
+
12
+ {raw tutorial-basic-snip-inclusion}
13
+
14
+ When this snip is rendered, it appears like this:
15
+
16
+ {tutorial-basic-snip-inclusion}
17
+
18
+ Notice the use of curly brackets to reference one snip from inside another. Vanilla.rb finds these references to snips, then renders that snip and replaces it in the first snip. Neat!
19
+
20
+ Renderers
21
+ --------
22
+
23
+ The way that a snip is rendered depends on whether or not it has a `render_as` attribute set. For instance, the `render_as` property of this snip ({link_to vanilla-rb}) is "Markdown". This means that the `content` of this snip will be passed through `Vanilla::Renderers::Markdown` before it is then rendered to the page. There are several different renders provided by Vanilla.rb at the moment:
24
+
25
+ * Markdown - as described above
26
+ * Textile - which performs similarly for Textile. This means that you can mix how you write the content of snips!
27
+ * Raw - which simply returns the content of the snip, as-is. If you attach a `.raw` extension to this url, you'll see it in action
28
+ * Bold - simply wraps the content in bold. It's a demo, essentially.
29
+ * Erb - passes the snip contents through Ruby's `Erb` library. It also makes some information available for use by ruby code within the snip's contents
30
+ * Ruby - parses the snips content as Ruby itself.
31
+
32
+ It's using this last renderer that a second concept of Vanilla is implemented - dynasnips.
33
+
34
+
35
+ Dynasnips
36
+ --------
37
+
38
+ Because the curly braces simply cause a snip to be rendered, we can use this in conjunction with the Ruby renderer to run actual code. For instance, in the snip above:
39
+
40
+ {raw tutorial-basic-snip-inclusion}
41
+
42
+ we can see a reference to the `link_to` snip - <tt>&#123;link\_to snip&#125;</tt>.
43
+
44
+ Lets look at the raw content of `link_to`:
45
+
46
+ {raw link_to}
47
+
48
+ 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. So, in the case of <tt>&#123;link\_to snip&#125;</tt>, the only argument is `snip`.
49
+
50
+ Vanilla.rb includes a number of dynasnips by default. Here are a couple:
51
+
52
+ * `rand`, which generates a random number (a silly demo really); {link_to rand}, or an example: {rand}
53
+ * `link_to`, to produce a link to another snip
54
+ * `kind`, which selects and renders sets of snips based on their `kind` attribute (this is how the blog is currently implemented)
55
+ * `raw`, which displays the raw contents of a snip
56
+ * `edit`, which implements the editor
57
+ * `index`, which shows all of the available snips: {link_to index}
58
+ * ... and several others.
59
+
60
+ 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 {link_to hello\_world}:
61
+
62
+ {raw hello_world}
63
+
64
+ which, when rendered, gives:
65
+
66
+ {hello_world}
67
+
68
+ Note that the `handle` method can take one (optional) argument. Lets try including it with <tt>&#123;hello\_world Dave&#125;</tt>:
69
+
70
+ {hello_world Dave}
71
+
72
+ Anyway - that should be enough to get you started.
73
+ END_OF_TUTORIAL
74
+
75
+ tutorial.save
76
+
77
+ tutorial_basic_snip_inclusion = app.snip(:name => 'tutorial-basic-snip-inclusion')
78
+ tutorial_basic_snip_inclusion.content = <<-EOS
79
+ This is a snip, which includes another {link_to snip}: {tutorial-another-snip}
80
+ EOS
81
+ tutorial_basic_snip_inclusion.save
82
+
83
+ tutorial_another_snip = app.snip(:name => 'tutorial-another-snip')
84
+ tutorial_another_snip.content = "this is another snip!"
85
+ tutorial_another_snip.save
86
+
87
+ hello_world = app.snip(:name => 'hello_world', :render_as => "Ruby")
88
+ hello_world.content = <<-END_OF_RUBY
89
+ class HelloWorld
90
+ # although the name doesn't need to match the snip name,
91
+ # it's simple to follow that convention where appropriate
92
+
93
+ def handle(name=nil)
94
+ if name
95
+ "Hey \#{name} - Hello World!"
96
+ else
97
+ "Hello World!"
98
+ end
99
+ end
100
+
101
+ # note that this code must evaluate to a class. One way of achieving that is by
102
+ # putting 'self' at the end of the class definition.
103
+ self
104
+ end
105
+ # Another way is by referring to the class at the end of the content. Either works fine.
106
+ HelloWorld
107
+ END_OF_RUBY
108
+ hello_world.save
109
+
110
+ snip = app.snip(:name => 'snip', :render_as => "Markdown")
111
+ snip.content = <<-EOS
112
+ A snip is the basic building block of information for {link_to vanilla-rb}. Essentially, it is a piece of content with arbitrary attributes. Vanilla anticipates the presence of some key attributes:
113
+
114
+ * `name` - the name of the snip, which is how it will be referred to. The `name` of this snip is _snip_.
115
+ * `content` - the default part of the snip to render. You can see the `content` of this snip <a href="/snip/content.raw">here</a>.
116
+ * `render_as` - the name of the renderer to use when rendering the content. The `render_as` of this snip is {snip.render_as}.
117
+
118
+ One implementation of the snip store is {link_to soup}.
119
+ EOS
120
+ snip.save
121
+
122
+ soup = app.snip(:name => 'soup')
123
+ soup.content = <<-EOS
124
+ Soup is a data store supporting the {link_to snip}-space that {link_to vanilla-rb} expects.
125
+
126
+ It's hosted on github <a href="http://github.com/lazyatom/soup">here</a>.
127
+ EOS
128
+ soup.save
129
+
130
+ vanilla_rb = app.snip(:name => 'vanilla-rb', :render_as => "Markdown")
131
+ vanilla_rb.content = <<-EOS
132
+ Vanilla.rb is the software powering this site. It's a sort-of wiki/bliki thing, based on {link_to vanilla}.
133
+
134
+ Here's the [introductory blog post][3].
135
+
136
+ It's developed on [github][1], and has a [lighthouse bug tracker][2]. At the moment it's not very well documented, since I'm exploring how the concept might work and the internals are subject to change. However, please do play around with it.
137
+
138
+ Here's the tutorial (helpfully included from {link_to vanilla-rb-tutorial}).
139
+
140
+ {vanilla-rb-tutorial}
141
+
142
+
143
+ [1]: http://github.com/lazyatom/vanilla
144
+ [2]: http://lazyatom.lighthouseapp.com/projects/11797-vanilla/tickets
145
+ [3]: http://interblah.net/introducing-vanilla-rb
146
+ EOS
147
+ vanilla_rb.save
148
+
149
+ vanilla = app.snip(:name => 'vanilla', :render_as => "Markdown")
150
+ vanilla.content = <<-EOS
151
+ The bliki upon which {link_to vanilla-rb} is based, writen by [Christian Langreiter][1]
152
+
153
+ [Official Web HQ][2]
154
+
155
+ [1]: http://www.langreiter.com
156
+ [2]: http://www.vanillasite.at
157
+ EOS
158
+ vanilla.save
159
+
160
+ test = app.snip(:name => "test")
161
+ test.content =<<EOF
162
+ Linking is good: {link_to bold}
163
+ Here's a bold snip: {bold}
164
+
165
+ - Here's a random number between 5 and 15: {rand 5,15}
166
+ - Here's a random number between 1 and 90 (the default min): {rand 90}
167
+ - Here's a random number between 1 and 100 (the default range): {rand}
168
+
169
+ And lets include some textile:
170
+
171
+ {textile_example}
172
+
173
+ The source for that was
174
+
175
+ {pre textile_example}
176
+
177
+ And lets include some markdown!:
178
+
179
+ {markdown_example}
180
+
181
+ The source for that was
182
+
183
+ {pre markdown_example}
184
+
185
+ How about some {link_to debug} information: {debug}
186
+
187
+ What about a missing snip? Lets try to include one: {monkey}
188
+
189
+ And an error when running? {bad_dynasnip}
190
+
191
+ EOF
192
+ test.render_as = "Markdown"
193
+ test.save
194
+
195
+ bold = app.snip(:name => "bold")
196
+ bold.content =<<EOF
197
+ Snip2 in da house!
198
+ EOF
199
+ bold.render_as = "Bold"
200
+ bold.save
201
+
202
+ textile = app.snip(:name => "textile_example")
203
+ textile.content =<<EOF
204
+
205
+ # testing lists
206
+ # because lists are common things
207
+
208
+ monkey
209
+
210
+ what the *hell* are __you__ looking at?
211
+
212
+ "Beyotch":http://example.com
213
+
214
+ EOF
215
+ textile.render_as = "Textile"
216
+ textile.save
217
+
218
+ textile = app.snip(:name => "markdown_example")
219
+ textile.content =<<EOF
220
+
221
+ # testing header
222
+
223
+ so, how are you?
224
+
225
+ - item one
226
+ - item two
227
+ - item three
228
+
229
+
230
+ what the *hell* are looking at, [beyotch](http://example.com)?
231
+ EOF
232
+ textile.render_as = "Markdown"
233
+ textile.save
234
+
235
+ bad_dynasnip = app.snip(:name => "bad_dynasnip", :render_as => "Ruby")
236
+ bad_dynasnip.content = <<EOF
237
+ class BadDynasnip
238
+ def get(*args)
239
+ raise "Oh no"
240
+ end
241
+ end
242
+ BadDynasnip
243
+ EOF
244
+ bad_dynasnip.save