vanilla 1.0.2 → 1.2

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 (105) hide show
  1. data/Rakefile +112 -109
  2. data/bin/vanilla +35 -6
  3. data/lib/vanilla.rb +10 -14
  4. data/lib/vanilla/app.rb +109 -41
  5. data/lib/vanilla/console.rb +22 -2
  6. data/lib/vanilla/dynasnip.rb +4 -36
  7. data/lib/vanilla/renderers.rb +12 -0
  8. data/lib/vanilla/renderers/base.rb +58 -34
  9. data/lib/vanilla/renderers/bold.rb +0 -2
  10. data/lib/vanilla/renderers/erb.rb +1 -3
  11. data/lib/vanilla/renderers/haml.rb +13 -0
  12. data/lib/vanilla/renderers/markdown.rb +0 -2
  13. data/lib/vanilla/renderers/raw.rb +0 -2
  14. data/lib/vanilla/renderers/ruby.rb +12 -6
  15. data/lib/vanilla/renderers/textile.rb +0 -2
  16. data/lib/vanilla/request.rb +19 -17
  17. data/lib/vanilla/routes.rb +9 -20
  18. data/lib/vanilla/snip_reference_parser.rb +94 -0
  19. data/lib/vanilla/static.rb +28 -0
  20. data/pristine_app/Gemfile +3 -0
  21. data/pristine_app/Gemfile.lock +32 -0
  22. data/pristine_app/README +47 -0
  23. data/pristine_app/config.ru +26 -0
  24. data/pristine_app/public/vanilla.css +15 -0
  25. data/pristine_app/soups/base/layout.snip +18 -0
  26. data/pristine_app/soups/base/start.snip +19 -0
  27. data/pristine_app/soups/dynasnips/current_snip.rb +29 -0
  28. data/{lib/vanilla → pristine_app/soups}/dynasnips/debug.rb +5 -3
  29. data/pristine_app/soups/dynasnips/index.rb +12 -0
  30. data/{lib/vanilla → pristine_app/soups}/dynasnips/link_to.rb +4 -2
  31. data/pristine_app/soups/dynasnips/link_to_current_snip.rb +14 -0
  32. data/pristine_app/soups/dynasnips/page_title.rb +9 -0
  33. data/{lib/vanilla → pristine_app/soups}/dynasnips/pre.rb +7 -5
  34. data/{lib/vanilla → pristine_app/soups}/dynasnips/raw.rb +8 -5
  35. data/pristine_app/soups/extras/comments.rb +78 -0
  36. data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/kind.rb +19 -17
  37. data/{lib/vanilla/dynasnips → pristine_app/soups/extras}/rand.rb +2 -0
  38. data/pristine_app/soups/extras/url_to.rb +7 -0
  39. data/pristine_app/soups/tutorial/bad_dynasnip.snip +8 -0
  40. data/pristine_app/soups/tutorial/hello_world.snip +20 -0
  41. data/pristine_app/soups/tutorial/markdown_example.snip +13 -0
  42. data/pristine_app/soups/tutorial/snip.snip +9 -0
  43. data/pristine_app/soups/tutorial/soup.snip +3 -0
  44. data/pristine_app/soups/tutorial/test.snip +30 -0
  45. data/pristine_app/soups/tutorial/textile_example.snip +11 -0
  46. data/pristine_app/soups/tutorial/tutorial-another-snip.snip +1 -0
  47. data/pristine_app/soups/tutorial/tutorial-basic-snip-inclusion.snip +1 -0
  48. data/pristine_app/soups/tutorial/tutorial-dynasnips.snip.markdown +56 -0
  49. data/pristine_app/soups/tutorial/tutorial-layout.snip +56 -0
  50. data/pristine_app/soups/tutorial/tutorial-links.snip +4 -0
  51. data/pristine_app/soups/tutorial/tutorial-renderers.snip.markdown +77 -0
  52. data/pristine_app/soups/tutorial/tutorial.snip.markdown +69 -0
  53. data/pristine_app/soups/tutorial/vanilla-rb.snip +16 -0
  54. data/pristine_app/soups/tutorial/vanilla.snip +8 -0
  55. data/test/dynasnip_test.rb +42 -0
  56. data/test/dynasnips/link_to_current_snip_test.rb +19 -0
  57. data/test/dynasnips/link_to_test.rb +27 -0
  58. data/test/dynasnips/page_title_test.rb +19 -0
  59. data/test/renderers/base_renderer_test.rb +43 -0
  60. data/test/renderers/erb_renderer_test.rb +29 -0
  61. data/test/renderers/haml_renderer_test.rb +35 -0
  62. data/test/renderers/markdown_renderer_test.rb +31 -0
  63. data/test/renderers/raw_renderer_test.rb +23 -0
  64. data/test/renderers/ruby_renderer_test.rb +59 -0
  65. data/test/snip_inclusion_test.rb +56 -0
  66. data/test/snip_reference_parser_test.rb +123 -0
  67. data/test/test_helper.rb +75 -0
  68. data/test/vanilla_app_test.rb +83 -0
  69. data/test/vanilla_presenting_test.rb +125 -0
  70. data/test/vanilla_request_test.rb +87 -0
  71. metadata +179 -78
  72. data/config.example.yml +0 -5
  73. data/config.ru +0 -9
  74. data/lib/defensio.rb +0 -59
  75. data/lib/tasks/vanilla.rake +0 -177
  76. data/lib/vanilla/dynasnips/comments.rb +0 -108
  77. data/lib/vanilla/dynasnips/current_snip.rb +0 -32
  78. data/lib/vanilla/dynasnips/edit.rb +0 -63
  79. data/lib/vanilla/dynasnips/edit_link.rb +0 -24
  80. data/lib/vanilla/dynasnips/index.rb +0 -11
  81. data/lib/vanilla/dynasnips/link_to_current_snip.rb +0 -16
  82. data/lib/vanilla/dynasnips/login.rb +0 -56
  83. data/lib/vanilla/dynasnips/new.rb +0 -14
  84. data/lib/vanilla/dynasnips/notes.rb +0 -42
  85. data/lib/vanilla/dynasnips/url_to.rb +0 -7
  86. data/lib/vanilla/snip_handling.rb +0 -33
  87. data/lib/vanilla/snips/start.rb +0 -27
  88. data/lib/vanilla/snips/system.rb +0 -76
  89. data/lib/vanilla/snips/tutorial.rb +0 -157
  90. data/lib/vanilla/test_snips.rb +0 -85
  91. data/public/hatch.png +0 -0
  92. data/public/javascripts/jquery.js +0 -3549
  93. data/public/javascripts/vanilla.js +0 -21
  94. data/spec/dynasnip_spec.rb +0 -31
  95. data/spec/renderers/base_renderer_spec.rb +0 -40
  96. data/spec/renderers/erb_renderer_spec.rb +0 -27
  97. data/spec/renderers/markdown_renderer_spec.rb +0 -29
  98. data/spec/renderers/raw_renderer_spec.rb +0 -21
  99. data/spec/renderers/ruby_renderer_spec.rb +0 -42
  100. data/spec/renderers/vanilla_app_detecting_renderer_spec.rb +0 -35
  101. data/spec/spec_helper.rb +0 -64
  102. data/spec/vanilla_app_spec.rb +0 -38
  103. data/spec/vanilla_presenting_spec.rb +0 -84
  104. data/spec/vanilla_request_spec.rb +0 -73
  105. data/spec/vanilla_snip_finding_spec.rb +0 -28
