vanilla 1.17 → 1.17.1
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.
- data/Rakefile +21 -7
- data/bin/vanilla +2 -2
- data/lib/vanilla.rb +10 -7
- data/lib/vanilla/app.rb +57 -97
- data/lib/vanilla/config.rb +46 -0
- data/lib/vanilla/console.rb +1 -1
- data/lib/vanilla/renderers/base.rb +12 -2
- data/lib/vanilla/request.rb +9 -34
- data/lib/vanilla/routing.rb +34 -0
- data/lib/vanilla/test_helper.rb +10 -7
- data/pristine_app/Gemfile.lock +35 -0
- data/pristine_app/application.rb +2 -4
- data/pristine_app/public/vanilla.css +299 -9
- data/pristine_app/soups/base/layout.snip +11 -7
- data/pristine_app/soups/base/start.snip +15 -14
- data/pristine_app/soups/system/current_snip.rb +2 -2
- data/pristine_app/soups/system/feed.rb +30 -0
- data/pristine_app/soups/system/index.rb +3 -3
- data/pristine_app/soups/system/link_to.rb +5 -1
- data/pristine_app/soups/system/link_to_current_snip.rb +2 -3
- data/pristine_app/soups/tutorial/tutorial-layout.snip +9 -2
- data/pristine_app/soups/tutorial/tutorial-links.snip +2 -1
- data/pristine_app/soups/tutorial/tutorial-removing.snip.markdown +8 -0
- data/pristine_app/soups/tutorial/tutorial-renderers.snip.markdown +10 -4
- data/pristine_app/soups/tutorial/tutorial.snip.markdown +0 -1
- data/pristine_app/soups/tutorial/vanilla-rb.snip +4 -6
- data/pristine_app/tmp/restart.txt +0 -0
- data/test/core/configuration_test.rb +89 -0
- data/test/{dynasnip_test.rb → core/dynasnip_test.rb} +0 -0
- data/test/{renderers → core/renderers}/base_renderer_test.rb +37 -0
- data/test/{renderers → core/renderers}/erb_renderer_test.rb +0 -0
- data/test/{renderers → core/renderers}/haml_renderer_test.rb +0 -0
- data/test/{renderers → core/renderers}/markdown_renderer_test.rb +0 -0
- data/test/{renderers → core/renderers}/raw_renderer_test.rb +0 -0
- data/test/{renderers → core/renderers}/ruby_renderer_test.rb +0 -0
- data/test/core/routing_test.rb +30 -0
- data/test/{snip_inclusion_test.rb → core/snip_inclusion_test.rb} +0 -0
- data/test/{snip_reference_parser_test.rb → core/snip_reference_parser_test.rb} +0 -0
- data/test/{test_helper.rb → core/test_helper.rb} +5 -4
- data/test/core/vanilla_app_test.rb +51 -0
- data/test/{vanilla_presenting_test.rb → core/vanilla_presenting_test.rb} +15 -1
- data/test/{vanilla_request_test.rb → core/vanilla_request_test.rb} +0 -0
- data/test/pristine_app/current_snip_test.rb +46 -0
- data/test/pristine_app/feed_test.rb +47 -0
- data/test/pristine_app/index_test.rb +34 -0
- data/test/pristine_app/link_to_current_snip_test.rb +11 -0
- data/test/pristine_app/link_to_test.rb +27 -0
- data/test/pristine_app/page_title_test.rb +15 -0
- data/test/pristine_app/raw_test.rb +24 -0
- data/test/pristine_app/test_helper.rb +25 -0
- metadata +83 -42
- data/lib/vanilla/routes.rb +0 -18
- data/test/dynasnips/link_to_current_snip_test.rb +0 -19
- data/test/dynasnips/link_to_test.rb +0 -27
- data/test/dynasnips/page_title_test.rb +0 -19
- data/test/vanilla_app_test.rb +0 -111
data/Rakefile
CHANGED
@@ -7,12 +7,24 @@ require "vanilla"
|
|
7
7
|
|
8
8
|
task :default => :test
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
task :test => ["test:core", "test:app"]
|
11
|
+
|
12
|
+
namespace :test do
|
13
|
+
require "rake/testtask"
|
14
|
+
Rake::TestTask.new(:core) do |t|
|
15
|
+
t.libs << "test/core"
|
16
|
+
t.ruby_opts << "-rubygems"
|
17
|
+
t.test_files = FileList["test/core/**/*_test.rb"]
|
18
|
+
t.verbose = true
|
19
|
+
end
|
20
|
+
|
21
|
+
require "rake/testtask"
|
22
|
+
Rake::TestTask.new(:app) do |t|
|
23
|
+
t.libs << "test/pristine_app"
|
24
|
+
t.ruby_opts << "-rubygems"
|
25
|
+
t.test_files = FileList["test/pristine_app/**/*_test.rb"]
|
26
|
+
t.verbose = true
|
27
|
+
end
|
16
28
|
end
|
17
29
|
|
18
30
|
if Object.const_defined?(:Gem)
|
@@ -42,7 +54,7 @@ if Object.const_defined?(:Gem)
|
|
42
54
|
|
43
55
|
# All the other gems we need.
|
44
56
|
s.add_dependency("rack", ">= 0.9.1")
|
45
|
-
s.add_dependency("soup", ">= 1.0.
|
57
|
+
s.add_dependency("soup", ">= 1.0.8")
|
46
58
|
s.add_dependency("ratom", ">= 0.3.5")
|
47
59
|
s.add_dependency("RedCloth", ">= 4.1.1")
|
48
60
|
s.add_dependency("BlueCloth", ">= 1.0.0")
|
@@ -52,6 +64,8 @@ if Object.const_defined?(:Gem)
|
|
52
64
|
|
53
65
|
s.add_development_dependency("kintama", ">= 0.1.6") # add any other gems for testing/development
|
54
66
|
s.add_development_dependency("mocha")
|
67
|
+
s.add_development_dependency("capybara")
|
68
|
+
s.add_development_dependency("launchy")
|
55
69
|
|
56
70
|
# If you want to publish automatically to rubyforge, you'll may need
|
57
71
|
# to tweak this, and the publishing task below too.
|
data/bin/vanilla
CHANGED
@@ -15,10 +15,10 @@ end
|
|
15
15
|
def upgrade
|
16
16
|
require 'fileutils'
|
17
17
|
soups_directory = File.join(Dir.pwd, "soups")
|
18
|
-
if File.directory(soups_directory)
|
18
|
+
if File.directory?(soups_directory)
|
19
19
|
confirm("Upgrade system snips?") do
|
20
20
|
pristine_system = File.expand_path("../../pristine_app/soups/system", __FILE__)
|
21
|
-
copy(pristine_system,
|
21
|
+
copy(pristine_system, soups_directory)
|
22
22
|
end
|
23
23
|
confirm("Upgrade tutorial snips?") do
|
24
24
|
pristine_system = File.expand_path("../../pristine_app/soups/tutorial", __FILE__)
|
data/lib/vanilla.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
module Vanilla
|
2
|
-
VERSION = "1.17"
|
2
|
+
VERSION = "1.17.1"
|
3
3
|
|
4
4
|
autoload :Renderers, "vanilla/renderers"
|
5
5
|
autoload :App, "vanilla/app"
|
6
|
+
autoload :Config, "vanilla/config"
|
6
7
|
autoload :Dynasnip, "vanilla/dynasnip"
|
7
8
|
autoload :Request, "vanilla/request"
|
8
|
-
autoload :
|
9
|
+
autoload :Routing, "vanilla/routing"
|
9
10
|
autoload :Static, "vanilla/static"
|
10
11
|
autoload :SnipReferenceParser, "vanilla/snip_reference_parser"
|
11
12
|
autoload :TestHelper, "vanilla/test_helper"
|
12
|
-
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
class << self
|
15
|
+
# The set of currently loaded Vanilla::App subclasses
|
16
|
+
def apps
|
17
|
+
@apps ||= []
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/vanilla/app.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'soup'
|
2
|
-
require 'ostruct'
|
3
2
|
|
4
3
|
module Vanilla
|
4
|
+
|
5
|
+
# This is the main App class for Vanilla applications; this should
|
6
|
+
# be subclassed for each instance of Vanilla that you want to run.
|
5
7
|
class App
|
6
|
-
include Vanilla::
|
8
|
+
include Vanilla::Routing
|
7
9
|
|
8
10
|
class << self
|
9
11
|
attr_reader :config
|
@@ -13,48 +15,23 @@ module Vanilla
|
|
13
15
|
self
|
14
16
|
end
|
15
17
|
def reset!
|
16
|
-
@config =
|
18
|
+
@config = Vanilla::Config.new
|
19
|
+
end
|
20
|
+
def inherited(app)
|
21
|
+
Vanilla.apps << app
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
20
|
-
attr_reader :request, :response, :
|
21
|
-
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
:root => self.class.config.root,
|
27
|
-
:root_snip => self.class.config.root_snip,
|
28
|
-
:renderers => self.class.config.renderers,
|
29
|
-
:default_layout_snip => self.class.config.default_layout_snip,
|
30
|
-
:default_renderer => self.class.config.default_renderer}
|
31
|
-
else
|
32
|
-
{}
|
33
|
-
end
|
25
|
+
attr_reader :request, :response, :soup
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@renderers = Hash.new { config.default_renderer }
|
29
|
+
@soup = prepare_soup
|
30
|
+
prepare_renderers
|
34
31
|
end
|
35
32
|
|
36
|
-
|
37
|
-
|
38
|
-
#
|
39
|
-
# :soup - provide the path to the soup data
|
40
|
-
# :soups - provide an array of paths to soup data
|
41
|
-
# :root - the directory that the soup paths are relative to;
|
42
|
-
# defaults to Dir.pwd
|
43
|
-
# :renderers - a hash of names to classes
|
44
|
-
# :default_renderer - the class to use when no renderer is provided;
|
45
|
-
# defaults to 'Vanilla::Renderers::Base'
|
46
|
-
# :default_layout_snip - the snip to use as a layout when rendering to HTML;
|
47
|
-
# defaults to 'layout'
|
48
|
-
# :root_snip - the snip to load for the root ('/') url;
|
49
|
-
# defaults to 'start'
|
50
|
-
def initialize(additional_configuration={})
|
51
|
-
@config = class_config.merge(additional_configuration)
|
52
|
-
@root_directory = @config[:root] || Dir.pwd
|
53
|
-
if @config[:soup].nil? && @config[:soups].nil?
|
54
|
-
@config[:soup] = File.expand_path("soup", @root_directory)
|
55
|
-
end
|
56
|
-
@soup = prepare_soup(config)
|
57
|
-
prepare_renderers(config[:renderers])
|
33
|
+
def config
|
34
|
+
self.class.config
|
58
35
|
end
|
59
36
|
|
60
37
|
# Returns a Rack-appropriate 3-element array (via Rack::Response#finish)
|
@@ -64,7 +41,7 @@ module Vanilla
|
|
64
41
|
@response = Rack::Response.new
|
65
42
|
|
66
43
|
begin
|
67
|
-
output =
|
44
|
+
output = render_in_format(request.snip, request.part, request.format)
|
68
45
|
rescue => e
|
69
46
|
@response.status = 500
|
70
47
|
output = e.to_s + e.backtrace.join("\n")
|
@@ -76,29 +53,14 @@ module Vanilla
|
|
76
53
|
@response.finish # returns the array
|
77
54
|
end
|
78
55
|
|
79
|
-
def formatted_render(snip, part=nil, format=nil)
|
80
|
-
case format
|
81
|
-
when 'html', nil
|
82
|
-
layout = layout_for(snip)
|
83
|
-
if layout == snip
|
84
|
-
"Rendering of the current layout would result in infinite recursion."
|
85
|
-
else
|
86
|
-
render(layout)
|
87
|
-
end
|
88
|
-
when 'raw', 'css', 'js'
|
89
|
-
Renderers::Raw.new(self).render(snip, part)
|
90
|
-
when 'text', 'atom', 'xml'
|
91
|
-
render(snip, part)
|
92
|
-
else
|
93
|
-
raise "Unknown format '#{format}'"
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
56
|
# render a snip using either the renderer given, or the renderer
|
98
57
|
# specified by the snip's "render_as" property, or Render::Base
|
99
58
|
# if nothing else is given.
|
59
|
+
#
|
60
|
+
# This method can be useful if a dynasnip or other part of the
|
61
|
+
# system needs to get a fully rendered version of a snip.
|
100
62
|
def render(snip, part=:content, args=[], enclosing_snip=snip)
|
101
|
-
|
63
|
+
rendering_and_handling_errors(snip) do |renderer|
|
102
64
|
renderer.render(snip, part, args, enclosing_snip)
|
103
65
|
end
|
104
66
|
end
|
@@ -108,24 +70,12 @@ module Vanilla
|
|
108
70
|
if snip
|
109
71
|
find_renderer(snip.render_as || snip.extension)
|
110
72
|
else
|
111
|
-
default_renderer
|
73
|
+
config.default_renderer
|
112
74
|
end
|
113
75
|
end
|
114
76
|
|
115
77
|
def default_layout_snip
|
116
|
-
soup[config
|
117
|
-
end
|
118
|
-
|
119
|
-
def layout_for(snip)
|
120
|
-
if snip
|
121
|
-
renderer_for(snip).new(self).layout_for(snip)
|
122
|
-
else
|
123
|
-
default_layout_snip
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def snip(attributes)
|
128
|
-
@soup << attributes
|
78
|
+
soup[config.default_layout_snip]
|
129
79
|
end
|
130
80
|
|
131
81
|
def register_renderer(klass, *types)
|
@@ -139,31 +89,15 @@ module Vanilla
|
|
139
89
|
|
140
90
|
private
|
141
91
|
|
142
|
-
def prepare_renderers
|
143
|
-
|
144
|
-
@renderers.merge!({
|
145
|
-
"base" => Vanilla::Renderers::Base,
|
146
|
-
"markdown" => Vanilla::Renderers::Markdown,
|
147
|
-
"bold" => Vanilla::Renderers::Bold,
|
148
|
-
"erb" => Vanilla::Renderers::Erb,
|
149
|
-
"rb" => Vanilla::Renderers::Ruby,
|
150
|
-
"ruby" => Vanilla::Renderers::Ruby,
|
151
|
-
"haml" => Vanilla::Renderers::Haml,
|
152
|
-
"raw" => Vanilla::Renderers::Raw,
|
153
|
-
"textile" => Vanilla::Renderers::Textile
|
154
|
-
})
|
155
|
-
additional_renderers.each { |name, klass| register_renderer(klass, name) } if additional_renderers
|
92
|
+
def prepare_renderers
|
93
|
+
config.renderers.each { |name, klass| register_renderer(klass, name) }
|
156
94
|
end
|
157
95
|
|
158
96
|
def find_renderer(name)
|
159
97
|
@renderers[(name ? name.downcase : nil)]
|
160
98
|
end
|
161
99
|
|
162
|
-
def
|
163
|
-
@renderers[nil]
|
164
|
-
end
|
165
|
-
|
166
|
-
def rendering(snip)
|
100
|
+
def rendering_and_handling_errors(snip)
|
167
101
|
renderer_instance = renderer_for(snip).new(self)
|
168
102
|
yield renderer_instance
|
169
103
|
rescue Exception => e
|
@@ -173,14 +107,40 @@ module Vanilla
|
|
173
107
|
e.backtrace.join("\n").gsub("<", "<").gsub(">", ">") + "</pre>"
|
174
108
|
end
|
175
109
|
|
176
|
-
def
|
177
|
-
|
178
|
-
|
179
|
-
|
110
|
+
def render_in_format(snip, part=nil, format=nil)
|
111
|
+
case format
|
112
|
+
when 'html', nil
|
113
|
+
layout = layout_for(snip)
|
114
|
+
if layout == snip
|
115
|
+
"Rendering of the current layout would result in infinite recursion."
|
116
|
+
else
|
117
|
+
render(layout)
|
118
|
+
end
|
119
|
+
when 'raw', 'css', 'js'
|
120
|
+
Renderers::Raw.new(self).render(snip, part)
|
121
|
+
when 'text', 'atom', 'xml'
|
122
|
+
render(snip, part)
|
123
|
+
else
|
124
|
+
raise "Unknown format '#{format}'"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def layout_for(snip)
|
129
|
+
if snip
|
130
|
+
renderer_for(snip).new(self).layout_for(snip)
|
131
|
+
else
|
132
|
+
default_layout_snip
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def prepare_soup
|
137
|
+
if config.soups
|
138
|
+
backends = [config.soups].flatten.map do |path|
|
139
|
+
::Soup::Backends::FileBackend.new(File.expand_path(path, config.root))
|
180
140
|
end
|
181
141
|
::Soup.new(::Soup::Backends::MultiSoup.new(*backends))
|
182
142
|
else
|
183
|
-
|
143
|
+
raise "No soups defined!"
|
184
144
|
end
|
185
145
|
end
|
186
146
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "vanilla"
|
2
|
+
|
3
|
+
module Vanilla
|
4
|
+
|
5
|
+
# Create a new Vanilla application
|
6
|
+
# Configuration options:
|
7
|
+
#
|
8
|
+
# :soup - provide the path to the soup data
|
9
|
+
# :soups - provide an array of paths to soup data
|
10
|
+
# :root - the directory that the soup paths are relative to;
|
11
|
+
# defaults to Dir.pwd
|
12
|
+
# :renderers - a hash of names to classes
|
13
|
+
# :default_renderer - the class to use when no renderer is provided;
|
14
|
+
# defaults to 'Vanilla::Renderers::Base'
|
15
|
+
# :default_layout_snip - the snip to use as a layout when rendering to HTML;
|
16
|
+
# defaults to 'layout'
|
17
|
+
# :root_snip - the snip to load for the root ('/') url;
|
18
|
+
# defaults to 'start'
|
19
|
+
class Config
|
20
|
+
attr_accessor :root,
|
21
|
+
:root_snip,
|
22
|
+
:soups,
|
23
|
+
:renderers,
|
24
|
+
:default_layout_snip,
|
25
|
+
:default_renderer
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@root = Dir.pwd
|
29
|
+
@root_snip = "start"
|
30
|
+
@soups = ["soups/base", "soups/system"]
|
31
|
+
@default_layout_snip = "layout"
|
32
|
+
@default_renderer = Vanilla::Renderers::Base
|
33
|
+
@renderers = {
|
34
|
+
"base" => Vanilla::Renderers::Base,
|
35
|
+
"markdown" => Vanilla::Renderers::Markdown,
|
36
|
+
"bold" => Vanilla::Renderers::Bold,
|
37
|
+
"erb" => Vanilla::Renderers::Erb,
|
38
|
+
"rb" => Vanilla::Renderers::Ruby,
|
39
|
+
"ruby" => Vanilla::Renderers::Ruby,
|
40
|
+
"haml" => Vanilla::Renderers::Haml,
|
41
|
+
"raw" => Vanilla::Renderers::Raw,
|
42
|
+
"textile" => Vanilla::Renderers::Textile
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/vanilla/console.rb
CHANGED
@@ -3,7 +3,6 @@ require 'vanilla/snip_reference_parser'
|
|
3
3
|
module Vanilla
|
4
4
|
module Renderers
|
5
5
|
class Base
|
6
|
-
include Routes
|
7
6
|
|
8
7
|
# Render a snip.
|
9
8
|
def self.render(snip, part=:content)
|
@@ -20,11 +19,22 @@ module Vanilla
|
|
20
19
|
@app = app
|
21
20
|
end
|
22
21
|
|
23
|
-
# defined for the routes
|
24
22
|
def soup
|
25
23
|
@app.soup
|
26
24
|
end
|
27
25
|
|
26
|
+
def url_to(*args)
|
27
|
+
@app.url_to(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def link_to(link_text, snip_name=link_text, part=nil)
|
31
|
+
if soup[snip_name]
|
32
|
+
%{<a href="#{url_to(snip_name, part)}">#{link_text}</a>}
|
33
|
+
else
|
34
|
+
%{<a class="missing" href="#{url_to(snip_name, part)}">#{link_text}</a>}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def self.snip_regexp
|
29
39
|
%r{(\{[\w\-_\d\.\"\' ]+( +[^\}.]+)?\})}
|
30
40
|
end
|
data/lib/vanilla/request.rb
CHANGED
@@ -13,6 +13,7 @@ module Vanilla
|
|
13
13
|
determine_request_uri_parts
|
14
14
|
end
|
15
15
|
|
16
|
+
# returns the parameters of the request, with every key as a symbol
|
16
17
|
def params
|
17
18
|
# Don't you just love how terse functional programming tends to look like maths?
|
18
19
|
@symbolised_params ||= @rack_request.params.inject({}) { |p, (k,v)| p[k.to_sym] = v; p }
|
@@ -24,47 +25,21 @@ module Vanilla
|
|
24
25
|
@app.soup[snip_name]
|
25
26
|
end
|
26
27
|
|
27
|
-
def
|
28
|
-
@rack_request.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def session
|
36
|
-
@rack_request.env["rack.session"]
|
28
|
+
def method_missing(name, *args)
|
29
|
+
if @rack_request.respond_to?(name)
|
30
|
+
@rack_request.send(name, *args)
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
37
34
|
end
|
38
35
|
|
39
36
|
private
|
40
37
|
|
41
38
|
def determine_request_uri_parts
|
42
|
-
@snip_name, @part, @format =
|
39
|
+
@snip_name, @part, @format = Vanilla::Routing.parse(@rack_request.path_info)
|
40
|
+
@snip_name ||= @app.config.root_snip
|
43
41
|
@format ||= 'html'
|
44
42
|
@method = (params.delete(:_method) || @rack_request.request_method).downcase
|
45
43
|
end
|
46
|
-
|
47
|
-
def uri_path(request)
|
48
|
-
request.path_info
|
49
|
-
end
|
50
|
-
|
51
|
-
URL_ROOT = /\A\/?\Z/ # i.e. / or nothing
|
52
|
-
URL_SNIP = /\A\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /start, /start.html
|
53
|
-
URL_SNIP_AND_PART = /\A\/([\w\-\s]+)\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /blah/part, /blah/part.raw
|
54
|
-
|
55
|
-
# Returns an array of the requested snip, part and format
|
56
|
-
def request_uri_parts(request)
|
57
|
-
case CGI.unescape(uri_path(request))
|
58
|
-
when URL_ROOT
|
59
|
-
[@app.config[:root_snip] || 'start', nil, 'html']
|
60
|
-
when URL_SNIP
|
61
|
-
[$1, nil, $3]
|
62
|
-
when URL_SNIP_AND_PART
|
63
|
-
[$1, $2, $4]
|
64
|
-
else
|
65
|
-
[]
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
44
|
end
|
70
45
|
end
|