lanyon 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a1d734e248758a22e846cf73dc15b13a323548a6
4
+ data.tar.gz: b7f4ed547b531a6d746f5a0caf31928af6ad968e
5
+ SHA512:
6
+ metadata.gz: 36f129ec0ff9053464adcfaec6984d10eb04d6d9252538ab4f434ed0fd2de5aeaa3348d68507eb0b906b3664a44d526bd333668ae0a1757f24f526796850106b
7
+ data.tar.gz: 33a2dc54b3b19c0108773903e18d525808875dcce69f98abf725b5f4fe7bc3cc52f97b0d2d61bffce8c89186495bf24cce627c392a4e6b06c97a626f6b96e960
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Marcus Stollsteimer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,106 @@
1
+ Lanyon
2
+ ======
3
+
4
+ Lanyon serves your Jekyll site as a Rack application.
5
+
6
+ Lanyon is a good friend of [Jekyll][jekyll], the static site generator,
7
+ and transforms your website into a [Rack][rack] application.
8
+
9
+ ## Getting Started
10
+
11
+ Assuming you already have a Jekyll project that can be built and
12
+ served using the `jekyll` command line tool, then converting it
13
+ to a Rack application is very simple.
14
+
15
+ 1. Add a `config.ru` file in your project's root directory,
16
+ with the following content:
17
+
18
+ ``` ruby
19
+ require "lanyon"
20
+
21
+ run Lanyon.application
22
+ ```
23
+
24
+ You can specify additional Rack middleware in this file.
25
+
26
+ 2. At the command prompt, build the site and start the web server with
27
+
28
+ ``` sh
29
+ rackup config.ru
30
+ ```
31
+
32
+ You can find an example site in the `demo` directory.
33
+
34
+ Note that Lanyon does not watch for site changes.
35
+ Auto-regeneration similar to Jekyll's `serve` command is
36
+ not supported, and there are no plans to add this feature.
37
+
38
+ Lanyon applications can be served with WEBrick, Thin, Unicorn and many
39
+ other web servers, and they can be deployed to services like e.g. Heroku.
40
+
41
+ ## Installation
42
+
43
+ You can install the Lanyon gem from RubyGems.org with
44
+
45
+ ``` sh
46
+ gem install lanyon
47
+ ```
48
+
49
+ ## Configuration
50
+
51
+ ### Options
52
+
53
+ Jekyll configuration options can be specified in a `_config.yml` file
54
+ or as Lanyon initialization options in `config.ru`.
55
+
56
+ Example:
57
+
58
+ ``` ruby
59
+ run Lanyon.application(:destination => "mysite")
60
+ ```
61
+
62
+ This will set a custom destination path, overriding the default (`_site`)
63
+ and settings from a config file.
64
+ See Jekyll's documentation for more settings.
65
+
66
+ Additional Lanyon initialization options:
67
+
68
+ :config - use given config file (default: "_config.yml")
69
+ :skip_build - whether to skip site generation at startup
70
+ (default: false)
71
+
72
+ Note that on read-only filesystems a site build will fail,
73
+ so you must set `:skip_build => true` in these cases.
74
+
75
+ ### Custum 404 Page
76
+
77
+ You can provide a custom `404.html` file in your site's root directory.
78
+ This can also be a file generated by Jekyll from e.g. Markdown sources.
79
+
80
+ ## Requirements
81
+
82
+ - [Ruby][ruby] 2.0.0 or higher
83
+
84
+ - Gem dependencies (runtime): `jekyll`, `rack`
85
+
86
+ ## Reporting Bugs
87
+
88
+ Report bugs on the Lanyon home page: <https://github.com/stomar/lanyon/>
89
+
90
+ ## Credits
91
+
92
+ Lanyon was inspired by [rack-jekyll][rack-jekyll] and written as a replacement.
93
+
94
+ ## License
95
+
96
+ Copyright &copy; 2015 Marcus Stollsteimer
97
+
98
+ Lanyon is licensed under the [MIT License][MIT].
99
+ See also the included `LICENSE` file for more information.
100
+
101
+
102
+ [ruby]: http://www.ruby-lang.org/
103
+ [jekyll]: http://jekyllrb.com/
104
+ [rack]: http://rack.github.io/
105
+ [rack-jekyll]: https://github.com/adaoraul/rack-jekyll
106
+ [MIT]: http://www.opensource.org/licenses/MIT
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require "rake/testtask"
2
+ require "fileutils"
3
+
4
+
5
+ def gemspec_file
6
+ "lanyon.gemspec"
7
+ end
8
+
9
+
10
+ task :default => [:test]
11
+
12
+ Rake::TestTask.new do |t|
13
+ t.pattern = "test/**/test_*.rb"
14
+ t.verbose = true
15
+ t.warning = true
16
+ end
17
+
18
+
19
+ desc "Build gem"
20
+ task :build do
21
+ sh "gem build #{gemspec_file}"
22
+ end
23
+
24
+
25
+ desc "Remove generated files"
26
+ task :clean do
27
+ FileUtils.rm_rf("demo/_site")
28
+ FileUtils.rm(Dir.glob("*.gem"))
29
+ end
30
+
31
+
32
+ desc "Serve demo site"
33
+ task :demo do
34
+ port = 4000
35
+ puts "Starting server: http://localhost:#{port}/"
36
+ Dir.chdir("demo") { sh "rackup -p #{port} -I ../lib" }
37
+ end
data/demo/404.md ADDED
@@ -0,0 +1,11 @@
1
+ ---
2
+ layout: default
3
+ title: "404: Not Found"
4
+ permalink: 404.html
5
+ ---
6
+
7
+ # 404: Not Found
8
+
9
+ The requested page does not exist.
10
+
11
+ [Go back to home page](/)
data/demo/_config.yml ADDED
@@ -0,0 +1,5 @@
1
+ markdown: kramdown
2
+ permalink: pretty
3
+
4
+ exclude:
5
+ - config.ru
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <link rel="stylesheet" type="text/css" href="/css/site.css">
6
+ {% if page.title != null %}
7
+ <title>Lanyon Demo - {{ page.title }}</title>
8
+ {% else %}
9
+ <title>Lanyon Demo</title>
10
+ {% endif %}
11
+ </head>
12
+ <body>
13
+ {{ content }}
14
+ </body>
15
+ </html>
@@ -0,0 +1,7 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ {{ content }}
6
+
7
+ <p><a href="/">Go back to home page</a></p>
@@ -0,0 +1,8 @@
1
+ ---
2
+ layout: post
3
+ title: Hello World!
4
+ ---
5
+
6
+ # Hello World!
7
+
8
+ A demo blog post for Lanyon.
@@ -0,0 +1,10 @@
1
+ ---
2
+ layout: default
3
+ title: About Lanyon
4
+ ---
5
+
6
+ # About Lanyon
7
+
8
+ Lanyon serves your Jekyll site as a Rack application.
9
+
10
+ [Go back to home page](/)
data/demo/config.ru ADDED
@@ -0,0 +1,6 @@
1
+ require "lanyon"
2
+
3
+ # Rack middleware
4
+ use Rack::Runtime
5
+
6
+ run Lanyon.application
data/demo/css/site.css ADDED
@@ -0,0 +1,6 @@
1
+ body {
2
+ background-color: #f0f0f0;
3
+ font-family: sans-serif;
4
+ }
5
+
6
+ .date { color: #808080; }
data/demo/index.md ADDED
@@ -0,0 +1,18 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ # Lanyon Demo
6
+
7
+ Demo page for the Lanyon gem. [Read more...](about/)
8
+
9
+ Blog posts:
10
+
11
+ <ul>
12
+ {% for post in site.posts %}
13
+ <li>
14
+ <span class="date">{{ post.date | date_to_string }}:</span>
15
+ <a href="{{ post.url }}">{{ post.title }}</a>
16
+ </li>
17
+ {% endfor %}
18
+ </ul>
data/lanyon.gemspec ADDED
@@ -0,0 +1,46 @@
1
+ require_relative "lib/lanyon/version"
2
+
3
+ version = Lanyon::VERSION
4
+ date = Lanyon::DATE
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "lanyon"
8
+ s.version = version
9
+ s.date = date
10
+
11
+ s.summary = "Lanyon serves your Jekyll site as a Rack application."
12
+ s.description =
13
+ "Lanyon is a good friend of Jekyll, the static site generator, " +
14
+ "and transforms your website into a Rack application."
15
+
16
+ s.authors = ["Marcus Stollsteimer"]
17
+ s.email = "sto.mar@web.de"
18
+ s.homepage = "https://github.com/stomar/lanyon/"
19
+
20
+ s.license = "MIT"
21
+
22
+ s.required_ruby_version = ">= 2.0.0"
23
+
24
+ s.add_dependency "jekyll", "~> 2.0"
25
+ s.add_dependency "rack", "~> 1.6"
26
+
27
+ s.add_development_dependency "rake", "~> 10.4"
28
+ s.add_development_dependency "minitest", "~> 5.8"
29
+
30
+ s.require_paths = ["lib"]
31
+
32
+ s.files = %w[
33
+ README.md
34
+ LICENSE
35
+ lanyon.gemspec
36
+ Gemfile
37
+ Rakefile
38
+ .yardopts
39
+ ] +
40
+ Dir.glob("lib/**/*") +
41
+ Dir.glob("test/**/*") +
42
+ Dir.glob("demo/**/*").reject {|f| f =~ %r(\Ademo/_site/) }
43
+
44
+ s.extra_rdoc_files = %w[README.md LICENSE]
45
+ s.rdoc_options = ["--charset=UTF-8", "--main=README.md"]
46
+ end
@@ -0,0 +1,124 @@
1
+ require "rack/mime"
2
+ require "rack/request"
3
+ require "rack/response"
4
+ require "time"
5
+
6
+
7
+ module Lanyon
8
+
9
+ # Rack application that serves the Jekyll site.
10
+ #
11
+ # Not to be instantiated directly, use Lanyon.application instead.
12
+ class Application
13
+
14
+ attr_reader :router
15
+
16
+ def initialize(router)
17
+ @router = router
18
+ end
19
+
20
+ def call(env)
21
+ request = Rack::Request.new(env)
22
+ endpoint = router.endpoint(request.path_info)
23
+
24
+ case endpoint
25
+ when :not_found
26
+ not_found_response
27
+ when :must_redirect
28
+ redirect_to_dir_response(request.path_info)
29
+ else
30
+ case request.request_method
31
+ when "HEAD", "GET"
32
+ response(endpoint)
33
+ when "OPTIONS"
34
+ [200, { "Allow" => "GET,HEAD,OPTIONS", "Content-Length" => "0" }, []]
35
+ else
36
+ not_allowed_response
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def response(filename) # :nodoc:
44
+ response = Rack::Response.new(File.read(filename))
45
+ response["Content-Type"] = media_type(filename)
46
+ response["Last-Modified"] = modification_time(filename)
47
+
48
+ response.finish
49
+ end
50
+
51
+ def html_response(body, status, headers = {}) # :nodoc:
52
+ response = Rack::Response.new(body, status, headers)
53
+ response["Content-Type"] = "text/html"
54
+
55
+ response.finish
56
+ end
57
+
58
+ def media_type(filename) # :nodoc:
59
+ extension = ::File.extname(filename)
60
+
61
+ Rack::Mime.mime_type(extension)
62
+ end
63
+
64
+ def modification_time(filename) # :nodoc:
65
+ File.mtime(filename).httpdate
66
+ end
67
+
68
+ def html_wrap(title, content) # :nodoc:
69
+ <<-document.gsub(/^ {6}/, "")
70
+ <!DOCTYPE html>
71
+ <html lang="en">
72
+ <head>
73
+ <meta charset="utf-8">
74
+ <title>#{title}</title></head>
75
+ <body>
76
+ #{content}
77
+ </body>
78
+ </html>
79
+ document
80
+ end
81
+
82
+ def default_404_body # :nodoc:
83
+ html_wrap("Error", "<p>404: Not Found</p>")
84
+ end
85
+
86
+ def custom_404_body # :nodoc:
87
+ router.custom_404_body
88
+ end
89
+
90
+ def not_found_response # :nodoc:
91
+ body = custom_404_body || default_404_body
92
+
93
+ html_response(body, 404)
94
+ end
95
+
96
+ def not_allowed_response # :nodoc:
97
+ body = html_wrap("Error", "<p>405: Method Not Allowed</p>")
98
+
99
+ html_response(body, 405)
100
+ end
101
+
102
+ def redirect_body(to_path) # :nodoc:
103
+ message = %Q{<p>Redirecting to <a href="#{to_path}">#{to_path}</a>.</p>}
104
+
105
+ html_wrap("Redirection", message)
106
+ end
107
+
108
+ def redirect_to_dir_response(from_path) # :nodoc:
109
+ location = from_path.dup
110
+ location << "/" unless location.end_with?("/")
111
+
112
+ cache_time = 3600
113
+
114
+ body = redirect_body(location)
115
+ headers = {
116
+ "Location" => location,
117
+ "Cache-Control" => "max-age=#{cache_time}, must-revalidate",
118
+ "Expires" => (Time.now + cache_time).httpdate
119
+ }
120
+
121
+ html_response(body, 301, headers)
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,52 @@
1
+ module Lanyon
2
+
3
+ # Router class for Lanyon applications.
4
+ class Router
5
+
6
+ attr_reader :root
7
+
8
+ # Creates a Router for the given root directory.
9
+ def initialize(root)
10
+ @root = File.expand_path(root)
11
+ end
12
+
13
+ # Returns the full file system path of the file corresponding to
14
+ # the given URL +path+, or
15
+ #
16
+ # - +:not_found+ if no corresponding file exists,
17
+ # - +:must_redirect+ if the request must be redirected to <tt>path/</tt>.
18
+ #
19
+ def endpoint(path)
20
+ fullpath = File.join(@root, path)
21
+
22
+ if fullpath.end_with?("/")
23
+ normalized = fullpath + "index.html"
24
+ else
25
+ normalized = fullpath
26
+ end
27
+
28
+ endpoint = if FileTest.file?(normalized)
29
+ normalized
30
+ elsif needs_redirect_to_dir?(normalized)
31
+ :must_redirect
32
+ else
33
+ :not_found
34
+ end
35
+
36
+ endpoint
37
+ end
38
+
39
+ # Returns the body of the custom 404 page or +nil+ if none exists.
40
+ def custom_404_body
41
+ filename = File.join(root, "404.html")
42
+
43
+ File.exist?(filename) ? File.read(filename) : nil
44
+ end
45
+
46
+ private
47
+
48
+ def needs_redirect_to_dir?(fullpath) # :nodoc:
49
+ !fullpath.end_with?("/") && FileTest.file?(fullpath + "/index.html")
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,4 @@
1
+ module Lanyon
2
+ VERSION = '0.2.0'
3
+ DATE = '2015-11-11'
4
+ end
data/lib/lanyon.rb ADDED
@@ -0,0 +1,79 @@
1
+ # = lanyon.rb
2
+ #
3
+ # See Lanyon module for documentation.
4
+
5
+ require "jekyll"
6
+
7
+ require "lanyon/application"
8
+ require "lanyon/router"
9
+ require "lanyon/version"
10
+
11
+
12
+ # Lanyon serves your Jekyll site as a Rack application.
13
+ #
14
+ # See Lanyon.application for available initialization options.
15
+ #
16
+ # Further information on the Lanyon library is available in the README file
17
+ # or on the project home page: <https://github.com/stomar/lanyon/>.
18
+ #
19
+ module Lanyon
20
+
21
+ # Builds the Jekyll site and returns a Rack application.
22
+ #
23
+ # Options:
24
+ #
25
+ # +:config+:: use given config file (default: "_config.yml")
26
+ #
27
+ # +:skip_build+:: whether to skip site generation at startup
28
+ # (default: +false+)
29
+ #
30
+ # Other options are passed on to Jekyll::Site.
31
+ #
32
+ # Returns a Rack application.
33
+ def self.application(options = {})
34
+ skip_build = options.fetch(:skip_build, default_options[:skip_build])
35
+
36
+ config = jekyll_config(options)
37
+
38
+ if skip_build
39
+ puts skip_build_warning
40
+ else
41
+ build(config)
42
+ end
43
+
44
+ destination = config["destination"]
45
+ router = Router.new(destination)
46
+
47
+ Rack::Builder.new do
48
+ use Rack::Head
49
+ use Rack::ConditionalGet
50
+
51
+ run Application.new(router)
52
+ end
53
+ end
54
+
55
+ # @private
56
+ def self.default_options # :nodoc:
57
+ { :skip_build => false }
58
+ end
59
+
60
+ # @private
61
+ def self.jekyll_config(overrides = {}) # :nodoc:
62
+ overrides = overrides.dup
63
+ default_options.each_key {|key| overrides.delete(key) }
64
+
65
+ ::Jekyll.configuration(overrides)
66
+ end
67
+
68
+ # @private
69
+ def self.skip_build_warning # :nodoc:
70
+ "Build warning: Skipping the initial build."
71
+ end
72
+
73
+ # @private
74
+ def self.build(config) # :nodoc:
75
+ site = ::Jekyll::Site.new(config)
76
+ puts "Generating site: #{site.source} -> #{site.dest}"
77
+ site.process
78
+ end
79
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,51 @@
1
+ require "minitest/autorun"
2
+ require "fileutils"
3
+ require "stringio"
4
+ require "rack/mock"
5
+ require "time"
6
+
7
+ require "lanyon"
8
+
9
+
10
+ TEST_DIR = File.expand_path("..", __FILE__)
11
+ TEMP_DIR = File.join(TEST_DIR, "tmp")
12
+
13
+
14
+ def setup_tempdir
15
+ FileUtils.mkdir_p(TEMP_DIR)
16
+
17
+ File.exist?(TEMP_DIR) ? TEMP_DIR : nil
18
+ end
19
+
20
+ def teardown_tempdir
21
+ FileUtils.rm_rf(TEMP_DIR) if File.exist?(TEMP_DIR)
22
+ end
23
+
24
+ def chdir_tempdir
25
+ Dir.chdir(TEMP_DIR)
26
+ end
27
+
28
+ def sourcedir
29
+ File.join(TEST_DIR, "source")
30
+ end
31
+
32
+
33
+ def silence_output
34
+ original_stderr, original_stdout = $stderr, $stdout
35
+ $stderr, $stdout = StringIO.new, StringIO.new
36
+
37
+ yield
38
+ ensure
39
+ $stderr, $stdout = original_stderr, original_stdout
40
+ end
41
+
42
+
43
+ def file_must_exist(filename)
44
+ assert File.exist?(filename),
45
+ "Expected file `#{filename}' to exist."
46
+ end
47
+
48
+ def file_wont_exist(filename)
49
+ assert !File.exist?(filename),
50
+ "Expected file `#{filename}' to not exist."
51
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ ---
3
+
4
+ A Blog Post
@@ -0,0 +1,4 @@
1
+ ---
2
+ ---
3
+
4
+ ¡Buenos días!
@@ -0,0 +1 @@
1
+ /* CSS */
@@ -0,0 +1,4 @@
1
+ ---
2
+ ---
3
+
4
+ Index of dir-with-index/
@@ -0,0 +1,4 @@
1
+ ---
2
+ ---
3
+
4
+ Test
@@ -0,0 +1,4 @@
1
+ ---
2
+ ---
3
+
4
+ Home Page
@@ -0,0 +1 @@
1
+ // JavaScript
@@ -0,0 +1 @@
1
+ Test