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
@@ -1,3 +1,23 @@
1
1
  require 'vanilla'
2
- Soup.prepare
3
- puts "The Soup is simmering."
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
16
+
17
+ def app(reload=false)
18
+ if !@__vanilla_console_app || reload
19
+ shim_binding = Vanilla::RackShim.new.get_binding
20
+ @__vanilla_console_app = eval File.read("config.ru"), shim_binding
21
+ end
22
+ @__vanilla_console_app
23
+ end
@@ -29,48 +29,16 @@ class Dynasnip < Vanilla::Renderers::Base
29
29
  attribute :usage, escape_curly_braces(str).strip
30
30
  end
31
31
 
32
- def self.persist_all!(overwrite=false)
33
- all.each do |dynasnip|
34
- dynasnip.persist!(overwrite)
35
- end
36
- end
37
-
38
- def self.build_snip
39
- Snip.new(snip_attributes)
40
- end
41
-
42
32
  def self.snip_attributes
43
33
  full_snip_attributes = {:name => snip_name, :content => self.name, :render_as => "Ruby"}
44
34
  @attributes ? full_snip_attributes.merge!(@attributes) : full_snip_attributes
45
35
  end
46
36
 
47
- def self.persist!(overwrite=false)
48
- if overwrite
49
- snip = Soup[snip_name]
50
- if snip
51
- if snip.is_a?(Array)
52
- snip.each { |s| s.destroy }
53
- else
54
- snip.destroy
55
- end
56
- end
57
- end
58
- snip = Soup[snip_name]
59
- snip = snip[0] if snip.is_a?(Array)
60
- if snip
61
- snip_attributes.each do |name, value|
62
- snip.set_value(name, value)
63
- end
64
- else
65
- snip = build_snip
66
- end
67
- snip.save
68
- snip
69
- end
37
+ attr_accessor :enclosing_snip
70
38
 
71
39
  def method_missing(method, *args)
72
- if snip = Vanilla.snip(snip_name)
73
- snip.get_value(method)
40
+ if snip
41
+ snip.__send__(method)
74
42
  elsif part = self.class.attribute(method)
75
43
  part
76
44
  else
@@ -88,7 +56,7 @@ class Dynasnip < Vanilla::Renderers::Base
88
56
  end
89
57
 
90
58
  def snip
91
- Snip[snip_name]
59
+ app.soup[snip_name]
92
60
  end
93
61
 
94
62
  def show_usage
@@ -0,0 +1,12 @@
1
+ module Vanilla
2
+ module Renderers
3
+ autoload :Base, "vanilla/renderers/base"
4
+ autoload :Bold, "vanilla/renderers/bold"
5
+ autoload :Erb, "vanilla/renderers/erb"
6
+ autoload :Haml, "vanilla/renderers/haml"
7
+ autoload :Markdown, "vanilla/renderers/markdown"
8
+ autoload :Raw, "vanilla/renderers/raw"
9
+ autoload :Ruby, "vanilla/renderers/ruby"
10
+ autoload :Textile, "vanilla/renderers/textile"
11
+ end
12
+ end
@@ -1,74 +1,98 @@
1
- require 'vanilla/app'
1
+ require 'vanilla/snip_reference_parser'
2
2
 
3
3
  module Vanilla
4
4
  module Renderers
5
5
  class Base
6
-
6
+ include Routes
7
+
7
8
  # Render a snip.
8
9
  def self.render(snip, part=:content)
9
10
  new(app).render(snip, part)
10
11
  end
11
-
12
+
12
13
  def self.escape_curly_braces(str)
13
14
  str.gsub("{", "&#123;").gsub("}", "&#125;")
14
15
  end
15
-
16
+
16
17
  attr_reader :app
17
-
18
+
18
19
  def initialize(app)
19
20
  @app = app
20
21
  end
21
-
22
+
23
+ # defined for the routes
24
+ def soup
25
+ @app.soup
26
+ end
27
+
22
28
  def self.snip_regexp
