nesta 0.9.13 → 0.10.0
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.
- checksums.yaml +7 -0
- data/{spec/spec.opts → .rspec} +0 -0
- data/.travis.yml +3 -2
- data/CHANGES +130 -1
- data/Gemfile +1 -8
- data/Gemfile.lock +68 -51
- data/LICENSE +1 -1
- data/README.md +38 -6
- data/Rakefile +2 -5
- data/bin/nesta +59 -3
- data/config.ru +3 -0
- data/lib/nesta.rb +1 -1
- data/lib/nesta/app.rb +20 -17
- data/lib/nesta/commands.rb +6 -3
- data/lib/nesta/config.rb +52 -15
- data/lib/nesta/helpers.rb +30 -3
- data/lib/nesta/models.rb +48 -30
- data/lib/nesta/navigation.rb +32 -12
- data/lib/nesta/overrides.rb +5 -5
- data/lib/nesta/version.rb +1 -1
- data/nesta.gemspec +9 -10
- data/smoke-test.sh +102 -0
- data/spec/atom_spec.rb +52 -49
- data/spec/commands_spec.rb +22 -16
- data/spec/config_spec.rb +66 -6
- data/spec/fixtures/nesta-plugin-test/lib/nesta-plugin-test/init.rb +1 -3
- data/spec/model_factory.rb +16 -16
- data/spec/models_spec.rb +197 -144
- data/spec/overrides_spec.rb +21 -21
- data/spec/page_spec.rb +182 -136
- data/spec/sitemap_spec.rb +48 -43
- data/spec/spec_helper.rb +32 -17
- data/templates/Gemfile +5 -2
- data/templates/config/config.yml +13 -13
- data/templates/config/deploy.rb +2 -2
- data/templates/index.haml +2 -0
- data/templates/themes/app.rb +1 -1
- data/templates/themes/views/layout.haml +7 -0
- data/templates/themes/views/master.sass +3 -0
- data/templates/themes/views/page.haml +1 -0
- data/views/atom.haml +3 -3
- data/views/comments.haml +1 -1
- data/views/error.haml +1 -1
- data/views/feed.haml +1 -1
- data/views/layout.haml +6 -3
- data/views/master.sass +143 -133
- data/views/mixins.sass +53 -28
- data/views/normalize.scss +396 -0
- data/views/page_meta.haml +2 -2
- data/views/sitemap.haml +2 -2
- data/views/summaries.haml +2 -2
- metadata +155 -202
- data/lib/nesta/cache.rb +0 -138
data/config.ru
CHANGED
@@ -4,7 +4,10 @@ require 'bundler/setup'
|
|
4
4
|
Bundler.require(:default)
|
5
5
|
|
6
6
|
$LOAD_PATH.unshift(::File.expand_path('lib', ::File.dirname(__FILE__)))
|
7
|
+
|
7
8
|
require 'nesta/env'
|
9
|
+
Nesta::Env.root = ::File.expand_path('.', ::File.dirname(__FILE__))
|
10
|
+
|
8
11
|
require 'nesta/app'
|
9
12
|
|
10
13
|
run Nesta::App
|
data/lib/nesta.rb
CHANGED
data/lib/nesta/app.rb
CHANGED
@@ -4,7 +4,6 @@ require 'sass'
|
|
4
4
|
|
5
5
|
require File.expand_path('../nesta', File.dirname(__FILE__))
|
6
6
|
require File.expand_path('env', File.dirname(__FILE__))
|
7
|
-
require File.expand_path('cache', File.dirname(__FILE__))
|
8
7
|
require File.expand_path('config', File.dirname(__FILE__))
|
9
8
|
require File.expand_path('models', File.dirname(__FILE__))
|
10
9
|
require File.expand_path('helpers', File.dirname(__FILE__))
|
@@ -16,17 +15,19 @@ Encoding.default_external = 'utf-8' if RUBY_VERSION =~ /^1.9/
|
|
16
15
|
|
17
16
|
module Nesta
|
18
17
|
class App < Sinatra::Base
|
19
|
-
register Sinatra::Cache
|
20
|
-
|
21
18
|
set :root, Nesta::Env.root
|
22
19
|
set :views, File.expand_path('../../views', File.dirname(__FILE__))
|
23
|
-
set :
|
24
|
-
set :haml, { :format => :html5 }
|
20
|
+
set :haml, { format: :html5 }
|
25
21
|
|
26
22
|
helpers Overrides::Renderers
|
27
23
|
helpers Navigation::Renderers
|
28
24
|
helpers View::Helpers
|
29
25
|
|
26
|
+
def cache(content)
|
27
|
+
Nesta.deprecated('cache', "it's no longer required - remove it from app.rb")
|
28
|
+
content
|
29
|
+
end
|
30
|
+
|
30
31
|
before do
|
31
32
|
if request.path_info =~ Regexp.new('./$')
|
32
33
|
redirect to(request.path_info.sub(Regexp.new('/$'), ''))
|
@@ -47,7 +48,7 @@ module Nesta
|
|
47
48
|
Overrides.load_theme_app
|
48
49
|
|
49
50
|
get '/robots.txt' do
|
50
|
-
content_type 'text/plain', :
|
51
|
+
content_type 'text/plain', charset: 'utf-8'
|
51
52
|
<<-EOF
|
52
53
|
# robots.txt
|
53
54
|
# See http://en.wikipedia.org/wiki/Robots_exclusion_standard
|
@@ -55,33 +56,35 @@ module Nesta
|
|
55
56
|
end
|
56
57
|
|
57
58
|
get '/css/:sheet.css' do
|
58
|
-
content_type 'text/css', :
|
59
|
-
|
59
|
+
content_type 'text/css', charset: 'utf-8'
|
60
|
+
stylesheet(params[:sheet].to_sym)
|
60
61
|
end
|
61
62
|
|
62
|
-
get %r{/attachments/([\w
|
63
|
+
get %r{/attachments/([\w/.@-]+)} do |file|
|
63
64
|
file = File.join(Nesta::Config.attachment_path, params[:captures].first)
|
64
65
|
if file =~ /\.\.\//
|
65
66
|
not_found
|
66
|
-
else
|
67
|
-
send_file(file, :
|
67
|
+
else
|
68
|
+
send_file(file, disposition: nil)
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
72
|
get '/articles.xml' do
|
72
|
-
content_type :xml, :
|
73
|
+
content_type :xml, charset: 'utf-8'
|
73
74
|
set_from_config(:title, :subtitle, :author)
|
74
75
|
@articles = Page.find_articles.select { |a| a.date }[0..9]
|
75
|
-
|
76
|
+
haml(:atom, format: :xhtml, layout: false)
|
76
77
|
end
|
77
78
|
|
78
79
|
get '/sitemap.xml' do
|
79
|
-
content_type :xml, :
|
80
|
-
@pages = Page.find_all
|
80
|
+
content_type :xml, charset: 'utf-8'
|
81
|
+
@pages = Page.find_all.reject do |page|
|
82
|
+
page.draft? or page.flagged_as?('skip-sitemap')
|
83
|
+
end
|
81
84
|
@last = @pages.map { |page| page.last_modified }.inject do |latest, page|
|
82
85
|
(page > latest) ? page : latest
|
83
86
|
end
|
84
|
-
|
87
|
+
haml(:sitemap, format: :xhtml, layout: false)
|
85
88
|
end
|
86
89
|
|
87
90
|
get '*' do
|
@@ -91,7 +94,7 @@ module Nesta
|
|
91
94
|
raise Sinatra::NotFound if @page.nil?
|
92
95
|
@title = @page.title
|
93
96
|
set_from_page(:description, :keywords)
|
94
|
-
|
97
|
+
haml(@page.template, layout: @page.layout)
|
95
98
|
end
|
96
99
|
end
|
97
100
|
end
|
data/lib/nesta/commands.rb
CHANGED
@@ -204,8 +204,8 @@ end
|
|
204
204
|
output = ''
|
205
205
|
file.each_line do |line|
|
206
206
|
if line =~ /^end/
|
207
|
-
output << '
|
208
|
-
output << '
|
207
|
+
output << ' gem.add_dependency("nesta", ">= 0.9.11")' + "\n"
|
208
|
+
output << ' gem.add_development_dependency("rake")' + "\n"
|
209
209
|
end
|
210
210
|
output << line
|
211
211
|
end
|
@@ -247,7 +247,10 @@ end
|
|
247
247
|
make_directories
|
248
248
|
copy_templates(
|
249
249
|
'themes/README.md' => "#{@theme_path}/README.md",
|
250
|
-
'themes/app.rb' => "#{@theme_path}/app.rb"
|
250
|
+
'themes/app.rb' => "#{@theme_path}/app.rb",
|
251
|
+
'themes/views/layout.haml' => "#{@theme_path}/views/layout.haml",
|
252
|
+
'themes/views/page.haml' => "#{@theme_path}/views/page.haml",
|
253
|
+
'themes/views/master.sass' => "#{@theme_path}/views/master.sass"
|
251
254
|
)
|
252
255
|
end
|
253
256
|
end
|
data/lib/nesta/config.rb
CHANGED
@@ -2,8 +2,17 @@ require 'yaml'
|
|
2
2
|
|
3
3
|
module Nesta
|
4
4
|
class Config
|
5
|
+
class NotDefined < KeyError; end
|
6
|
+
|
5
7
|
@settings = %w[
|
6
|
-
|
8
|
+
cache
|
9
|
+
content
|
10
|
+
disqus_short_name
|
11
|
+
google_analytics_code
|
12
|
+
read_more
|
13
|
+
subtitle
|
14
|
+
theme
|
15
|
+
title
|
7
16
|
]
|
8
17
|
@author_settings = %w[name uri email]
|
9
18
|
@yaml = nil
|
@@ -11,11 +20,20 @@ module Nesta
|
|
11
20
|
class << self
|
12
21
|
attr_accessor :settings, :author_settings, :yaml_conf
|
13
22
|
end
|
14
|
-
|
23
|
+
|
24
|
+
def self.fetch(key, *default)
|
25
|
+
from_environment(key.to_s)
|
26
|
+
rescue NotDefined
|
27
|
+
begin
|
28
|
+
from_yaml(key.to_s)
|
29
|
+
rescue NotDefined
|
30
|
+
default.empty? && raise || (return default.first)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
15
34
|
def self.method_missing(method, *args)
|
16
|
-
|
17
|
-
|
18
|
-
from_environment(setting) || from_yaml(setting)
|
35
|
+
if settings.include?(method.to_s)
|
36
|
+
fetch(method, nil)
|
19
37
|
else
|
20
38
|
super
|
21
39
|
end
|
@@ -27,7 +45,14 @@ module Nesta
|
|
27
45
|
variable = "NESTA_AUTHOR__#{setting.upcase}"
|
28
46
|
ENV[variable] && environment_config[setting] = ENV[variable]
|
29
47
|
end
|
30
|
-
environment_config.empty? ? from_yaml(
|
48
|
+
environment_config.empty? ? from_yaml('author') : environment_config
|
49
|
+
rescue NotDefined
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.cache
|
54
|
+
Nesta.deprecated('Nesta::Config.cache',
|
55
|
+
'see http://nestacms.com/docs/deployment/page-caching')
|
31
56
|
end
|
32
57
|
|
33
58
|
def self.content_path(basename = nil)
|
@@ -45,9 +70,16 @@ module Nesta
|
|
45
70
|
def self.yaml_path
|
46
71
|
File.expand_path('config/config.yml', Nesta::App.root)
|
47
72
|
end
|
48
|
-
|
73
|
+
|
74
|
+
def self.read_more
|
75
|
+
fetch('read_more', 'Continue reading')
|
76
|
+
end
|
77
|
+
|
49
78
|
def self.from_environment(setting)
|
50
|
-
value = ENV
|
79
|
+
value = ENV.fetch("NESTA_#{setting.upcase}")
|
80
|
+
rescue KeyError
|
81
|
+
raise NotDefined.new(setting)
|
82
|
+
else
|
51
83
|
overrides = { "true" => true, "false" => false }
|
52
84
|
overrides.has_key?(value) ? overrides[value] : value
|
53
85
|
end
|
@@ -63,15 +95,20 @@ module Nesta
|
|
63
95
|
end
|
64
96
|
private_class_method :can_use_yaml?
|
65
97
|
|
98
|
+
def self.from_hash(hash, setting)
|
99
|
+
hash.fetch(setting) { raise NotDefined.new(setting) }
|
100
|
+
end
|
101
|
+
private_class_method :from_hash
|
102
|
+
|
66
103
|
def self.from_yaml(setting)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
104
|
+
raise NotDefined.new(setting) unless can_use_yaml?
|
105
|
+
self.yaml_conf ||= YAML::load(ERB.new(IO.read(yaml_path)).result)
|
106
|
+
env_config = self.yaml_conf.fetch(Nesta::App.environment.to_s, {})
|
107
|
+
begin
|
108
|
+
from_hash(env_config, setting)
|
109
|
+
rescue NotDefined
|
110
|
+
from_hash(self.yaml_conf, setting)
|
71
111
|
end
|
72
|
-
rescue Errno::ENOENT # config file not found
|
73
|
-
raise unless Nesta::App.environment == :test
|
74
|
-
nil
|
75
112
|
end
|
76
113
|
private_class_method :from_yaml
|
77
114
|
|
data/lib/nesta/helpers.rb
CHANGED
@@ -25,7 +25,7 @@ module Nesta
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def absolute_urls(text)
|
28
|
-
text.gsub!(/(<a href=['"])\//, '\1' +
|
28
|
+
text.gsub!(/(<a href=['"])\//, '\1' + path_to('/', uri: true))
|
29
29
|
text
|
30
30
|
end
|
31
31
|
|
@@ -54,7 +54,7 @@ module Nesta
|
|
54
54
|
def local_stylesheet_link_tag(name)
|
55
55
|
pattern = File.expand_path("views/#{name}.s{a,c}ss", Nesta::App.root)
|
56
56
|
if Dir.glob(pattern).size > 0
|
57
|
-
haml_tag :link, :
|
57
|
+
haml_tag :link, href: path_to("/css/#{name}.css"), rel: "stylesheet"
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -63,12 +63,39 @@ module Nesta
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def article_summaries(articles)
|
66
|
-
haml(:summaries, :
|
66
|
+
haml(:summaries, layout: false, locals: { pages: articles })
|
67
67
|
end
|
68
68
|
|
69
69
|
def articles_heading
|
70
70
|
@page.metadata('articles heading') || "Articles on #{@page.heading}"
|
71
71
|
end
|
72
|
+
|
73
|
+
# Generates the full path to a given page, taking Rack routers and
|
74
|
+
# reverse proxies into account.
|
75
|
+
#
|
76
|
+
# Takes an options hash with a single option called `uri`. Set it
|
77
|
+
# to `true` if you'd like the publicly accessible URI for the
|
78
|
+
# path, rather than just the path relative to the site's root URI.
|
79
|
+
# The default is `false`.
|
80
|
+
#
|
81
|
+
# path_to(page.abspath, uri: true)
|
82
|
+
#
|
83
|
+
def path_to(page_path, options = {})
|
84
|
+
host = ''
|
85
|
+
if options[:uri]
|
86
|
+
host << "http#{'s' if request.ssl?}://"
|
87
|
+
if (request.env.include?("HTTP_X_FORWARDED_HOST") or
|
88
|
+
request.port != (request.ssl? ? 443 : 80))
|
89
|
+
host << request.host_with_port
|
90
|
+
else
|
91
|
+
host << request.host
|
92
|
+
end
|
93
|
+
end
|
94
|
+
uri_parts = [host]
|
95
|
+
uri_parts << request.script_name.to_s if request.script_name
|
96
|
+
uri_parts << page_path
|
97
|
+
File.join(uri_parts)
|
98
|
+
end
|
72
99
|
end
|
73
100
|
end
|
74
101
|
end
|
data/lib/nesta/models.rb
CHANGED
@@ -7,11 +7,14 @@ Tilt.register Tilt::RDiscountTemplate, 'mdown'
|
|
7
7
|
Tilt.register Tilt::RedcarpetTemplate, 'mdown'
|
8
8
|
|
9
9
|
module Nesta
|
10
|
+
class HeadingNotSet < RuntimeError; end
|
11
|
+
class LinkTextNotSet < RuntimeError; end
|
10
12
|
class MetadataParseError < RuntimeError; end
|
11
13
|
|
12
14
|
class FileModel
|
13
15
|
FORMATS = [:mdown, :haml, :textile]
|
14
|
-
@@
|
16
|
+
@@page_cache = {}
|
17
|
+
@@filename_cache = {}
|
15
18
|
|
16
19
|
attr_reader :filename, :mtime
|
17
20
|
|
@@ -33,25 +36,35 @@ module Nesta
|
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
39
|
+
def self.find_file_for_path(path)
|
40
|
+
if ! @@filename_cache.has_key?(path)
|
41
|
+
FORMATS.each do |format|
|
42
|
+
[path, File.join(path, 'index')].each do |basename|
|
43
|
+
filename = model_path("#{basename}.#{format}")
|
44
|
+
if File.exist?(filename)
|
45
|
+
@@filename_cache[path] = filename
|
46
|
+
break
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
@@filename_cache[path]
|
52
|
+
end
|
53
|
+
|
36
54
|
def self.needs_loading?(path, filename)
|
37
|
-
@@
|
55
|
+
@@page_cache[path].nil? || File.mtime(filename) > @@page_cache[path].mtime
|
38
56
|
end
|
39
57
|
|
40
58
|
def self.load(path)
|
41
|
-
|
42
|
-
[path
|
43
|
-
filename = model_path("#{basename}.#{format}")
|
44
|
-
if File.exist?(filename) && needs_loading?(path, filename)
|
45
|
-
@@cache[path] = self.new(filename)
|
46
|
-
break
|
47
|
-
end
|
48
|
-
end
|
59
|
+
if (filename = find_file_for_path(path)) && needs_loading?(path, filename)
|
60
|
+
@@page_cache[path] = self.new(filename)
|
49
61
|
end
|
50
|
-
@@
|
62
|
+
@@page_cache[path]
|
51
63
|
end
|
52
64
|
|
53
65
|
def self.purge_cache
|
54
|
-
@@
|
66
|
+
@@page_cache = {}
|
67
|
+
@@filename_cache = {}
|
55
68
|
end
|
56
69
|
|
57
70
|
def self.menu_items
|
@@ -155,19 +168,19 @@ module Nesta
|
|
155
168
|
end
|
156
169
|
end
|
157
170
|
|
158
|
-
def
|
159
|
-
|
160
|
-
if
|
171
|
+
def add_p_tags_to_haml(text)
|
172
|
+
contains_tags = (text =~ /^\s*%/)
|
173
|
+
if contains_tags
|
161
174
|
text
|
162
175
|
else
|
163
|
-
text.split(/\r?\n/).inject(
|
176
|
+
text.split(/\r?\n/).inject('') do |accumulator, line|
|
164
177
|
accumulator << "%p #{line}\n"
|
165
178
|
end
|
166
179
|
end
|
167
180
|
end
|
168
181
|
|
169
182
|
def convert_to_html(format, scope, text)
|
170
|
-
text =
|
183
|
+
text = add_p_tags_to_haml(text) if @format == :haml
|
171
184
|
template = Tilt[format].new { text }
|
172
185
|
template.render(scope)
|
173
186
|
end
|
@@ -215,19 +228,20 @@ module Nesta
|
|
215
228
|
/^\s*h1\.\s+(.*)/
|
216
229
|
end
|
217
230
|
markup =~ regex
|
218
|
-
Regexp.last_match(1)
|
231
|
+
Regexp.last_match(1) or raise HeadingNotSet, "#{abspath} needs a heading"
|
232
|
+
end
|
233
|
+
|
234
|
+
def link_text
|
235
|
+
metadata('link text') || heading
|
236
|
+
rescue HeadingNotSet
|
237
|
+
raise LinkTextNotSet, "Need to link to '#{abspath}' but can't get link text"
|
219
238
|
end
|
220
239
|
|
221
240
|
def title
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
elsif heading
|
227
|
-
"#{heading} - #{Nesta::Config.title}"
|
228
|
-
elsif abspath == '/'
|
229
|
-
Nesta::Config.title
|
230
|
-
end
|
241
|
+
metadata('title') || link_text
|
242
|
+
rescue LinkTextNotSet
|
243
|
+
return Nesta::Config.title if abspath == '/'
|
244
|
+
raise
|
231
245
|
end
|
232
246
|
|
233
247
|
def date(format = nil)
|
@@ -245,7 +259,7 @@ module Nesta
|
|
245
259
|
end
|
246
260
|
|
247
261
|
def read_more
|
248
|
-
metadata('read more') ||
|
262
|
+
metadata('read more') || Nesta::Config.read_more
|
249
263
|
end
|
250
264
|
|
251
265
|
def summary
|
@@ -274,7 +288,7 @@ module Nesta
|
|
274
288
|
paths = category_strings.map { |specifier| specifier.sub(/:-?\d+$/, '') }
|
275
289
|
pages = valid_paths(paths).map { |p| Page.find_by_path(p) }
|
276
290
|
pages.sort do |x, y|
|
277
|
-
x.
|
291
|
+
x.link_text.downcase <=> y.link_text.downcase
|
278
292
|
end
|
279
293
|
end
|
280
294
|
|
@@ -306,7 +320,7 @@ module Nesta
|
|
306
320
|
in_category.sort do |x, y|
|
307
321
|
by_priority = y.priority(path) <=> x.priority(path)
|
308
322
|
if by_priority == 0
|
309
|
-
x.
|
323
|
+
x.link_text.downcase <=> y.link_text.downcase
|
310
324
|
else
|
311
325
|
by_priority
|
312
326
|
end
|
@@ -317,6 +331,10 @@ module Nesta
|
|
317
331
|
Page.find_articles.select { |article| article.categories.include?(self) }
|
318
332
|
end
|
319
333
|
|
334
|
+
def receives_comments?
|
335
|
+
! date.nil?
|
336
|
+
end
|
337
|
+
|
320
338
|
private
|
321
339
|
def category_strings
|
322
340
|
strings = metadata('categories')
|