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
@@ -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