siru 0.3.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/Gemfile +19 -0
- data/README.md +164 -0
- data/bin/siru +89 -0
- data/lib/siru/builder.rb +126 -0
- data/lib/siru/cli.rb +155 -0
- data/lib/siru/config.rb +92 -0
- data/lib/siru/post.rb +92 -0
- data/lib/siru/server.rb +57 -0
- data/lib/siru/site.rb +47 -0
- data/lib/siru/theme.rb +56 -0
- data/lib/siru.rb +23 -0
- data/siru.gemspec +30 -0
- data/themes/paper/layouts/baseof.liquid +39 -0
- data/themes/paper/layouts/index.liquid +17 -0
- data/themes/paper/layouts/post.liquid +13 -0
- data/themes/paper/layouts/single.liquid +18 -0
- data/themes/paper/static/assets/style.css +24 -0
- data/themes/paper+/layouts/baseof.liquid +39 -0
- data/themes/paper+/layouts/index.liquid +17 -0
- data/themes/paper+/layouts/post.liquid +13 -0
- data/themes/paper+/layouts/single.liquid +18 -0
- data/themes/paper+/static/assets/style.css +73 -0
- data/themes/paper+/static/bluesky.svg +1 -0
- data/themes/paper+/static/mastodon.svg +1 -0
- data/themes/paper+/static/nostr.svg +13 -0
- data/themes/paper+/static/twitter.svg +1 -0
- metadata +236 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a129c8c8137e9ef0ffef0839973bbf761105a083edbbd3ba1b519e61a521dfbe
|
4
|
+
data.tar.gz: 8341a02414f843007b01dba2527c6d6a21ef96c0dd447eb4eb91353200e50e23
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f4d9b74fa3257a7ecb91b1ff0b188949cfa2db8b6012957e3e7735f64a0d37648cea45d6cbb00a6adf4bed78a1c18f685112fd7f3710060d18a526c1e34f6879
|
7
|
+
data.tar.gz: 2afb22464e6303caee943ddfc2d2dc24ec35df002be29b6f07f4bafbeefa4e0c13c5ccb11fc896931aea948cb8ff7f40e29c5852656684f54c242819adb34e4c
|
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'redcarpet', '~> 3.6'
|
4
|
+
gem 'liquid', '~> 5.4'
|
5
|
+
gem 'toml', '~> 0.3'
|
6
|
+
gem 'sassc', '~> 2.4'
|
7
|
+
gem 'listen', '~> 3.8'
|
8
|
+
gem 'webrick', '~> 1.8'
|
9
|
+
gem 'front_matter_parser', '~> 1.0'
|
10
|
+
gem 'fileutils'
|
11
|
+
gem 'pathname'
|
12
|
+
gem 'yaml'
|
13
|
+
gem 'base64'
|
14
|
+
gem 'logger'
|
15
|
+
|
16
|
+
group :development do
|
17
|
+
gem 'rspec', '~> 3.12'
|
18
|
+
gem 'rubocop', '~> 1.56'
|
19
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# Siru
|
2
|
+
|
3
|
+
Siru is a static site generator inspired by [Hugo](https://gohugo.io/), built with Ruby.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
- Markdown content rendering
|
7
|
+
- Theme support
|
8
|
+
- Live server with reload
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
### Via APT Repository (Ubuntu/Debian)
|
13
|
+
|
14
|
+
```bash
|
15
|
+
# Add the repository
|
16
|
+
echo "deb [trusted=yes arch=amd64] https://raw.githubusercontent.com/timappledotcom/siru-apt-repo/main/ stable main" | sudo tee /etc/apt/sources.list.d/siru.list
|
17
|
+
|
18
|
+
# Update package list
|
19
|
+
sudo apt update
|
20
|
+
|
21
|
+
# Install Siru
|
22
|
+
sudo apt install siru
|
23
|
+
```
|
24
|
+
|
25
|
+
### Via .deb Package
|
26
|
+
|
27
|
+
```bash
|
28
|
+
wget https://github.com/timappledotcom/siru/releases/download/v0.2.0/siru_0.2.0_all.deb
|
29
|
+
sudo dpkg -i siru_0.2.0_all.deb
|
30
|
+
```
|
31
|
+
|
32
|
+
### Via Flatpak
|
33
|
+
|
34
|
+
```bash
|
35
|
+
flatpak install --user siru-0.2.0.flatpak
|
36
|
+
```
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
1. **Create a new site**
|
41
|
+
```
|
42
|
+
siru new [sitename]
|
43
|
+
```
|
44
|
+
|
45
|
+
2. **Create a new post**
|
46
|
+
|
47
|
+
**Quick method (auto-generates and opens in editor):**
|
48
|
+
```
|
49
|
+
siru new post "My Post Title"
|
50
|
+
siru new post "My Draft Post" --draft
|
51
|
+
```
|
52
|
+
|
53
|
+
This command will:
|
54
|
+
- Create a new markdown file in `content/posts/`
|
55
|
+
- Generate a filename from the title (e.g., "my-post-title.md")
|
56
|
+
- Add proper front matter with title, date, and draft status
|
57
|
+
- Open the file in your default editor (set via `$EDITOR` or `$VISUAL`)
|
58
|
+
|
59
|
+
**Manual method:**
|
60
|
+
- Navigate to the `content/posts/` directory.
|
61
|
+
- Create a new Markdown file with TOML or YAML front matter:
|
62
|
+
|
63
|
+
```toml
|
64
|
+
+++
|
65
|
+
title = "My Awesome Post"
|
66
|
+
date = "2025-07-14"
|
67
|
+
draft = true
|
68
|
+
+++
|
69
|
+
|
70
|
+
Content goes here.
|
71
|
+
```
|
72
|
+
|
73
|
+
3. **Create a new page**
|
74
|
+
- Navigate to the `content/` directory (not inside `posts`).
|
75
|
+
- Create a new Markdown file:
|
76
|
+
|
77
|
+
```toml
|
78
|
+
+++
|
79
|
+
title = "About Us"
|
80
|
+
date = "2025-07-14"
|
81
|
+
draft = true
|
82
|
+
+++
|
83
|
+
|
84
|
+
About us content.
|
85
|
+
```
|
86
|
+
|
87
|
+
4. **Build the site**
|
88
|
+
```
|
89
|
+
cd [sitename]
|
90
|
+
siru build
|
91
|
+
```
|
92
|
+
|
93
|
+
5. **Serve the site**
|
94
|
+
```
|
95
|
+
siru serve
|
96
|
+
```
|
97
|
+
|
98
|
+
### Drafts
|
99
|
+
|
100
|
+
- **Draft Mode**: To include draft posts in your build or serve, add the `--draft` option.
|
101
|
+
|
102
|
+
```bash
|
103
|
+
siru build --draft
|
104
|
+
siru serve --draft
|
105
|
+
```
|
106
|
+
|
107
|
+
- **Draft Status**: Posts with `draft = true` in their front matter will not be published unless the `--draft` option is used.
|
108
|
+
|
109
|
+
## Configuration
|
110
|
+
|
111
|
+
Siru sites are configured through a `config.toml` file in the root directory:
|
112
|
+
|
113
|
+
```toml
|
114
|
+
baseURL = "https://yoursite.com/"
|
115
|
+
languageCode = "en-us"
|
116
|
+
title = "My Awesome Site"
|
117
|
+
theme = "paper"
|
118
|
+
|
119
|
+
[params]
|
120
|
+
color = "linen" # Theme color: linen, wheat, gray, light
|
121
|
+
bio = "Welcome to my blog!"
|
122
|
+
twitter = "yourusername"
|
123
|
+
github = "yourusername"
|
124
|
+
mastodon = "https://mastodon.social/@yourusername"
|
125
|
+
bluesky = "yourusername.bsky.social"
|
126
|
+
```
|
127
|
+
|
128
|
+
## Front Matter
|
129
|
+
|
130
|
+
Siru supports both TOML and YAML front matter:
|
131
|
+
|
132
|
+
### TOML Front Matter
|
133
|
+
```toml
|
134
|
+
+++
|
135
|
+
title = "Post Title"
|
136
|
+
date = "2025-07-14"
|
137
|
+
draft = false
|
138
|
+
tags = ["ruby", "static-site"]
|
139
|
+
summary = "A brief summary of the post"
|
140
|
+
+++
|
141
|
+
```
|
142
|
+
|
143
|
+
### YAML Front Matter
|
144
|
+
```yaml
|
145
|
+
---
|
146
|
+
title: "Post Title"
|
147
|
+
date: "2025-07-14"
|
148
|
+
draft: false
|
149
|
+
tags: ["ruby", "static-site"]
|
150
|
+
summary: "A brief summary of the post"
|
151
|
+
---
|
152
|
+
```
|
153
|
+
|
154
|
+
### Available Front Matter Fields
|
155
|
+
- `title`: Post/page title
|
156
|
+
- `date`: Publication date
|
157
|
+
- `draft`: Whether the content is a draft (true/false)
|
158
|
+
- `tags`: Array of tags for the post
|
159
|
+
- `summary`: Brief description (used in post lists)
|
160
|
+
- `slug`: Custom URL slug (optional)
|
161
|
+
|
162
|
+
## License
|
163
|
+
|
164
|
+
This project is licensed under the terms of the [GPL-3.0 license](LICENSE).
|
data/bin/siru
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/siru'
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
options = {}
|
8
|
+
OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: siru [options] [command]"
|
10
|
+
|
11
|
+
opts.separator ""
|
12
|
+
opts.separator "Commands:"
|
13
|
+
opts.separator " new SITENAME Create a new site"
|
14
|
+
opts.separator " new post TITLE Create a new post"
|
15
|
+
opts.separator " build Build the site"
|
16
|
+
opts.separator " serve Serve the site locally"
|
17
|
+
opts.separator " help Show this help"
|
18
|
+
opts.separator ""
|
19
|
+
opts.separator "Options:"
|
20
|
+
|
21
|
+
opts.on("-p", "--port PORT", "Port to serve on (default: 3000)") do |port|
|
22
|
+
options[:port] = port.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on("-w", "--watch", "Watch for changes and rebuild") do
|
26
|
+
options[:watch] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on("-d", "--draft", "Include draft posts") do
|
30
|
+
options[:draft] = true
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on("-h", "--help", "Show this help") do
|
34
|
+
puts opts
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
end.parse!
|
38
|
+
|
39
|
+
command = ARGV[0]
|
40
|
+
|
41
|
+
case command
|
42
|
+
when 'new'
|
43
|
+
subcommand = ARGV[1]
|
44
|
+
case subcommand
|
45
|
+
when 'post'
|
46
|
+
post_title = ARGV[2..-1].join(' ')
|
47
|
+
if post_title.empty?
|
48
|
+
puts "Error: Please provide a post title"
|
49
|
+
puts "Usage: siru new post TITLE"
|
50
|
+
exit 1
|
51
|
+
end
|
52
|
+
Siru::CLI.new_post(post_title, options)
|
53
|
+
else
|
54
|
+
# Treat as site name for backward compatibility
|
55
|
+
site_name = subcommand
|
56
|
+
if site_name.nil?
|
57
|
+
puts "Error: Please provide a site name or 'post' subcommand"
|
58
|
+
puts "Usage: siru new SITENAME"
|
59
|
+
puts " siru new post TITLE"
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
Siru::CLI.new_site(site_name)
|
63
|
+
end
|
64
|
+
when 'build'
|
65
|
+
Siru::CLI.build(options)
|
66
|
+
when 'serve'
|
67
|
+
Siru::CLI.serve(options)
|
68
|
+
when 'help', nil
|
69
|
+
puts "Siru - A Hugo-inspired static site generator"
|
70
|
+
puts ""
|
71
|
+
puts "Usage: siru [command] [options]"
|
72
|
+
puts ""
|
73
|
+
puts "Commands:"
|
74
|
+
puts " new SITENAME Create a new site"
|
75
|
+
puts " new post TITLE Create a new post"
|
76
|
+
puts " build Build the site"
|
77
|
+
puts " serve Serve the site locally"
|
78
|
+
puts " help Show this help"
|
79
|
+
puts ""
|
80
|
+
puts "Options:"
|
81
|
+
puts " -p, --port PORT Port to serve on (default: 3000)"
|
82
|
+
puts " -w, --watch Watch for changes and rebuild"
|
83
|
+
puts " -d, --draft Include draft posts"
|
84
|
+
puts " -h, --help Show this help"
|
85
|
+
else
|
86
|
+
puts "Unknown command: #{command}"
|
87
|
+
puts "Run 'siru help' for usage information"
|
88
|
+
exit 1
|
89
|
+
end
|
data/lib/siru/builder.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module Siru
|
2
|
+
class Builder
|
3
|
+
def initialize(site, options = {})
|
4
|
+
@site = site
|
5
|
+
@options = options
|
6
|
+
@output_dir = 'public'
|
7
|
+
end
|
8
|
+
|
9
|
+
def build
|
10
|
+
puts "Building site..."
|
11
|
+
|
12
|
+
# Clean output directory
|
13
|
+
FileUtils.rm_rf(@output_dir)
|
14
|
+
FileUtils.mkdir_p(@output_dir)
|
15
|
+
|
16
|
+
# Copy static files
|
17
|
+
copy_static_files
|
18
|
+
|
19
|
+
# Build pages
|
20
|
+
build_home_page
|
21
|
+
build_post_pages
|
22
|
+
|
23
|
+
puts "Site built successfully in #{@output_dir}/"
|
24
|
+
end
|
25
|
+
|
26
|
+
def clean
|
27
|
+
FileUtils.rm_rf(@output_dir)
|
28
|
+
puts "Cleaned output directory: #{@output_dir}"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def copy_static_files
|
34
|
+
# Copy theme static files
|
35
|
+
@site.theme.static_files.each do |file|
|
36
|
+
relative_path = file.gsub(@site.theme.path + '/static/', '')
|
37
|
+
output_path = File.join(@output_dir, relative_path)
|
38
|
+
|
39
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
40
|
+
FileUtils.cp(file, output_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Copy site static files
|
44
|
+
static_dir = 'static'
|
45
|
+
if Dir.exist?(static_dir)
|
46
|
+
Dir.glob(File.join(static_dir, '**', '*')).each do |file|
|
47
|
+
next unless File.file?(file)
|
48
|
+
|
49
|
+
relative_path = file.gsub(static_dir + '/', '')
|
50
|
+
output_path = File.join(@output_dir, relative_path)
|
51
|
+
|
52
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
53
|
+
FileUtils.cp(file, output_path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def build_home_page
|
59
|
+
variables = {
|
60
|
+
'site' => site_variables,
|
61
|
+
'posts' => @site.posts.map { |post| post_variables(post) },
|
62
|
+
'page_title' => 'Home',
|
63
|
+
'bg_color' => color_for_theme
|
64
|
+
}
|
65
|
+
|
66
|
+
content = @site.theme.render_layout('index', variables)
|
67
|
+
html = @site.theme.render_layout('baseof', variables.merge('content' => content))
|
68
|
+
|
69
|
+
File.write(File.join(@output_dir, 'index.html'), html)
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_post_pages
|
73
|
+
@site.posts.each do |post|
|
74
|
+
variables = {
|
75
|
+
'site' => site_variables,
|
76
|
+
'post' => post_variables(post),
|
77
|
+
'page_title' => post.title,
|
78
|
+
'bg_color' => color_for_theme
|
79
|
+
}
|
80
|
+
|
81
|
+
content = @site.theme.render_layout('single', variables)
|
82
|
+
html = @site.theme.render_layout('baseof', variables.merge('content' => content))
|
83
|
+
|
84
|
+
# Create directory structure
|
85
|
+
post_dir = File.join(@output_dir, 'posts', post.slug)
|
86
|
+
FileUtils.mkdir_p(post_dir)
|
87
|
+
|
88
|
+
File.write(File.join(post_dir, 'index.html'), html)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def site_variables
|
93
|
+
{
|
94
|
+
'title' => @site.title,
|
95
|
+
'base_url' => @site.base_url,
|
96
|
+
'language_code' => @site.language_code,
|
97
|
+
'params' => @site.params
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
def post_variables(post)
|
102
|
+
{
|
103
|
+
'title' => post.title,
|
104
|
+
'date' => post.date,
|
105
|
+
'slug' => post.slug,
|
106
|
+
'url' => post.url,
|
107
|
+
'summary' => post.summary,
|
108
|
+
'tags' => post.tags,
|
109
|
+
'rendered_content' => post.rendered_content,
|
110
|
+
'content' => post.content
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def color_for_theme
|
115
|
+
color_map = {
|
116
|
+
'linen' => '#faf8f1',
|
117
|
+
'wheat' => '#f8f5d7',
|
118
|
+
'gray' => '#fbfbfb',
|
119
|
+
'light' => '#fff',
|
120
|
+
'catppuccin-mocha' => '#1e1e2e'
|
121
|
+
}
|
122
|
+
|
123
|
+
color_map[@site.params['color']] || color_map['linen']
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/siru/cli.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
module Siru
|
2
|
+
class CLI
|
3
|
+
def self.new_site(name)
|
4
|
+
puts "Creating new site: #{name}"
|
5
|
+
|
6
|
+
# Get the original working directory from environment variable or current directory
|
7
|
+
original_dir = ENV['CD'] || Dir.pwd
|
8
|
+
target_dir = File.expand_path(name, original_dir)
|
9
|
+
|
10
|
+
FileUtils.mkdir_p(target_dir)
|
11
|
+
Dir.chdir(target_dir) do
|
12
|
+
# Create directory structure
|
13
|
+
%w[content content/posts static themes public].each do |dir|
|
14
|
+
FileUtils.mkdir_p(dir)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create config file
|
18
|
+
config = {
|
19
|
+
'baseURL' => 'http://localhost:3000/',
|
20
|
+
'languageCode' => 'en-us',
|
21
|
+
'title' => name.capitalize,
|
22
|
+
'theme' => 'paper',
|
23
|
+
'params' => {
|
24
|
+
'color' => 'linen',
|
25
|
+
'bio' => 'A blog powered by Siru',
|
26
|
+
'disableHLJS' => true,
|
27
|
+
'disablePostNavigation' => true,
|
28
|
+
'monoDarkIcon' => true,
|
29
|
+
'math' => true,
|
30
|
+
'localKatex' => false
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
File.write('config.toml', TOML::Generator.new(config).body)
|
35
|
+
|
36
|
+
# Create sample post
|
37
|
+
sample_post = <<~POST
|
38
|
+
+++
|
39
|
+
title = "Hello Siru"
|
40
|
+
date = "#{Date.today.strftime('%Y-%m-%d')}"
|
41
|
+
draft = false
|
42
|
+
+++
|
43
|
+
|
44
|
+
Welcome to your new Siru site!
|
45
|
+
|
46
|
+
This is your first post. Edit or delete it and start blogging!
|
47
|
+
POST
|
48
|
+
|
49
|
+
File.write('content/posts/hello-siru.md', sample_post)
|
50
|
+
|
51
|
+
# Copy theme files
|
52
|
+
siru_gem_dir = File.expand_path('../../..', __FILE__)
|
53
|
+
source_theme_dir = File.join(siru_gem_dir, 'themes', 'paper')
|
54
|
+
target_theme_dir = File.join('themes', 'paper')
|
55
|
+
|
56
|
+
if Dir.exist?(source_theme_dir)
|
57
|
+
FileUtils.cp_r(source_theme_dir, 'themes/')
|
58
|
+
puts "Theme 'paper' copied successfully"
|
59
|
+
else
|
60
|
+
puts "Warning: Theme 'paper' not found in #{source_theme_dir}"
|
61
|
+
end
|
62
|
+
|
63
|
+
puts "Site created successfully!"
|
64
|
+
puts "To get started:"
|
65
|
+
puts " cd #{name}"
|
66
|
+
puts " siru serve"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.build(options = {})
|
71
|
+
# Get the original working directory from environment variable or current directory
|
72
|
+
original_dir = ENV['CD'] || Dir.pwd
|
73
|
+
config_path = File.join(original_dir, 'config.toml')
|
74
|
+
|
75
|
+
unless File.exist?(config_path)
|
76
|
+
puts "Error: Not in a Siru site directory. Run 'siru new SITENAME' first."
|
77
|
+
exit 1
|
78
|
+
end
|
79
|
+
|
80
|
+
Dir.chdir(original_dir) do
|
81
|
+
config = Config.load
|
82
|
+
site = Site.new(config, options)
|
83
|
+
builder = Builder.new(site, options)
|
84
|
+
builder.build
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.serve(options = {})
|
89
|
+
# Get the original working directory from environment variable or current directory
|
90
|
+
original_dir = ENV['CD'] || Dir.pwd
|
91
|
+
config_path = File.join(original_dir, 'config.toml')
|
92
|
+
|
93
|
+
unless File.exist?(config_path)
|
94
|
+
puts "Error: Not in a Siru site directory. Run 'siru new SITENAME' first."
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
|
98
|
+
Dir.chdir(original_dir) do
|
99
|
+
config = Config.load
|
100
|
+
site = Site.new(config, options)
|
101
|
+
server = Server.new(site, options)
|
102
|
+
server.start
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.new_post(title, options = {})
|
107
|
+
# Get the original working directory from environment variable or current directory
|
108
|
+
original_dir = ENV['CD'] || Dir.pwd
|
109
|
+
config_path = File.join(original_dir, 'config.toml')
|
110
|
+
|
111
|
+
unless File.exist?(config_path)
|
112
|
+
puts "Error: Not in a Siru site directory. Run 'siru new SITENAME' first."
|
113
|
+
exit 1
|
114
|
+
end
|
115
|
+
|
116
|
+
# Generate filename from title
|
117
|
+
filename = title.downcase.gsub(/\s+/, '-').gsub(/[^a-z0-9\-]/, '') + '.md'
|
118
|
+
filepath = File.join(original_dir, 'content', 'posts', filename)
|
119
|
+
|
120
|
+
# Check if file already exists
|
121
|
+
if File.exist?(filepath)
|
122
|
+
puts "Error: Post '#{filepath}' already exists."
|
123
|
+
exit 1
|
124
|
+
end
|
125
|
+
|
126
|
+
# Create the posts directory if it doesn't exist
|
127
|
+
FileUtils.mkdir_p(File.dirname(filepath))
|
128
|
+
|
129
|
+
# Generate post content
|
130
|
+
date = Date.today.strftime('%Y-%m-%d')
|
131
|
+
draft = options[:draft] ? 'true' : 'false'
|
132
|
+
|
133
|
+
# Clean up the title (remove any surrounding quotes)
|
134
|
+
clean_title = title.gsub(/^["']|["']$/, '')
|
135
|
+
|
136
|
+
post_content = <<~POST
|
137
|
+
+++
|
138
|
+
title = "#{clean_title}"
|
139
|
+
date = "#{date}"
|
140
|
+
draft = #{draft}
|
141
|
+
+++
|
142
|
+
|
143
|
+
Write your post content here.
|
144
|
+
POST
|
145
|
+
|
146
|
+
# Write the file
|
147
|
+
File.write(filepath, post_content)
|
148
|
+
puts "Created new post: #{filepath}"
|
149
|
+
|
150
|
+
# Open in editor
|
151
|
+
editor = ENV['EDITOR'] || ENV['VISUAL'] || 'nano'
|
152
|
+
system("#{editor} #{filepath}")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/lib/siru/config.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module Siru
|
2
|
+
class Config
|
3
|
+
class ConfigError < StandardError; end
|
4
|
+
|
5
|
+
attr_reader :data
|
6
|
+
|
7
|
+
def self.load(path = 'config.toml', strict: false)
|
8
|
+
new(path, strict: strict)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(path = 'config.toml', strict: false)
|
12
|
+
@path = path
|
13
|
+
@strict = strict
|
14
|
+
@data = load_config
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](key)
|
18
|
+
@data[key]
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(key, value)
|
22
|
+
@data[key] = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch(key, default = nil)
|
26
|
+
@data.fetch(key, default)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(key)
|
30
|
+
@data[key]
|
31
|
+
end
|
32
|
+
|
33
|
+
def param(key)
|
34
|
+
return nil unless @data['params']
|
35
|
+
@data['params'][key]
|
36
|
+
end
|
37
|
+
|
38
|
+
def params
|
39
|
+
@data['params'] || {}
|
40
|
+
end
|
41
|
+
|
42
|
+
# Dynamic attribute access for config keys
|
43
|
+
def method_missing(method_name, *args, &block)
|
44
|
+
if args.empty? && @data.key?(method_name.to_s)
|
45
|
+
@data[method_name.to_s]
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def respond_to_missing?(method_name, include_private = false)
|
52
|
+
@data.key?(method_name.to_s) || super
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def load_config
|
58
|
+
unless File.exist?(@path)
|
59
|
+
if @strict
|
60
|
+
raise ConfigError, "Configuration file #{@path} not found"
|
61
|
+
else
|
62
|
+
return default_config
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
case File.extname(@path)
|
67
|
+
when '.toml'
|
68
|
+
TOML.load_file(@path)
|
69
|
+
when '.yaml', '.yml'
|
70
|
+
YAML.load_file(@path)
|
71
|
+
else
|
72
|
+
raise ConfigError, "Unsupported config format: #{@path}"
|
73
|
+
end
|
74
|
+
rescue Parslet::ParseFailed => e
|
75
|
+
raise ConfigError, "Error parsing TOML config: #{e.message}"
|
76
|
+
rescue Psych::SyntaxError => e
|
77
|
+
raise ConfigError, "Error parsing YAML config: #{e.message}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def default_config
|
81
|
+
{
|
82
|
+
'baseURL' => 'http://localhost:3000/',
|
83
|
+
'languageCode' => 'en-us',
|
84
|
+
'title' => 'My Siru Site',
|
85
|
+
'theme' => 'paper',
|
86
|
+
'params' => {
|
87
|
+
'color' => 'linen'
|
88
|
+
}
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|