vanilla 1.0.2 → 1.2

Sign up to get free protection for your applications and to get access to all the features.
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