nesta 0.14.0 → 0.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e14e3ed99700277225c068df787864f52f19385f08469d91bf1a8f4073e24568
4
- data.tar.gz: 84e9c0fb31ba8b380b0ce86f9edc6f660fd8a8f9474ad28400e7c921fd745c01
3
+ metadata.gz: f57754ef13ef4b4533c03ab454b2114fb35d3e168d20107c1fb39941d6af4b92
4
+ data.tar.gz: 9aa4a9b8e0715d77c1ec515a114f63827e8a117e1f3b807755a59d0c0eba0c45
5
5
  SHA512:
6
- metadata.gz: e39c4ada00a1ac3b4be18b6887240a670d4f1c050023771dc71fa6703bbb315bac54f959053788dc7018761a5bfc3e1fe387486e856629a785ae3098c8203704
7
- data.tar.gz: 4da9e195b6679df8c9f2c9ec3a07b780409b2a68f6cffe66feab9276a0ee90b987b7221a13d5f363c0b700c3d5b8d956e9b6a5753a0aa81058e1e10458ced75f
6
+ metadata.gz: effa2dcecf9d3ed0de395102c893d9f1571171b4bc4d63968911f3538c27bd8ef15692df2586239e2986d1b32e4bd4ef23513245c2cd89d0d159df3d9bf79903
7
+ data.tar.gz: c0f318224b4f70322af4d30b55e517b1d790b3087129eb0601d434eabf79cc65e3b8ae24262f7300812a0414dd5402d2969d0f11be1f5d0516afe1ad7474d27c
@@ -8,10 +8,10 @@ jobs:
8
8
  strategy:
9
9
  fail-fast: false
10
10
  matrix:
11
- ruby: ["2.7", "3.0", "3.1", "3.2", "head"]
11
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v3
14
+ - uses: actions/checkout@v4
15
15
  - uses: ruby/setup-ruby@v1
16
16
  with:
17
17
  ruby-version: ${{ matrix.ruby }}
@@ -1,4 +1,43 @@
1
- = 0.14.0 / (23 March 2023)
1
+ # Changelog
2
+
3
+ ## 0.16.0 (11 April 2024)
4
+
5
+ * Update Google Analytics JS code to GA4. (Matthew Bass)
6
+
7
+ * Upgrade to Sinatra 3.1. (なつき)
8
+
9
+ * Tilt renderers (e.g. for Markdown, Haml, or Textile) are now configurable.
10
+ See #146 for details. (Graham Ashton)
11
+
12
+ * Drop support for Ruby 2.7, which is no longer supported by Nokogiri,
13
+ which is one of Nesta's dependencies. This is understandable; Ruby
14
+ 2.7 reached end-of-life in March 2023. (Graham Ashton)
15
+
16
+ * Bug fix: Config variables that were defined for an environment (test,
17
+ dev, production), but for which there was no default, were always read
18
+ as nil. (Matthew Bass)
19
+
20
+ ## 0.15.0 (11 July 2023)
21
+
22
+ * Upgrade to Sinatra 3. (Graham Ashton)
23
+
24
+ * The `models.rb` file has been long and unnecessarily hard to navigate
25
+ for too long. It has been split up into multiple files, one for each
26
+ class. (Graham Ashton, suggested by Lilith River)
27
+
28
+ * Remove support for the BlueCloth markdown library. Nesta uses Tilt
29
+ for rendering Markdown, and BlueCloth support has been removed in
30
+ Tilt 2.2.0. See rtomayko/tilt#382 for details.
31
+
32
+ If your site uses BlueCloth, remove your call to `Tilt.prefer`,
33
+ and Nesta will use its default Markdown processor. See Nesta's docs
34
+ on [configuring the Markdown processor] for more details.
35
+
36
+ [configuring the Markdown processor]: https://nestacms.com/docs/creating-content/changing-the-markdown-processor
37
+
38
+ (Graham Ashton)
39
+
40
+ ## 0.14.0 (23 March 2023)
2
41
 
3
42
  * Nesta can now be used as a Static Site Generator (SSG) with its new