23
- %r{ \{
24
- ([\w\-]+) (?: \.([\w\-]+) )?
25
- (?: \s+ ([\w\-,]+) )?
26
- \} }x
29
+ %r{(\{[\w\-_\d\.\"\'\s]+(\s+[^\}.]+)?\})}
30
+ end
31
+
32
+ def default_layout_snip
33
+ app.default_layout_snip
34
+ end
35
+
36
+ def layout_for(snip)
37
+ layout_snip = (snip && snip.layout) ? soup[snip.layout] : default_layout_snip
27
38
  end
28
-
39
+
29
40
  # Default behaviour to include a snip's content
30
- def include_snips(content)
41
+ def include_snips(content, enclosing_snip)
31
42
  content.gsub(Vanilla::Renderers::Base.snip_regexp) do
32
- snip_name = $1
33
- snip_attribute = $2
34
- snip_args = $3 ? $3.split(',') : []
35
-
36
- # Render the snip or snip part with the given args, and the current
37
- # context, but with the default renderer for that snip. We dispatch
38
- # *back* out to the root Vanilla.render method to do this.
39
- snip = Vanilla.snip(snip_name)
40
- if snip
41
- app.render(snip, snip_attribute, snip_args)
43
+ snip_tree = parse_snip_reference($1)
44
+ if snip_tree
45
+ snip_name = snip_tree.snip
46
+ snip_attribute = snip_tree.attribute
47
+ snip_args = snip_tree.arguments
48
+
49
+ # Render the snip or snip part with the given args, and the current
50
+ # context, but with the default renderer for that snip. We dispatch
51
+ # *back* out to the root Vanilla.render method to do this.
52
+ if snip = soup[snip_name]
53
+ app.render(snip, snip_attribute, snip_args, enclosing_snip)
54
+ else
55
+ render_missing_snip(snip_name)
56
+ end
42
57
  else
43
- app.render_missing_snip(snip_name)
58
+ "malformed snip reference: #{$1.inspect}"
44
59
  end
45
60
  end
46
61
  end
47
-
62
+
63
+ def parse_snip_reference(string)
64
+ @parser ||= Vanilla::SnipReferenceParser.new
65
+ @parser.parse(string)
66
+ end
67
+
68
+ def render_missing_snip(snip_name)
69
+ "[snip '#{snip_name}' cannot be found]"
70
+ end
71
+
48
72
  # Default rendering behaviour. Subclasses shouldn't really need to touch this.
49
- def render(snip, part=:content, args=[])
50
- prepare(snip, part, args)
73
+ def render(snip, part=:content, args=[], enclosing_snip=snip)
74
+ prepare(snip, part, args, enclosing_snip)
51
75
  processed_text = render_without_including_snips(snip, part)
52
- include_snips(processed_text)
76
+ include_snips(processed_text, snip)
53
77
  end
54
-
78
+
55
79
  # Subclasses should override this to perform any actions required before
56
80
  # rendering
57
- def prepare(snip, part, args)
81
+ def prepare(snip, part, args, enclosing_snip)
58
82
  # do nothing, by default
59
83
  end
60
-
84
+
61
85
  def render_without_including_snips(snip, part=:content)
62
86
  process_text(raw_content(snip, part))
63
87
  end
64
-
65
- # Handles processing the text of the content.
66
- # Subclasses should override this method to do fancy text processing
88
+
89
+ # Handles processing the text of the content.
90
+ # Subclasses should override this method to do fancy text processing
67
91
  # like markdown, or loading the content as Ruby code.
68
92
  def process_text(content)
69
93
  content
70
94
  end
71
-
95
+
72
96
  # Returns the raw content for the selected part of the selected snip
73
97
  def raw_content(snip, part)
74
98
  snip.__send__((part || :content).to_sym)
@@ -1,5 +1,3 @@
1
- require 'vanilla/renderers/base'
2
-
3
1
  module Vanilla::Renderers
4
2
  class Bold < Base
5
3
  def process_text(content)
@@ -1,11 +1,9 @@
1
- require 'vanilla/renderers/base'
2
-
3
1
  require 'erb'
4
2
  include ERB::Util
5
3
 
6
4
  module Vanilla::Renderers
7
5
  class Erb < Base
8
- def prepare(snip, part=:content, args=[])
6
+ def prepare(snip, part=:content, args=[], enclosing_snip=snip)
9
7
  @snip = snip
10
8
  end
11
9
 
@@ -0,0 +1,13 @@
1
+ require 'haml'
2
+
3
+ module Vanilla::Renderers
4
+ class Haml < Base
5
+ def prepare(snip, part=:content, args=[], enclosing_snip=snip)
6
+ @snip = snip
7
+ end
8
+
9
+ def process_text(content)
10
+ ::Haml::Engine.new(content).render(binding)
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,3 @@
1
- require 'vanilla/renderers/base'
2
-
3
1
  require 'rubygems'
4
2
  gem 'BlueCloth' # from http://www.deveiate.org/projects/BlueCloth
5
3
  require 'bluecloth'
@@ -1,5 +1,3 @@
1
- require 'vanilla/renderers/base'
2
-
3
1
  module Vanilla::Renderers
4
2
  class Raw < Base
5
3
  def render(snip, part=:content)
@@ -1,5 +1,3 @@
1
- require 'vanilla/renderers/base'
2
-
3
1
  module Vanilla::Renderers
4
2
  # Snips that render_as "Ruby" should define a class.
5
3
  # The class should have instance methods for any HTTP request methods that the dynasnip
@@ -13,9 +11,10 @@ module Vanilla::Renderers
13
11
  # itself), it should be a subclass of Dynasnip (or define an initializer
14
12
  # that accepts the context as its first argument).
15
13
  class Ruby < Base
16
- def prepare(snip, part=:content, args=[])
14
+ def prepare(snip, part=:content, args=[], enclosing_snip=snip)
17
15
  @args = args
18
16
  @snip = snip
17
+ @enclosing_snip = enclosing_snip
19
18
  end
20
19
 
21
20
  def process_text(content)
@@ -25,10 +24,17 @@ module Vanilla::Renderers
25
24
  else
26
25
  handler_klass.new
27
26
  end
28
- if (method = app.request.method) && instance.respond_to?(method)
29
- instance.send(method, *@args).to_s
27
+ instance.enclosing_snip = @enclosing_snip if instance.respond_to?(:enclosing_snip)
28
+
29
+ if app.request && (method = app.request.method) && instance.respond_to?(method)
30
+ message = method
31
+ else
32
+ message = :handle
33
+ end
34
+ if @args.is_a?(Array)
35
+ instance.send(message, *@args).to_s
30
36
  else
31
- instance.handle(*@args).to_s
37
+ instance.send(message, @args).to_s
32
38
  end
33
39
  end
34
40
  end
@@ -1,5 +1,3 @@
1
- require 'vanilla/renderers/base'
2
-
3
1
  require 'rubygems'
4
2
  gem 'RedCloth'
5
3
  require 'redcloth'
@@ -4,10 +4,12 @@ module Vanilla
4
4
  # Create a request with symbolised access to the params, and some special
5
5
  # accessors to the snip, part and format based on our routing.
6
6
  class Request
7
- attr_reader :snip_name, :part, :format, :method
8
-
9
- def initialize(env)
7
+ attr_reader :snip_name, :part, :format, :method, :env
8
+
9
+ def initialize(env, app)
10
+ @env = env
10
11
  @rack_request = Rack::Request.new(env)
12
+ @app = app
11
13
  determine_request_uri_parts
12
14
  end
13
15
 
@@ -15,46 +17,46 @@ module Vanilla
15
17
  # Don't you just love how terse functional programming tends to look like maths?
16
18
  @symbolised_params ||= @rack_request.params.inject({}) { |p, (k,v)| p[k.to_sym] = v; p }
17
19
  end
18
-
20
+
19
21
  # Returns the snip referenced by the request's URL. Performs no exception
20
22
  # handling, so if the snip does not exist, an exception will be thrown.
21
23
  def snip
22
- Vanilla.snip(snip_name)
24
+ @app.soup[snip_name]
23
25
  end
24
-
26
+
25
27
  def cookies
26
28
  @rack_request.cookies
27
29
  end
28
-
30
+
29
31
  def ip
30
32
  @rack_request.env["REMOTE_ADDR"]
31
33
  end
32
-
34
+
33
35
  def session
34
36
  @rack_request.env["rack.session"]
35
37
  end
36
-
38
+
37
39
  private
38
-
40
+
39
41
  def determine_request_uri_parts
40
42
  @snip_name, @part, @format = request_uri_parts(@rack_request)
41
43
  @format ||= 'html'
42
44
  @method = (params.delete(:_method) || @rack_request.request_method).downcase
43
45
  end
44
-
46
+
45
47
  def uri_path(request)
46
48
  request.path_info
47
49
  end
48
-
49
- URL_ROOT = /\A\/\Z/ # i.e. /
50
+
51
+ URL_ROOT = /\A\/?\Z/ # i.e. / or nothing
50
52
  URL_SNIP = /\A\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /start, /start.html
51
53
  URL_SNIP_AND_PART = /\A\/([\w\-\s]+)\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /blah/part, /blah/part.raw
52
-
54
+
53
55
  # Returns an array of the requested snip, part and format
54
56
  def request_uri_parts(request)
55
57
  case CGI.unescape(uri_path(request))
56
58
  when URL_ROOT
57
- ['start', nil, 'html']
59
+ [@app.config[:root_snip] || 'start', nil, 'html']
58
60
  when URL_SNIP
59
61
  [$1, nil, $3]
60
62
  when URL_SNIP_AND_PART
@@ -63,6 +65,6 @@ module Vanilla
63
65
  []
64
66
  end
65
67
  end
66
-
68
+
67
69
  end
68
- end
70
+ end
@@ -1,29 +1,18 @@
1
1
  module Vanilla
2
+ # Expects to be able to call 'soup' on whatever it is included into
2
3
  module Routes
3
4
  def link_to(link_text, snip_name=link_text, part=nil)
4
- %{<a href="#{Vanilla::Routes.url_to(snip_name, part)}">#{link_text}</a>}
5
+ if soup[snip_name]
6
+ %{<a href="#{url_to(snip_name, part)}">#{link_text}</a>}
7
+ else
8
+ %{<a class="missing" href="#{url_to(snip_name, part)}">#{link_text}</a>}
9
+ end
5
10
  end
6
-
11
+
7
12
  def url_to(snip_name, part=nil)
8
- url = "/#{snip_name}"
13
+ url = "/#{snip_name.gsub(" ", "+")}"
9
14
  url += "/#{part}" if part
10
15
  url
11
16
  end
12
-
13
- def url_to_raw(snip_name, part=nil)
14
- url = "/#{snip_name}"
15
- url += "/#{part}" if part
16
- url += ".raw"
17
- end
18
-
19
- def edit_link(snip_name, link_text)
20
- %[<a href="/edit?name=#{snip_name}">#{link_text}</a>]
21
- end
22
-
23
- def new_link(snip_name="New")
24
- %[<a href="/new?name=#{snip_name}" class="new">#{snip_name}</a>]
25
- end
26
-
27
- extend self
28
17
  end
29
- end
18
+ end