foresite 1.1.3

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 495db3b9b94366d4ec2ee21650912ce9f545ccab88a5206aebf49e6cb08cfee8
4
+ data.tar.gz: 1712e43ee2800c9158fb54879423693b5f764e0f7ad53565ebff9151c76e322d
5
+ SHA512:
6
+ metadata.gz: 3079e9d70d3d1020d209251caeb1bc85b6a286d9db03bb9a29a8abfaecdbb0522f815b8680ceab129a4247388dfe2d5d8326c275f975c3b1608b83fea18b1f6d
7
+ data.tar.gz: e5263d34aea71db355288285d168e607fbfe30415bbc19b5eb2679bddbf48ebc255118e58b8c7bfa13ea2f1fbf24bca4e3c5136a4c62e4bbdd7d9e8e71c085fa
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Carl Wiedemann
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,128 @@
1
+ # Foresite
2
+
3
+ An extremely minimal static site generator.
4
+
5
+ CLI executable that converts markdown wrapped in a single template to static HTML for simple blogs hosted on [GitHub Pages](https://pages.github.com/) or similar.
6
+
7
+ ## Installation
8
+
9
+ The only requirement is Ruby >= 2.7.0.
10
+
11
+ $ gem install foresite
12
+
13
+ ## Quick start: Hello World
14
+
15
+ $ mkdir my_blog # Create a project directory
16
+
17
+ $ cd my_blog
18
+
19
+ $ foresite init # Initialize
20
+
21
+ $ foresite touch "Hello World" # Create markdown post titled "Hello World"
22
+
23
+ $ foresite build # Converts markdown to HTML
24
+
25
+ ![Screenshot of Hello World post](screenshot.png)
26
+
27
+ ## Getting started guide
28
+
29
+ ### 1. Create your project directory
30
+
31
+ Create a project directory for your site and run `foresite init` from within it:
32
+
33
+ $ mkdir my_blog
34
+
35
+ $ cd my_blog
36
+
37
+ $ foresite init
38
+ Created md/
39
+ Created post/
40
+ Created erb/
41
+ Created erb/post.md.erb
42
+ Created erb/wrapper.html.erb
43
+ Created erb/_list.html.erb
44
+
45
+ Three subdirectories are created, along with three [ERB](https://docs.ruby-lang.org/en/3.2/ERB.html) template files.
46
+
47
+ Some facts:
48
+
49
+ * `md` subdirectory will contain markdown files known as posts, which are your site's content.
50
+ * `post` subdirectory will contain HTML files generated from the markdown posts with the exception of an `index.html` file listing all posts, which will exist in the top-level project directory.
51
+ * `erb` subdirectory contains [ERB](https://docs.ruby-lang.org/en/3.2/ERB.html) templates you can modify:
52
+ * `post.md.erb` is the default markdown file for every post.
53
+ * `wrapper.html.erb` is a HTML wrapper template for every generated HTML file.
54
+ * `_list.html.erb` is a HTML template partial for the list of posts on the `index.html` page.
55
+
56
+ ### 2. Write your first post
57
+
58
+ Run `foresite touch` to generate a new post in the `md` subdirectory. The title is its sole argument.
59
+
60
+ $ foresite touch "Welcome to my site"
61
+ Created md/2023-01-15-welcome-to-my-site.md
62
+
63
+ $ cat md/2023-01-15-welcome-to-my-site.md
64
+ # Welcome to my site
65
+
66
+ 2023-01-15
67
+
68
+ A single markdown file is created in the `md` subdirectory. **This file is meant for you to edit.**
69
+
70
+ Some facts:
71
+
72
+ * The title is the first line formatted as H1 (mandatory).
73
+ * Current date in YYYY-MM-DD format is the first markdown paragraph (optional).
74
+ * Current date and title are "slugified" for filename.
75
+
76
+ ### 3. Modify templates as desired
77
+
78
+ `post.md.erb` is used to when running `foresite touch` for the default markdown content. It has two variables, `@title` for the post title and `@date_ymd` for the created date in ISO 8601 `YYYY-MM-DD` format. Modify to have different defaults when running `foresite touch`.
79
+
80
+ `wrapper.html.erb` wraps all of your markdown. Its sole variable `@content` will be a given post's HTML (converted from markdown). For the `index.html` file, `@content` will be an list of links to all posts in reverse-chronological order. Modify to have different overall page structure, or to add `<style>` etc.
81
+
82
+ `_list.html.erb` is used to generate the `<ul>` list of posts on the `index.html` file. Modify to show posts in a different way.
83
+
84
+ ### 4. Generate HTML from markdown
85
+
86
+ Run `foresite build` to create HTML in the `post` subdirectory and the `index.html` file:
87
+
88
+ $ foresite build
89
+ Created post/2023-01-15-welcome-to-my-site.html
90
+ Created index.html
91
+
92
+ In this example, two HTML files are created.
93
+
94
+ Some facts:
95
+
96
+ * For every post markdown file in the `md` subdirectory an equivalent HTML file is generated in the `post` subdirectory, each wrapped with wrapper template markup.
97
+ * A single `index.html` file shows a list of links to all posts in reverse-chronological order, prefixed with post date.
98
+ * Post titles are parsed from the first H1 tag in each post markdown file.
99
+ * Post dates are parsed from the post markdown filename.
100
+ * Re-running `foresite build` removes and recreates all HTML files in the `post` subdirectory as well as the `index.html` file.
101
+
102
+ In this example, the `index.html` will contain:
103
+
104
+ ```html
105
+ <ul>
106
+ <li>2023-01-15 <a href="2023-01-15-welcome-to-my-site.html">Welcome to my site</a></li>
107
+ </ul>
108
+ ```
109
+
110
+ ## Development
111
+
112
+ 1. Clone
113
+ 2. `bundle` to install dependencies
114
+ 3. `bundle exec rake` to run tests & linter
115
+
116
+ To install this gem from local source, run `bundle exec rake install:local`.
117
+
118
+ ## Contributing
119
+
120
+ Bug reports and pull requests are welcome. The goals of Foresite are:
121
+
122
+ * Extremely lightweight
123
+ * Simple to use & understand
124
+ * Minimal features
125
+
126
+ ## License
127
+
128
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/foresite ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/foresite'
3
+ Foresite::Cli.start
@@ -0,0 +1,120 @@
1
+ module Foresite
2
+ ##
3
+ # Cli class.
4
+ #
5
+ # For CLI functionality to generate static content.
6
+ #
7
+ class Cli < ::Thor
8
+ ##
9
+ # Ensure that failures exit with a status of zero.
10
+ #
11
+ def self.exit_on_failure?
12
+ true
13
+ end
14
+
15
+ desc "init", "Initializes foresite in current directory"
16
+ long_desc <<-LONGDESC
17
+ Initializes foresite in the current directory.
18
+
19
+ Creates `#{Foresite::DIRNAME_MARKDOWN}/` for storing editable markdown posts, `#{Foresite::DIRNAME_POST}/` for storing generated HTML, and `#{Foresite::DIRNAME_ERB}` for storing editable template.
20
+
21
+ Does not overwrite existing subdirectories.
22
+ LONGDESC
23
+
24
+ def init
25
+ unless Foresite.root_exists?
26
+ warn("Nonexistent directory #{Foresite.get_path_to_root}")
27
+ exit(1)
28
+ end
29
+
30
+ unless Foresite.root_writable?
31
+ warn("Cannot write to directory #{Foresite.get_path_to_root}")
32
+ exit(1)
33
+ end
34
+
35
+ Foresite.touch_directories.map { $stdout.puts(_1) }
36
+ Foresite.copy_templates.map { $stdout.puts(_1) }
37
+ end
38
+
39
+ desc "touch [TITLE]", "Creates new `.md` file with TITLE in `#{Foresite::DIRNAME_MARKDOWN}` directory"
40
+ long_desc <<-LONGDESC
41
+ Creates a markdown file for usage as a post, with optional title.
42
+
43
+ The name of the file will be the current date suffixed by the `TITLE` argument. The current date will be formatted as `YYYY-MM-DD` and the title will be transformed to use lowercase alphanumeric characters, separated by hyphens.
44
+
45
+ Example: (If today is 14 January 2023, and the command is run from /Users/carlos/my_project)
46
+
47
+ $ foresite touch "Happy new year!"
48
+ \x5> Created #{Foresite::DIRNAME_MARKDOWN}/2023-01-14-happy-new-year.md
49
+ LONGDESC
50
+
51
+ def touch(title)
52
+ unless Foresite.subdirectories_exist?
53
+ warn("Missing subdirectories, try running `foresite init`")
54
+ exit(1)
55
+ end
56
+
57
+ date_ymd = Time.now.strftime("%F")
58
+ slug = title.downcase.gsub(/[^a-z]/i, " ").strip.gsub(/ +/, "-")
59
+
60
+ path = Foresite.get_path_to_md_file("#{date_ymd}-#{slug}.md")
61
+
62
+ if File.exist?(path)
63
+ $stdout.puts("File #{Foresite.relative_path(path)} already exists")
64
+ else
65
+ File.write(path, Foresite.render_post(title, date_ymd))
66
+ $stdout.puts("Created #{Foresite.relative_path(path)}")
67
+ end
68
+ end
69
+
70
+ desc "build", "Generates HTML from markdown into `#{Foresite::DIRNAME_POST}` directory"
71
+ long_desc <<-LONGDESC
72
+ Creates HTML files from all markdown posts and writes them to the `#{Foresite::DIRNAME_POST}` directory.
73
+
74
+ The names of the HTML files match corresponding markdown files with extension `.html` instead of `.md`.
75
+ LONGDESC
76
+
77
+ def build
78
+ unless Foresite.subdirectories_exist?
79
+ warn("Missing subdirectories, try running `foresite init`")
80
+ exit(1)
81
+ end
82
+
83
+ # Wipe all output files.
84
+ Dir.glob(File.join(Foresite.get_path_to_out, "*.html")).each { File.delete(_1) }
85
+ File.delete(Foresite.get_path_to_index_file) if File.exist?(Foresite.get_path_to_index_file)
86
+
87
+ markdown_paths = Dir.glob(File.join(Foresite.get_path_to_md, "*.md"))
88
+
89
+ if markdown_paths.count == 0
90
+ warn("No markdown files, try running `foresite touch`")
91
+ exit(1)
92
+ end
93
+
94
+ links = markdown_paths.map do |markdown_path|
95
+ markdown_content = File.read(markdown_path)
96
+
97
+ filename_markdown = File.basename(markdown_path)
98
+ html_path = Foresite.get_path_to_out_file(filename_markdown.gsub(/\.md$/, ".html"))
99
+
100
+ File.write(html_path, Foresite.render_wrapped(markdown_content))
101
+ $stdout.puts("Created #{Foresite.relative_path(html_path)}")
102
+
103
+ # Extract date if it exists.
104
+ match_data = /\d{4}-\d{2}-\d{2}/.match(filename_markdown)
105
+
106
+ {
107
+ date_ymd: match_data.nil? ? "" : match_data[0],
108
+ href: Foresite.relative_path(html_path),
109
+ title: markdown_content.split("\n").first { |line| /^# [a-z]/i =~ line }.gsub(/^#/, "").strip
110
+ }
111
+ end
112
+
113
+ # Generate index file.
114
+ index_html_path = Foresite.get_path_to_index_file
115
+ File.write(index_html_path, Foresite.render_wrapped_index(links))
116
+
117
+ $stdout.puts("Created #{Foresite.relative_path(index_html_path)}")
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,43 @@
1
+ module Foresite
2
+ ##
3
+ # Renderer class.
4
+ #
5
+ # Basic implementation of ERB for a path to a given template and variables.
6
+ #
7
+ class Renderer
8
+ ##
9
+ # Constructor.
10
+ #
11
+ # @param [String] path Path to file.
12
+ # @param [Hash] vars Variables for template.
13
+ def initialize(path, vars)
14
+ @path = path
15
+ vars.each do |k, v|
16
+ if k.is_a?(Symbol)
17
+ instance_variable_set("@#{k}".to_sym, v)
18
+ end
19
+ end
20
+ end
21
+
22
+ ##
23
+ # Renders template with variables.
24
+ #
25
+ # @return [String] Rendered template output.
26
+ #
27
+ def render
28
+ ::ERB.new(File.read(@path), trim_mode: "-").result(binding)
29
+ end
30
+
31
+ ##
32
+ # Statically renders template with variables.
33
+ #
34
+ # @param [String] path Path to file.
35
+ # @param [Hash] vars Variables for template.
36
+ #
37
+ # @return [String] Rendered template output.
38
+ #
39
+ def self.render(path, vars)
40
+ new(path, vars).render
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Foresite
4
+ VERSION = "1.1.3"
5
+ end
data/lib/foresite.rb ADDED
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "thor"
5
+ require "kramdown"
6
+ require "zeitwerk"
7
+
8
+ loader = Zeitwerk::Loader.for_gem
9
+ loader.setup
10
+
11
+ module Foresite
12
+ DIRNAME_MARKDOWN = "md"
13
+ DIRNAME_POST = "post"
14
+ DIRNAME_ERB = "erb"
15
+
16
+ FILENAME_POST_MD = "post.md.erb"
17
+ FILENAME_WRAPPER_HTML = "wrapper.html.erb"
18
+ FILENAME_LIST_HTML = "_list.html.erb"
19
+
20
+ ENV_ROOT = "FORESITE_ROOT"
21
+
22
+ PATH_TO_DEFAULTS = File.join(__dir__, "skeleton")
23
+
24
+ def self.get_path_to_root
25
+ ENV[ENV_ROOT] || Dir.pwd
26
+ end
27
+
28
+ def self.root_exists?
29
+ Dir.exist?(get_path_to_root)
30
+ end
31
+
32
+ def self.root_writable?
33
+ File.writable?(get_path_to_root)
34
+ end
35
+
36
+ def self.subdirectories_exist?
37
+ [get_path_to_md, get_path_to_out, get_path_to_erb].all? do |path|
38
+ Dir.exist?(path)
39
+ end
40
+ end
41
+
42
+ def self.get_path_to_md
43
+ File.join(get_path_to_root, DIRNAME_MARKDOWN)
44
+ end
45
+
46
+ def self.get_path_to_out
47
+ File.join(get_path_to_root, DIRNAME_POST)
48
+ end
49
+
50
+ def self.get_path_to_erb
51
+ File.join(get_path_to_root, DIRNAME_ERB)
52
+ end
53
+
54
+ def self.get_path_to_erb_file(file)
55
+ File.join(get_path_to_erb, file)
56
+ end
57
+
58
+ def self.get_path_to_md_file(file)
59
+ File.join(get_path_to_md, file)
60
+ end
61
+
62
+ def self.get_path_to_out_file(file)
63
+ File.join(get_path_to_out, file)
64
+ end
65
+
66
+ def self.get_path_to_index_file
67
+ File.join(get_path_to_root, "index.html")
68
+ end
69
+
70
+ def self.relative_path(full_path)
71
+ full_path.gsub(get_path_to_root, "").gsub(Regexp.new("^#{File::SEPARATOR}"), "")
72
+ end
73
+
74
+ def self.render_erb_file(file, vars)
75
+ Renderer.render(get_path_to_erb_file(file), vars)
76
+ end
77
+
78
+ def self.render_post(title, date_ymd)
79
+ render_erb_file(FILENAME_POST_MD, {
80
+ title: title,
81
+ date_ymd: date_ymd
82
+ })
83
+ end
84
+
85
+ def self.render_wrapped(markdown_content)
86
+ render_erb_file(FILENAME_WRAPPER_HTML, {
87
+ content: ::Kramdown::Document.new(markdown_content).to_html
88
+ })
89
+ end
90
+
91
+ def self.render_wrapped_index(links)
92
+ render_erb_file(FILENAME_WRAPPER_HTML, {
93
+ content: render_erb_file(FILENAME_LIST_HTML, {
94
+ links: links.reverse
95
+ })
96
+ })
97
+ end
98
+
99
+ def self.touch_directories
100
+ [get_path_to_md, get_path_to_out, get_path_to_erb].map do |path|
101
+ if Dir.exist?(path)
102
+ "#{relative_path(path)}/ already exists"
103
+ else
104
+ Dir.mkdir(path)
105
+ "Created #{relative_path(path)}/"
106
+ end
107
+ end
108
+ end
109
+
110
+ def self.copy_templates
111
+ [FILENAME_POST_MD, FILENAME_WRAPPER_HTML, FILENAME_LIST_HTML].map do |filename|
112
+ full_file_path = File.join(get_path_to_erb, filename)
113
+ if File.exist?(full_file_path)
114
+ "#{relative_path(full_file_path)} already exists"
115
+ else
116
+ File.copy_stream(File.join(PATH_TO_DEFAULTS, filename), full_file_path)
117
+ "Created #{relative_path(full_file_path)}"
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,7 @@
1
+ <% if @links.count > 0 -%>
2
+ <ul>
3
+ <% @links.each do |link| -%>
4
+ <li><%= link[:date_ymd] %> <a href="<%= link[:href] %>"><%= link[:title] %></a></li>
5
+ <% end -%>
6
+ </ul>
7
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ # <%= @title %>
2
+
3
+ <%= @date_ymd %>
4
+
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Another Foresite Blog</title>
6
+ <style></style>
7
+ </head>
8
+ <body>
9
+ <header>
10
+ <h1><a href="/">Another Foresite Blog</a></h1>
11
+ <nav>
12
+ <ul>
13
+ <li><a href="https://rubygems.org/gems/foresite">Foresite on RubyGems</a></li>
14
+ <li><a href="https://github.com/carlwiedemann/foresite">Foresite on GitHub</a></li>
15
+ </ul>
16
+ </nav>
17
+ </header>
18
+ <main>
19
+ <%= @content %>
20
+ </main>
21
+ <footer></footer>
22
+ </body>
23
+ </html>
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: foresite
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Carl Wiedemann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kramdown
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: zeitwerk
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: standard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '13'
97
+ description:
98
+ email:
99
+ - carl.wiedemann@gmail.com
100
+ executables:
101
+ - foresite
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - Gemfile
106
+ - LICENSE.txt
107
+ - README.md
108
+ - bin/foresite
109
+ - lib/foresite.rb
110
+ - lib/foresite/cli.rb
111
+ - lib/foresite/renderer.rb
112
+ - lib/foresite/version.rb
113
+ - lib/skeleton/_list.html.erb
114
+ - lib/skeleton/post.md.erb
115
+ - lib/skeleton/wrapper.html.erb
116
+ homepage: https://github.com/carlwiedemann/foresite
117
+ licenses:
118
+ - MIT
119
+ metadata:
120
+ homepage_uri: https://github.com/carlwiedemann/foresite
121
+ source_code_uri: https://github.com/carlwiedemann/foresite
122
+ changelog_uri: https://github.com/carlwiedemann/foresite/blob/main/CHANGELOG.md
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 2.7.0
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.4.3
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: An extremely minimal static site generator.
142
+ test_files: []