4
43
  `nesta build` command! Server Side Rendering (SSR) is still supported,
@@ -71,7 +110,7 @@
71
110
  * The breadcrumb_label helper method (deprecated in 0.9.3) has been removed.
72
111
  (Graham Ashton)
73
112
 
74
- = 0.13.0 / (28 September 2022)
113
+ ## 0.13.0 (28 September 2022)
75
114
 
76
115
  * Update dependencies in order to support Ruby 3.0 and above.
77
116
  (Graham Ashton)
@@ -97,7 +136,7 @@
97
136
  * Stopped the test suite from executing external commands during tests.
98
137
  (Graham Ashton)
99
138
 
100
- = 0.12.0 / (30 June 2020)
139
+ ## 0.12.0 (30 June 2020)
101
140
 
102
141
  * Upgrade to Sinatra 2 and Rack 2. (Graham Ashton)
103
142
 
@@ -113,12 +152,12 @@
113
152
  * Stop running the test suite under Ruby 2.3 and 2.4, both of which
114
153
  have reached end-of-life. (Graham Ashton)
115
154
 
116
- = 0.11.1 / (26 March 2015)
155
+ ## 0.11.1 (26 March 2015)
117
156
 
118
157
  * Tighten dependency on Tilt, as version 2.x is incompatible.
119
158
  (Graham Ashton)
120
159
 
121
- = 0.11.0 / (16 March 2015)
160
+ ## 0.11.0 (16 March 2015)
122
161
 
123
162
  * Allow Haml pages to use the built-in Markdown filter again, by
124
163
  including the haml-contrib gem.
@@ -161,7 +200,7 @@
161
200
 
162
201
  * Support for Ruby 2.2. (Graham Ashton)
163
202
 
164
- = 0.10.0 / (25 April 2014)
203
+ ## 0.10.0 (25 April 2014)
165
204
 
166
205
  * Upgraded the default theme to a responsive design, using Google's
167
206
  Roboto Slab web font. (Graham Ashton)
@@ -285,7 +324,7 @@
285
324
  this list. See GitHub for the full list of commits.
286
325
  https://github.com/gma/nesta/compare/v0.9.13...v0.10.0
287
326
 
288
- = 0.9.13 / (3 March 2012)
327
+ ## 0.9.13 (3 March 2012)
289
328
 
290
329
  * The nesta script has a new command; edit. You can pass it the path
291
330
  to a file within your content/pages folder and it will open the file
@@ -343,9 +382,9 @@
343
382
  * Bug fix: Summaries on Haml pages were not marked up as paragraphs.
344
383
  See #75.
345
384
 
346
- = 0.9.12 / (Released then pulled, due to rubygems [still] being a total mess)
385
+ ## 0.9.12 (Released then pulled, due to rubygems [still] being a total mess)
347
386
 
348
- = 0.9.11 / (22 September 2011)
387
+ ## 0.9.11 (22 September 2011)
349
388
 
350
389
  * Use Tilt to render the Markdown, Textile and Haml in content/pages.
351
390
  RDiscount is now the default Markdown processor. To continue using
@@ -372,7 +411,7 @@
372
411
  within the content folder by crafting a relative path containing
373
412
  the string '../' (Louis Nyffenegger).
374
413
 
375
- = 0.9.10 / (9 September 2011)
414
+ ## 0.9.10 (9 September 2011)
376
415
 
377
416
  * Load Nesta plugins from gems. Any gem whose name begins with
378
417
  nesta-plugin- can be used in a project by adding it to the project's
@@ -390,7 +429,7 @@
390
429
  the Sass rendering engine by default, which allows it to find .sass
391
430
  files within the gem if no matching files are found locally.
392
431
 
393
- = 0.9.9 / (24 August 2011)
432
+ ## 0.9.9 (24 August 2011)
394
433
 
395
434
  * Bug fix: What a debacle this is turning into. The new Nesta::Env
396
435
  class must be required before the code in 'nesta/app' is loaded.
@@ -398,7 +437,7 @@
398
437
  via config.ru. Running Nesta any other way lead to an immediate
399
438
  crash.