@@ -0,0 +1,94 @@
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
18
+ end
19
+
20
+ def parse(string)
21
+ Reference.new(SnipTransform.new.apply(SnipParser.new.parse(string)))
22
+ 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
42
+ 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) }
63
+
64
+ rule(:arguments) { hash_arg_list | named_arg_list | string_arg_list }
65
+ rule(:snip_part) { string.as(:snip) >> (dot >> string.as(:attribute)).maybe }
66
+
67
+ rule(:snip_reference) do
68
+ left_brace >> spaces? >>
69
+ snip_part >> (spaces >> arguments.as(:arguments)).maybe >>
70
+ spaces? >> right_brace
71
+ end
72
+
73
+ root(:snip_reference)
74
+ end
75
+
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 }
82
+
83
+ class Arg
84
+ def initialize(k, v); @k, @v = k, v; end
85
+ def to_h; {@k.to_sym => @v}; end
86
+ 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
+ end
93
+ end
94
+ end
@@ -0,0 +1,28 @@
1
+ require 'rack/utils'
2
+
3
+ # Heavily based on ActionDispatch::Static
4
+ module Vanilla
5
+ class Static
6
+ def initialize(app, root)
7
+ @app = app
8
+ @file_server = ::Rack::File.new(root)
9
+ end
10
+
11
+ def call(env)
12
+ path = env['PATH_INFO'].chomp('/')
13
+ method = env['REQUEST_METHOD']
14
+
15
+ if %w(GET HEAD).include?(method) && file_exist?(path)
16
+ @file_server.call(env)
17
+ else
18
+ @app.call(env)
19
+ end
20
+ end
21
+
22
+ private
23
+ def file_exist?(path)
24
+ full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path))
25
+ File.file?(full_path) && File.readable?(full_path)
26
+ end
27
+ end
28
+ end
@@ -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.14.1)
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.1.1)
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,47 @@
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
+ Editing snips
20
+ -------------
21
+ You can edit any file in the soup directory using your favourite editor,
22
+ and the changes will be reflected automatically. The snip files are
23
+ slightly modified YAML files. Here's an example, which you might save
24
+ in a file called 'soup.snip':
25
+
26
+
27
+ Soup is a data store supporting the {link_to snip}-space that
28
+ {link_to vanilla-rb} expects.
29
+
30
+ It's hosted on github [here](http://github.com/lazyatom/soup).
31
+
32
+ :created_at: 2011-05-23 14:14:16 +01:00
33
+ :updated_at: 2009-05-23 15:23:22 +01:00
34
+ :render_as: Markdown
35
+
36
+
37
+ The 'content' of the snip is at the top of the file, followed by the
38
+ rest of the snip attributes on lines starting with ':'.
39
+
40
+
41
+ The console
42
+ -----------
43
+
44
+ Within a vanilla app directory, you can run `vanilla console` to start
45
+ an IRB session and interact with your app and snips. The `app` method
46
+ returns your application object, and `app.soup['start']` will return
47
+ the start snip from your soup(s).
@@ -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 app.request.snip
18
+ if attribute ||= app.request.part
19
+ "{#{app.request.snip_name}.#{attribute}}"
20
+ else
21
+ "{#{app.request.snip_name}}"
22
+ end
23
+ else
24
+ app.response.status = 404
25
+ %{Couldn't find snip "#{app.request.snip_name}"}
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
@@ -0,0 +1,12 @@
1
+ require 'vanilla/dynasnip'
2
+
3
+ class Index < Dynasnip
4
+ def get(*args)
5
+ list = app.soup.instance_eval { @backend }.send(:all_snips).sort_by { |a| a.updated_at || Time.at(0) }.reverse.map { |snip|
6
+ "<li>#{link_to snip.name}</li>"
7
+ }
8
+ "<ol>#{list}</ol>"
9
+ end
10
+
11
+ self
12
+ end
@@ -8,7 +8,9 @@ The link_to dyna lets you create links between snips:
8
8
 
9
9
  would insert a link to the blah snip.|
10
10
 
11
- def handle(snip_name)
12
- Vanilla.snip_exists?(snip_name) ? Vanilla::Routes.link_to(snip_name) : Vanilla::Routes.new_link(snip_name)
11
+ def handle(snip_name, link_text=snip_name, part=nil)
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
- %{<pre>#{Vanilla.snip(snip_name).__send__(part || :content)}</pre>}
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(Vanilla.snip(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