400
439
 
401
- = 0.9.8 / (22 August 2011)
440
+ ## 0.9.8 (22 August 2011)
402
441
 
403
442
  * Bug fix: The Sinatra app's root directory wasn't set which meant
404
443
  that Nesta couldn't always find the ./public directory (such as when
@@ -409,12 +448,12 @@
409
448
  Nesta::Env class. In 0.9.6 I forgot to actually set Nesta::App.root
410
449
  as well, which was a big mistake. Whoops.
411
450
 
412
- = 0.9.7 / (19 August 2011)
451
+ ## 0.9.7 (19 August 2011)
413
452
 
414
453
  * No code changes from 0.9.6; version number increased to allow new gem
415
454
  to be deployed to rubygems.org.
416
455
 
417
- = 0.9.6 / (18 August 2011) [never released due to packaging bug]
456
+ ## 0.9.6 (18 August 2011) [never released due to packaging bug]
418
457
 
419
458
  * Nesta no longer cares whether you write your Sass stylesheets in the
420
459
  original indented Sass format or the default SCSS syntax (which is a
@@ -440,7 +479,7 @@
440
479
  Nesta::App.root would be before requiring nesta/app. Fixed by
441
480
  creating Nesta::Env and moving root to there instead.
442
481
 
443
- = 0.9.5 / (1 May 2011)
482
+ ## 0.9.5 (1 May 2011)
444
483
 
445
484
  * Added --version option to nesta command (Christopher Lindblom).
446
485
 
@@ -466,14 +505,14 @@
466
505
  within Haml templates. See https://github.com/gma/nesta/pull/18
467
506
  (Carl Furrow).
468
507
 
469
- = 0.9.4 / 18 February 2011
508
+ ## 0.9.4 (18 February 2011)
470
509
 
471
510
  * Updated the link colours in the default theme.
472
511
 
473
512
  * Set the default encoding to UTF-8. Without it Heroku would sometimes
474
513
  fail to render pages (issue 14).
475
514
 
476
- = 0.9.3 / 18 January 2011
515
+ ## 0.9.3 (18 January 2011)
477
516
 
478
517
  * The route and view for serving the home page (/) has been removed,
479
518
  and the home page must now be created as an index page in
@@ -515,7 +554,7 @@
515
554
  * Bug fix: Don't output empty <li> tags for nested submenus that are
516
555
  beneath the requested number of levels.
517
556
 
518
- = 0.9.2 / 10 January 2011
557
+ ## 0.9.2 (10 January 2011)
519
558
 
520
559
  * Made the FileModel.metadata method public, to allow for custom
521
560
  metadata at the top of each page. (Wynn Netherland)
@@ -525,7 +564,7 @@
525
564
 
526
565
  * Added templates required by `nesta theme:create`.
527
566
 
528
- = 0.9.1 / 31 December 2010
567
+ ## 0.9.1 (31 December 2010)
529
568
 
530
569
  * Re-implemented the default theme, using semantic HTML5 and
531
570
  Andy Clarke's Universal Internet Explorer 6 CSS. Named the previous
@@ -538,15 +577,16 @@
538
577
  * Moved the navigation helpers into the Nesta::Navigation::Renderers
539
578
  module.
540
579
 
541
- = 0.9.0 / 20 December 2010
580
+ ## 0.9.0 (20 December 2010)
542
581
 
543
582
  * Packaged Nesta as a gem for the first time, instead of as a template
544
583
  site that can be cloned, edited and deployed. Added the `nesta`
545
584
  command for generating new sites and managing themes.
546
585
 
547
- = Previous versions / from 26 November 2008
586
+ ## Previous versions (from 26 November 2008)
548
587
 
549
588
  * Prior to 0.9.0 Nesta was distributed as a git repository that could
550
589
  be forked, edited and deployed. The only change log for these
551
- versions is the Git commit history.
590
+ versions is the commit history:
591
+
552
592
  https://github.com/gma/nesta/commits/master
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nesta (0.14.0)
4
+ nesta (0.16.0)
5
5
  RedCloth (~> 4.2)
6
6
  haml (>= 3.1, < 6.0)
7
7
  haml-contrib (>= 1.0)
@@ -9,13 +9,13 @@ PATH
9
9
  rake
10
10
  rdiscount (~> 2.1)
11
11
  sass-embedded (~> 1.58)
12
- sinatra (~> 2.0)
13
- tilt (~> 2.0)
12
+ sinatra (~> 3.1)
13
+ tilt (~> 2.1)
14
14
 
15
15
  GEM
16
16
  remote: https://rubygems.org/
17
17
  specs:
18
- RedCloth (4.3.2)
18
+ RedCloth (4.3.3)
19
19
  addressable (2.8.1)
20
20
  public_suffix (>= 2.0.2, < 6.0)
21
21
  ansi (1.5.0)
@@ -41,7 +41,7 @@ GEM
41
41
  rb-inotify (>= 0.9)
42
42
  rb-kqueue (>= 0.2)
43
43
  mini_mime (1.1.2)
44
- mini_portile2 (2.8.1)
44
+ mini_portile2 (2.8.5)
45
45
  minitest (5.18.0)
46
46
  minitest-reporters (1.6.0)
47
47
  ansi
@@ -53,16 +53,16 @@ GEM
53
53
  rb-fsevent (>= 0.9)
54
54
  rb-inotify (>= 0.8)
55
55
  unicorn (>= 4.5)
56
- mustermann (2.0.2)
56
+ mustermann (3.0.0)
57
57
  ruby2_keywords (~> 0.0.1)
58
- nokogiri (1.14.2)
59
- mini_portile2 (~> 2.8.0)
58
+ nokogiri (1.16.2)
59
+ mini_portile2 (~> 2.8.2)
60
60
  racc (~> 1.4)
61
61
  public_suffix (5.0.1)
62
- racc (1.6.2)
63
- rack (2.2.6.4)
64
- rack-protection (2.2.4)
65
- rack
62
+ racc (1.7.3)
63
+ rack (2.2.8.1)
64
+ rack-protection (3.1.0)
65
+ rack (~> 2.2, >= 2.2.4)
66
66
  rack-test (2.0.2)
67
67
  rack (>= 1.3)
68
68
  raindrops (0.20.1)
@@ -78,10 +78,10 @@ GEM
78
78
  sass-embedded (1.58.3)
79
79
  google-protobuf (~> 3.21)
80
80
  rake (>= 10.0.0)
81
- sinatra (2.2.4)
82
- mustermann (~> 2.0)
83
- rack (~> 2.2)
84
- rack-protection (= 2.2.4)
81
+ sinatra (3.1.0)
82
+ mustermann (~> 3.0)
83
+ rack (~> 2.2, >= 2.2.4)
84
+ rack-protection (= 3.1.0)
85
85
  tilt (~> 2.0)
86
86
  temple (0.10.0)
87
87
  tilt (2.1.0)
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008-2022 Graham Ashton
1
+ Copyright (c) 2008-2023 Graham Ashton
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,34 +1,37 @@
1
- # Nesta - a CMS for Ruby Developers
1
+ # Lightweight file-based CMS and Static Site Generator
2
2
 
3
- A file-based CMS for web sites and blogs, written in [Sinatra][frank].
3
+ Nesta is a lightweight CMS for building content sites and blogs, written in
4
+ [Sinatra].
4
5
 
5
- Content can be written in [Markdown][markdown] or [Textile][textile] and
6
- stored in text files (though you can also use Haml if you need to add
7
- some HTML to your pages). There's no database; write your content in
8
- your editor. Publish by pushing to a git repository.
6
+ Content can be written in [Markdown] or [Textile], stored in text files on your
7
+ computer. There is no database.
9
8
 
10
- [frank]: http://www.sinatrarb.com/ "Sinatra"
11
- [markdown]: http://daringfireball.net/projects/markdown/
12
- [textile]: http://textism.com/tools/textile/
9
+ You do your writing in your text editor.
10
+
11
+ Publish by pushing your changes to a git repository that's setup to deploy your
12
+ changes to the web.
13
+
14
+ [Sinatra]: http://www.sinatrarb.com/ "Sinatra"
15
+ [Markdown]: http://daringfireball.net/projects/markdown/
16
+ [Textile]: http://textism.com/tools/textile/
13
17
 
14
18
  ## Installation
15
19
 
16
- Begin by installing the gem:
20
+ Begin by [installing Ruby], then the Nesta gem:
17
21
 
18
22
  $ gem install nesta
19
23
 
20
- Then use the `nesta` command to generate a new site:
24
+ Use the `nesta` command to generate a new site:
21
25
 
22
- $ nesta new mysite.com --git
26
+ $ nesta new mysite.com --git # a git repo is optional, but recommended
23
27
 
24
28
  Install a few dependencies, and you're away:
25
29
 
26
30
  $ cd mysite.com
27
31
  $ bundle
28
32
 
29
- You'll find basic configuration options for your site in
30
- `config/config.yml`. The defaults will work, but you'll want to tweak it
31
- before you go very far.
33
+ You'll find configuration options for your site in `config/config.yml`. The
34
+ defaults will work, but you'll want to tweak it before you go very far.
32
35
 
33
36
  That's it - you can launch a local web server in development mode using
34
37
  mr-sparkle...
@@ -36,34 +39,43 @@ mr-sparkle...
36
39
  $ bundle exec mr-sparkle config.ru
37
40
 
38
41
  ...then point your web browser at http://localhost:8080. Start editing
39
- the files in `content/pages` (see the [docs on writing content][] for
40
- full instructions).
42
+ the files in `content/pages` (see the [docs on writing content] for full
43
+ instructions).
44
+
45
+ You can either [deploy it] behind a web server, or build a static version of
46
+ your site:
47
+
48
+ $ nesta build # but see config.yml for related settings
41
49
 
42
- [docs on writing content]: http://nestacms.com/docs/creating-content
50
+ [installing Ruby]: https://www.ruby-lang.org/en/documentation/installation/
51
+ [docs on writing content]: http://nestacms.com/docs/creating-content/
52
+ [deploy it]: https://nestacms.com/docs/deployment/
43
53
 
44
54
  ## Support
45
55
 
46
56
  There's plenty of information on <http://nestacms.com>. If you need some
47
57
  help with anything feel free to file an issue, or contact me on Mastodon
48
- (@gma@hachyderm.io) or Twitter (@grahamashton).
58
+ ([@gma@hachyderm.io]) or Twitter ([@grahamashton]).
49
59
 
50
- If you like Nesta you can keep up with developments by following [@nestacms][]
51
- on Twitter, and on [the blog][].
60
+ If you like Nesta you can keep up with developments by following [@nestacms]
61
+ on Twitter, and on [the blog].
52
62
 
53
- [@nestacms]: http://twitter.com/nestacms
54
- [the blog]: http://nestacms.com/blog
63
+ [@gma@hachyderm.io]: https://hachyderm.io/@gma
64
+ [@grahamashton]: https://twitter.com/grahamashton
65
+ [@nestacms]: https://twitter.com/nestacms
66
+ [the blog]: https://nestacms.com/blog
55
67
 
56
68
  ![Tests](https://github.com/gma/nesta/actions/workflows/tests.yml/badge.svg)
57
69
 
58
70
  ## Contributing
59
71
 
60
- If you want to add a new feature, I recommend that you file an issue to discuss
61
- it before you start coding. I'm likely to suggest that we implement it as a
62
- [plugin][] (to keep Nesta itself lean and simple), so you might save yourself
63
- some time if we chat about a good approach before you start.
72
+ If you want to add a new feature, please [create an issue] to discuss it before
73
+ you start coding. I might suggest that we implement it as a [plugin] (to keep
74
+ Nesta itself lean and simple), or be able to chip in with ideas on how to
75
+ approach it.
64
76
 
65
- [plugin]: http://nestacms.com/docs/plugins
77
+ [create an issue]: https://github.com/gma/nesta/issues/new
78
+ [plugin]: https://nestacms.com/docs/plugins
66
79
 
67
- -- Graham ([@grahamashton][] on Twitter).
80
+ -- Graham
68
81
 
69
- [@grahamashton]: http://twitter.com/grahamashton
data/RELEASING.md CHANGED
@@ -8,15 +8,16 @@ the steps:
8
8
 
9
9
  2. Bump the version number in `lib/nesta/version.rb`. This will cause
10
10
  the version number in `Gemfile.lock` to be updated too, so regenerate
11
- it now and check them in together.
11
+ it now (e.g. run `bundle install`) and check them in together.
12
12
 
13
- 3. Update the `CHANGES` file with a summary of significant changes since
13
+ 3. Update the `CHANGLOG.md` file with a summary of significant changes since
14
14
  the previous release.
15
15
 
16
16
  4. Commit these changes with a commit message of 'Bump version to <version>'
17
17
 
18
- 5. Generate a new site with the `nesta` command, install the demo content,
19
- check that it runs okay locally.
18
+ 5. Install the gem locally (`rake install`), then generate a new site
19
+ with the `nesta` command. Install the demo content site, check that
20
+ it runs okay locally.
20
21
 
21
22
  6. If everything seems fine, run `rake release`.
22
23
 
data/lib/nesta/config.rb CHANGED
@@ -33,10 +33,11 @@ module Nesta
33
33
  setting = setting.to_s
34
34
  self.config ||= read_config_file(setting)
35
35
  env_config = config.fetch(Nesta::App.environment.to_s, {})
36
- env_config.fetch(
37
- setting,
38
- config.fetch(setting) { raise NotDefined.new(setting) }
39
- )
36
+ env_config.fetch(setting) do
37
+ config.fetch(setting) do
38
+ raise NotDefined.new(setting)
39
+ end
40
+ end
40
41
  rescue NotDefined
41
42
  default.empty? && raise || (return default.first)
42
43
  end
@@ -0,0 +1,195 @@
1
+ def register_template_handler(class_name, *extensions)
2
+ Tilt.register Tilt.const_get(class_name), *extensions
3
+ rescue LoadError
4
+ # Only one of the Markdown processors needs to be available, so we can
5
+ # safely ignore these load errors.
6
+ end
7
+
8
+ register_template_handler :MarukuTemplate, 'mdown', 'md'
9
+ register_template_handler :KramdownTemplate, 'mdown', 'md'
10
+ register_template_handler :RDiscountTemplate, 'mdown', 'md'
11
+ register_template_handler :RedcarpetTemplate, 'mdown', 'md'
12
+
13
+
14
+ module Nesta
15
+ class MetadataParseError < RuntimeError; end
16
+
17
+ class FileModel
18
+ FORMATS = [:mdown, :md, :haml, :textile]
19
+ @@model_cache = {}
20
+ @@filename_cache = {}
21
+
22
+ attr_reader :filename, :mtime
23
+
24
+ class CaseInsensitiveHash < Hash
25
+ def [](key)
26
+ super(key.to_s.downcase)
27
+ end
28
+ end
29
+
30
+ def self.model_path(basename = nil)
31
+ Nesta::Config.content_path(basename)
32
+ end
33
+
34
+ def self.find_all
35
+ file_pattern = File.join(model_path, "**", "*.{#{FORMATS.join(',')}}")
36
+ Dir.glob(file_pattern).map do |path|
37
+ relative = path.sub("#{model_path}/", "")
38
+ load(relative.sub(/\.(#{FORMATS.join('|')})/, ""))
39
+ end
40
+ end
41
+
42
+ def self.find_file_for_path(path)
43
+ if ! @@filename_cache.has_key?(path)
44
+ FORMATS.each do |format|
45
+ [path, File.join(path, 'index')].each do |basename|
46
+ filename = model_path("#{basename}.#{format}")
47
+ if File.exist?(filename)
48
+ @@filename_cache[path] = filename
49
+ break
50
+ end
51
+ end
52
+ end
53
+ end
54
+ @@filename_cache[path]
55
+ end
56
+
57
+ def self.needs_loading?(path, filename)
58
+ @@model_cache[path].nil? || File.mtime(filename) > @@model_cache[path].mtime
59
+ end
60
+
61
+ def self.load(path)
62
+ if (filename = find_file_for_path(path)) && needs_loading?(path, filename)
63
+ @@model_cache[path] = self.new(filename)
64
+ end
65
+ @@model_cache[path]
66
+ end
67
+
68
+ def self.purge_cache
69
+ @@model_cache = {}
70
+ @@filename_cache = {}
71
+ end
72
+
73
+ def initialize(filename)
74
+ @filename = filename
75
+ @format = filename.split('.').last.to_sym
76
+ if File.zero?(filename)
77
+ @metadata = {}
78
+ @markup = ''
79
+ else
80
+ @metadata, @markup = parse_file
81
+ end
82
+ @mtime = File.mtime(filename)
83
+ end
84
+
85
+ def ==(other)
86
+ other.respond_to?(:path) && (self.path == other.path)
87
+ end
88
+
89
+ def index_page?
90
+ @filename =~ /\/?index\.\w+$/
91
+ end
92
+
93
+ def abspath
94
+ file_path = @filename.sub(self.class.model_path, '')
95
+ if index_page?
96
+ File.dirname(file_path)
97
+ else
98
+ File.join(File.dirname(file_path), File.basename(file_path, '.*'))
99
+ end
100
+ end
101
+
102
+ def path
103
+ abspath.sub(/^\//, '')
104
+ end
105
+
106
+ def permalink
107
+ File.basename(path)
108
+ end
109
+
110
+ def layout
111
+ (metadata('layout') || 'layout').to_sym
112
+ end
113
+
114
+ def template
115
+ (metadata('template') || 'page').to_sym
116
+ end
117
+
118
+ def to_html(scope = Object.new)
119
+ convert_to_html(@format, scope, markup)
120
+ end
121
+
122
+ def last_modified
123
+ @last_modified ||= File.stat(@filename).mtime
124
+ end
125
+
126
+ def description
127
+ metadata('description')
128
+ end
129
+
130
+ def keywords
131
+ metadata('keywords')
132
+ end
133
+
134
+ def metadata(key)
135
+ @metadata[key]
136
+ end
137
+
138
+ def flagged_as?(flag)
139
+ flags = metadata('flags')
140
+ flags && flags.split(',').map { |name| name.strip }.include?(flag)
141
+ end
142
+
143
+ def parse_metadata(first_paragraph)
144
+ is_metadata = first_paragraph.split("\n").first =~ /^[\w ]+:/
145
+ raise MetadataParseError unless is_metadata
146
+ metadata = CaseInsensitiveHash.new
147
+ first_paragraph.split("\n").each do |line|
148
+ key, value = line.split(/\s*:\s*/, 2)
149
+ next if value.nil?
150
+ metadata[key.downcase] = value.chomp
151
+ end
152
+ metadata
153
+ end
154
+
155
+ private
156
+
157
+ def markup
158
+ @markup
159
+ end
160
+
161
+ def parse_file
162
+ contents = File.open(@filename).read
163
+ rescue Errno::ENOENT
164
+ raise Sinatra::NotFound
165
+ else
166
+ first_paragraph, remaining = contents.split(/\r?\n\r?\n/, 2)
167
+ begin
168
+ return parse_metadata(first_paragraph), remaining
169
+ rescue MetadataParseError
170
+ return {}, contents
171
+ end
172
+ end
173
+
174
+ def add_p_tags_to_haml(text)
175
+ contains_tags = (text =~ /^\s*%/)
176
+ if contains_tags
177
+ text
178
+ else
179
+ text.split(/\r?\n/).inject('') do |accumulator, line|
180
+ accumulator << "%p #{line}\n"
181
+ end
182
+ end
183
+ end
184
+
185
+ def convert_to_html(format, scope, text)
186
+ text = add_p_tags_to_haml(text) if @format == :haml
187
+ template = Tilt[format].new(renderer_config(@format)) { text }
188
+ template.render(scope)
189
+ end
190
+
191
+ def renderer_config(format)
192
+ {}
193
+ end
194
+ end
195
+ end