mint 0.8.0 → 0.8.1
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 +4 -4
- data/README.md +68 -105
- data/lib/mint/command_line.rb +4 -4
- data/lib/mint/css_parser.rb +76 -0
- data/lib/mint/document.rb +18 -0
- data/lib/mint/version.rb +1 -1
- data/man/mint.1 +5 -5
- data/spec/cli/README.md +11 -11
- data/spec/cli/argument_parsing_spec.rb +33 -3
- data/spec/css_parser_spec.rb +149 -0
- data/spec/plugin_spec.rb +58 -58
- metadata +4 -5
- data/config/templates/default/css/style.css +0 -205
- data/config/templates/newspaper/layout.erb +0 -16
- data/config/templates/protocol/layout.erb +0 -9
- data/config/templates/protocol/style.css +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49d66d53b189d1897ab9938358279f7dc0c4ede1d44926eba5f1b9b6f7d8344b
|
4
|
+
data.tar.gz: '08b1882ec1972dbedd02c87e0e6a4cf1f61ca0a631c7f56bca20b4dfeb1ea36b'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3acb8ce3fc1856014e0efe3aa94d3720faeb8f677e2f9e3a46c541ecc8bd62f65a187558421ac10acc0599f813a8d161bed142bf44c75b51e6bc8f140351cc7f
|
7
|
+
data.tar.gz: 3851e818c5bad026bfde0302c8fe3184dfe4d79e93ca87479e85590015bb3fd082926fe88f7397144b8fbbb4163ae9e602bbb510bf23da009d20943b334896c2
|
data/README.md
CHANGED
@@ -1,137 +1,100 @@
|
|
1
|
-
#
|
1
|
+
# Mint
|
2
2
|
|
3
|
-
|
3
|
+
Transform your plain text documents into beautiful HTML documents with customizable styling and templates.
|
4
4
|
|
5
|
-
|
5
|
+
## Installation
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
- To make your text amenable to scripting--for example, text analysis
|
7
|
+
```bash
|
8
|
+
gem install mint
|
9
|
+
```
|
11
10
|
|
12
|
-
|
11
|
+
## Quick Start
|
13
12
|
|
14
|
-
|
13
|
+
Transform a Markdown document into styled HTML:
|
15
14
|
|
16
|
-
|
15
|
+
```bash
|
16
|
+
mint publish Document.md
|
17
|
+
```
|
17
18
|
|
18
|
-
|
19
|
-
language, you're ready to go.
|
19
|
+
This creates `Document.html` in your current directory with beautiful default styling.
|
20
20
|
|
21
|
-
|
22
|
-
it to the default stylesheet, which I've designed for you.
|
21
|
+
## Usage
|
23
22
|
|
24
|
-
|
23
|
+
### Basic Commands
|
25
24
|
|
26
|
-
|
25
|
+
```bash
|
26
|
+
# Publish a single document
|
27
|
+
mint publish Document.md
|
27
28
|
|
28
|
-
|
29
|
+
# Publish with a template
|
30
|
+
mint publish Document.md --template nord
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
word-processed document, complete with big bold headers, italic emphasis, automatically indented
|
33
|
-
and numbered lists, and bullets. If you're in a modern browser, you'll even see ligatures and
|
34
|
-
proper kerning. The page will be on a white canvas that looks like a page, even though you are in a
|
35
|
-
browser.
|
32
|
+
# Publish to a specific directory
|
33
|
+
mint publish Document.md --destination public
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
wonder of print stylesheets.)
|
35
|
+
# Publish multiple files
|
36
|
+
mint publish *.md --destination final-drafts
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
# Publish a digital garden, with linked navigation
|
39
|
+
mint publish content/**/*.md --template garden --destination public
|
40
|
+
```
|
44
41
|
|
45
|
-
|
42
|
+
### Common Options
|
46
43
|
|
47
|
-
|
44
|
+
| Flag | Description |
|
45
|
+
|------|-------------|
|
46
|
+
| `-t, --template TEMPLATE` | Use a built-in template (combines layout + style) |
|
47
|
+
| `-l, --layout LAYOUT` | Specify only the layout |
|
48
|
+
| `-s, --style STYLE` | Specify only the style |
|
49
|
+
| `-d, --destination DIR` | Output directory |
|
50
|
+
| `-o, --output-file FORMAT` | Custom output filename format |
|
51
|
+
| `--style-mode MODE` | How styles are included (inline, external, original) |
|
52
|
+
| `--style-destination PATH` | Create external stylesheet and link it (sets mode to external) |
|
53
|
+
| `-r, --recursive` | Find all Markdown files in any directories specified |
|
48
54
|
|
49
|
-
|
50
|
-
mint publish Document.md --style-destination styles # creates external stylesheet in styles directory
|
51
|
-
mint publish Document.md --style-destination styles/custom.css # creates external stylesheet at specific path
|
55
|
+
### Style modes
|
52
56
|
|
53
|
-
|
57
|
+
Mint offers three ways to include styles in your HTML output:
|
54
58
|
|
55
|
-
|
59
|
+
- **`inline`** (default) – CSS is embedded directly in the HTML document as `<style>` tags
|
60
|
+
- **`external`** – CSS is compiled and saved as separate files, linked with `<link>` tags
|
61
|
+
- **`original`** – Links directly to original CSS template files without processing (for live editing)
|
56
62
|
|
57
|
-
|
58
|
-
skeleton of your document or the output directory--you don't have to. You'll probably be surprised
|
59
|
-
at how easy it is to use out of the box, and how configurable it is.
|
63
|
+
The `original` mode is particularly useful for template development, as it allows you to edit CSS files and see changes immediately without republishing. Only `.css` files are supported in this mode, and `@import` statements in CSS files will be included as additional `<link>` tags.
|
60
64
|
|
61
|
-
|
62
|
-
document.publish!
|
65
|
+
### Built-in templates
|
63
66
|
|
64
|
-
|
65
|
-
|
67
|
+
- `default` – Clean, minimal styling
|
68
|
+
- `nord` – Clean, uses Nord color scheme
|
69
|
+
- `nord-dark` – Dark version of Nord
|
70
|
+
- `garden` – For digital gardens; includes navigation
|
66
71
|
|
67
|
-
|
68
|
-
document = Mint::Document.new("Document.md",
|
69
|
-
style_destination: "css",
|
70
|
-
template: "zen")
|
71
|
-
document.publish!
|
72
|
+
## Documentation
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
layout: "resume",
|
77
|
-
style: "professional")
|
78
|
-
document.publish!
|
74
|
+
- **Complete usage guide:** [TUTORIAL.md](doc/TUTORIAL.md)
|
75
|
+
- **Man page:** `man mint` (after installation)
|
76
|
+
- **API documentation:** [RubyDoc](http://www.rubydoc.info/github/davejacobs/mint)
|
79
77
|
|
80
|
-
|
78
|
+
## Why Mint?
|
81
79
|
|
82
|
-
|
83
|
-
|
80
|
+
- **Focus on writing** – Keep documents as plain text
|
81
|
+
- **Version control friendly** – Text files work great with Git
|
82
|
+
- **Scriptable** – Automate document processing
|
83
|
+
- **Beautiful output** – Professional-looking HTML ready for print or web
|
84
|
+
- **Highly customizable** – Create your own templates and styles
|
84
85
|
|
85
|
-
## Templates
|
86
|
+
## Templates and customization
|
86
87
|
|
87
|
-
|
88
|
-
Tilt TEMPLATES file][Tilt templates] for more information.)
|
88
|
+
Mint supports layouts written in HAML or ERB and stylesheets can be written in CSS, SCSS, or SASS.
|
89
89
|
|
90
|
-
|
90
|
+
## Contributing
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
1. Fork the repository
|
93
|
+
2. Create a feature branch
|
94
|
+
3. Make your changes
|
95
|
+
4. Run the tests: `rspec`
|
96
|
+
5. Submit a pull request
|
96
97
|
|
97
|
-
|
98
|
+
## License
|
98
99
|
|
99
|
-
|
100
|
-
|
101
|
-
So if you're writing your layout using Haml, the template might look like this:
|
102
|
-
|
103
|
-
!!!
|
104
|
-
%html
|
105
|
-
%head
|
106
|
-
= stylesheet_tag
|
107
|
-
%body
|
108
|
-
#container= content
|
109
|
-
|
110
|
-
The `stylesheet_tag` method will generate either:
|
111
|
-
- `<style>...</style>` tags with inlined CSS for inline mode (default)
|
112
|
-
- `<link rel="stylesheet" href="...">` tags for external stylesheets
|
113
|
-
|
114
|
-
You can create template stylesheets using [CSS][] or [SCSS][].
|
115
|
-
|
116
|
-
Mint comes preloaded with a few templates to get you started.
|
117
|
-
|
118
|
-
1. Default
|
119
|
-
2. Zen
|
120
|
-
3. Nord
|
121
|
-
4. Nord Dark
|
122
|
-
|
123
|
-
## Plugins: A work in progress
|
124
|
-
|
125
|
-
I've designed the beginnings of a plugin system. With this system, you can implement a callback or
|
126
|
-
two and have full control over document creation and sharing. I'll get documentation going soon. For
|
127
|
-
now, look to lib/mint/plugins/epub.rb and bin/mint-epub for an example of how to build one. It's not
|
128
|
-
complete and I'm open to API suggestions.
|
129
|
-
|
130
|
-
This is going to be useful for things like creating actual office documents or e-books or even bound
|
131
|
-
novels. I'm actually thinking that half the power of this library is its plugin system.
|
132
|
-
|
133
|
-
[tutorial]: http://github.com/davejacobs/mint/tree/master/doc/API.md
|
134
|
-
[Tilt templates]: http://github.com/rtomayko/tilt/blob/master/TEMPLATES.md "A listing of all templates supported by Tilt."
|
135
|
-
[CSS]: http://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
136
|
-
[SASS/SCSS]: http://sass-lang.com/
|
137
|
-
[Less]: http://lesscss.org/
|
100
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
data/lib/mint/command_line.rb
CHANGED
@@ -41,8 +41,8 @@ module Mint
|
|
41
41
|
parsed_options[:destination] = d
|
42
42
|
end
|
43
43
|
|
44
|
-
cli.on "--
|
45
|
-
parsed_options[:style_mode] =
|
44
|
+
cli.on "--style-mode MODE", ["inline", "external", "original"], "Specify how styles are included (inline, external, original)" do |mode|
|
45
|
+
parsed_options[:style_mode] = mode.to_sym
|
46
46
|
end
|
47
47
|
|
48
48
|
cli.on "--style-destination DESTINATION", "Create stylesheet at specified directory or file path and link it" do |destination|
|
@@ -58,7 +58,7 @@ module Mint
|
|
58
58
|
parsed_options[:scope] = :user
|
59
59
|
end
|
60
60
|
|
61
|
-
cli.on "
|
61
|
+
cli.on "--local", "Specify config changes on a project-specific level" do
|
62
62
|
parsed_options[:scope] = :local
|
63
63
|
end
|
64
64
|
|
@@ -71,7 +71,7 @@ module Mint
|
|
71
71
|
parser.parse! transient_argv
|
72
72
|
|
73
73
|
if parsed_options[:style_mode] == :inline && parsed_options[:style_destination]
|
74
|
-
raise ArgumentError, "--
|
74
|
+
raise ArgumentError, "--style-mode inline and --style-destination cannot be used together"
|
75
75
|
end
|
76
76
|
|
77
77
|
default_options = Mint.default_options.merge(destination: Dir.getwd)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Mint
|
4
|
+
# Parses CSS files to extract @import statements and calculate relative paths
|
5
|
+
class CssParser
|
6
|
+
|
7
|
+
# Extracts @import statements from CSS content
|
8
|
+
#
|
9
|
+
# @param [String] css_content the CSS content to parse
|
10
|
+
# @return [Array<String>] array of imported file paths
|
11
|
+
def self.extract_imports(css_content)
|
12
|
+
imports = []
|
13
|
+
|
14
|
+
# Match @import statements with various formats:
|
15
|
+
# @import "file.css";
|
16
|
+
# @import 'file.css';
|
17
|
+
# @import url("file.css");
|
18
|
+
# @import url('file.css');
|
19
|
+
css_content.scan(/@import\s+(?:url\()?['"]([^'"]+)['"](?:\))?;?/i) do |match|
|
20
|
+
imports << match[0]
|
21
|
+
end
|
22
|
+
|
23
|
+
imports
|
24
|
+
end
|
25
|
+
|
26
|
+
# Resolves all CSS files (main + imports) and calculates their paths relative to HTML output
|
27
|
+
#
|
28
|
+
# @param [String] main_css_path absolute path to the main CSS file
|
29
|
+
# @param [String] html_output_path absolute path to the HTML output file
|
30
|
+
# @return [Array<String>] array of relative paths from HTML to CSS files
|
31
|
+
def self.resolve_css_files(main_css_path, html_output_path)
|
32
|
+
css_files = []
|
33
|
+
main_css_file = Pathname.new(main_css_path)
|
34
|
+
html_file = Pathname.new(html_output_path)
|
35
|
+
|
36
|
+
# Add the main CSS file
|
37
|
+
css_files << main_css_file.relative_path_from(html_file.dirname).to_s
|
38
|
+
|
39
|
+
# Only process if main CSS file exists and is a .css file
|
40
|
+
return css_files unless main_css_file.exist? && main_css_file.extname == '.css'
|
41
|
+
|
42
|
+
begin
|
43
|
+
css_content = File.read(main_css_path)
|
44
|
+
imports = extract_imports(css_content)
|
45
|
+
|
46
|
+
imports.each do |import_path|
|
47
|
+
# Resolve import path relative to the main CSS file's directory
|
48
|
+
import_file = main_css_file.dirname + import_path
|
49
|
+
|
50
|
+
# Only include if it's a .css file and exists
|
51
|
+
if import_file.exist? && import_file.extname == '.css'
|
52
|
+
# Calculate path relative to HTML output
|
53
|
+
relative_import = import_file.relative_path_from(html_file.dirname).to_s
|
54
|
+
css_files << relative_import
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
rescue => e
|
59
|
+
# If we can't read the CSS file, just return the main file
|
60
|
+
# This allows the system to gracefully handle missing or unreadable files
|
61
|
+
end
|
62
|
+
|
63
|
+
css_files
|
64
|
+
end
|
65
|
+
|
66
|
+
# Generates HTML link tags for CSS files
|
67
|
+
#
|
68
|
+
# @param [Array<String>] css_file_paths array of relative paths to CSS files
|
69
|
+
# @return [String] HTML link tags
|
70
|
+
def self.generate_link_tags(css_file_paths)
|
71
|
+
css_file_paths.map do |css_path|
|
72
|
+
%Q{<link rel="stylesheet" href="#{css_path}">}
|
73
|
+
end.join("\n ")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/mint/document.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "mint/resource"
|
2
2
|
require "mint/layout"
|
3
3
|
require "mint/style"
|
4
|
+
require "mint/css_parser"
|
4
5
|
|
5
6
|
module Mint
|
6
7
|
class Document < Resource
|
@@ -245,11 +246,28 @@ module Mint
|
|
245
246
|
case @style_mode
|
246
247
|
when :external
|
247
248
|
"<link rel=\"stylesheet\" href=\"#{stylesheet}\">".html_safe
|
249
|
+
when :original
|
250
|
+
original_stylesheet_tags.html_safe
|
248
251
|
else # :inline (default)
|
249
252
|
"<style>#{self.style.render}</style>".html_safe
|
250
253
|
end
|
251
254
|
end
|
252
255
|
|
256
|
+
# Generates stylesheet link tags for original mode
|
257
|
+
# Links directly to original CSS files without processing
|
258
|
+
def original_stylesheet_tags
|
259
|
+
return "" unless self.style&.template_path
|
260
|
+
|
261
|
+
main_css_path = self.style.template_path
|
262
|
+
html_output_path = self.output_file
|
263
|
+
|
264
|
+
# Only process .css files
|
265
|
+
return "" unless File.extname(main_css_path) == '.css'
|
266
|
+
|
267
|
+
css_file_paths = CssParser.resolve_css_files(main_css_path, html_output_path)
|
268
|
+
CssParser.generate_link_tags(css_file_paths)
|
269
|
+
end
|
270
|
+
|
253
271
|
# Parses styles defined in YAML metadata in content, including it
|
254
272
|
# in output CSS style
|
255
273
|
#
|
data/lib/mint/version.rb
CHANGED
data/man/mint.1
CHANGED
@@ -18,16 +18,16 @@ Transform one or more source files into HTML documents
|
|
18
18
|
.BR \-d ", " \-\-destination " " \fIDIRECTORY\fR
|
19
19
|
Specify a destination directory, relative to the root
|
20
20
|
.TP
|
21
|
-
.BR \-\-
|
22
|
-
|
21
|
+
.BR \-\-style\-mode " " \fIMODE\fR
|
22
|
+
Specify how styles are included (inline, external, original). Default is inline.
|
23
23
|
.TP
|
24
24
|
.BR \-\-style\-destination " " \fIDESTINATION\fR
|
25
|
-
Create stylesheet at specified directory or file path and link it. This
|
25
|
+
Create stylesheet at specified directory or file path and link it. This sets style mode to external.
|
26
26
|
.TP
|
27
27
|
.BR \-\-template " " \fITEMPLATE\fR
|
28
28
|
Specify a template to use for both layout and styling
|
29
29
|
.TP
|
30
|
-
.BR \-\-layout " " \fILAYOUT\fR
|
30
|
+
.BR \-l ", " \-\-layout " " \fILAYOUT\fR
|
31
31
|
Specify a specific layout template
|
32
32
|
.TP
|
33
33
|
.BR \-\-style " " \fISTYLE\fR
|
@@ -39,7 +39,7 @@ Specify config changes on a global level
|
|
39
39
|
.BR \-u ", " \-\-user
|
40
40
|
Specify config changes on a user-wide level
|
41
41
|
.TP
|
42
|
-
.BR
|
42
|
+
.BR \-\-local
|
43
43
|
Specify config changes on a local level (default)
|
44
44
|
.TP
|
45
45
|
.BR \-r ", " \-\-recursive
|
data/spec/cli/README.md
CHANGED
@@ -6,17 +6,17 @@ This directory contains a comprehensive test suite for the Mint command-line int
|
|
6
6
|
|
7
7
|
### Core test files
|
8
8
|
|
9
|
-
- **`argument_parsing_spec.rb`**
|
10
|
-
- **`template_management_spec.rb`**
|
11
|
-
- **`publish_workflow_spec.rb`**
|
12
|
-
- **`configuration_management_spec.rb`**
|
13
|
-
- **`bin_integration_spec.rb`**
|
14
|
-
- **`full_workflow_integration_spec.rb`**
|
9
|
+
- **`argument_parsing_spec.rb`** – Tests command-line argument parsing and option handling
|
10
|
+
- **`template_management_spec.rb`** – Tests template installation, uninstallation, editing, and listing
|
11
|
+
- **`publish_workflow_spec.rb`** – Tests markdown publishing, file discovery, and output generation
|
12
|
+
- **`configuration_management_spec.rb`** – Tests configuration setting, reading, and scope management
|
13
|
+
- **`bin_integration_spec.rb`** – Tests actual `bin/mint` executable integration
|
14
|
+
- **`full_workflow_integration_spec.rb`** – End-to-end workflow tests for common user scenarios
|
15
15
|
|
16
16
|
### Support files
|
17
17
|
|
18
|
-
- **`../support/cli_helpers.rb`**
|
19
|
-
- **`run_cli_tests.rb`**
|
18
|
+
- **`../support/cli_helpers.rb`** – Helper methods for CLI testing (temp directories, file creation, output capture)
|
19
|
+
- **`run_cli_tests.rb`** – Custom test runner with better output formatting
|
20
20
|
|
21
21
|
## Running tests
|
22
22
|
|
@@ -79,9 +79,9 @@ end
|
|
79
79
|
## Debugging failed tests
|
80
80
|
|
81
81
|
### Common issues
|
82
|
-
1. **Missing templates**
|
83
|
-
2. **File paths**
|
84
|
-
3. **Configuration**
|
82
|
+
1. **Missing templates** – Tests create minimal templates; check `create_template_directory`
|
83
|
+
2. **File paths** – All paths should be relative within temp directory
|
84
|
+
3. **Configuration** – Use `setup_basic_config` to establish minimal config
|
85
85
|
|
86
86
|
### Debug helpers
|
87
87
|
|
@@ -29,6 +29,13 @@ RSpec.describe "CLI Argument Parsing" do
|
|
29
29
|
expect(result[:options][:layout_or_style_or_template]).to eq([:layout, "custom"])
|
30
30
|
end
|
31
31
|
|
32
|
+
it "parses -l option for layout" do
|
33
|
+
result = Mint::CommandLine.parse(["-l", "custom", "file.md"])
|
34
|
+
|
35
|
+
expect(result[:argv]).to eq(["file.md"])
|
36
|
+
expect(result[:options][:layout_or_style_or_template]).to eq([:layout, "custom"])
|
37
|
+
end
|
38
|
+
|
32
39
|
it "parses --style option" do
|
33
40
|
result = Mint::CommandLine.parse(["--style", "minimal", "file.md"])
|
34
41
|
|
@@ -107,9 +114,6 @@ RSpec.describe "CLI Argument Parsing" do
|
|
107
114
|
|
108
115
|
result = Mint::CommandLine.parse(["-u"])
|
109
116
|
expect(result[:options][:scope]).to eq(:user)
|
110
|
-
|
111
|
-
result = Mint::CommandLine.parse(["-l"])
|
112
|
-
expect(result[:options][:scope]).to eq(:local)
|
113
117
|
end
|
114
118
|
end
|
115
119
|
|
@@ -203,5 +207,31 @@ RSpec.describe "CLI Argument Parsing" do
|
|
203
207
|
end
|
204
208
|
end
|
205
209
|
end
|
210
|
+
|
211
|
+
context "with style mode options" do
|
212
|
+
it "parses --style-mode inline" do
|
213
|
+
result = Mint::CommandLine.parse(["--style-mode", "inline", "file.md"])
|
214
|
+
|
215
|
+
expect(result[:options][:style_mode]).to eq(:inline)
|
216
|
+
end
|
217
|
+
|
218
|
+
it "parses --style-mode external" do
|
219
|
+
result = Mint::CommandLine.parse(["--style-mode", "external", "file.md"])
|
220
|
+
|
221
|
+
expect(result[:options][:style_mode]).to eq(:external)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "parses --style-mode original" do
|
225
|
+
result = Mint::CommandLine.parse(["--style-mode", "original", "file.md"])
|
226
|
+
|
227
|
+
expect(result[:options][:style_mode]).to eq(:original)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "defaults to inline style mode" do
|
231
|
+
result = Mint::CommandLine.parse(["file.md"])
|
232
|
+
|
233
|
+
expect(result[:options][:style_mode]).to eq(:inline)
|
234
|
+
end
|
235
|
+
end
|
206
236
|
end
|
207
237
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "mint/css_parser"
|
3
|
+
require "tempfile"
|
4
|
+
require "pathname"
|
5
|
+
|
6
|
+
describe Mint::CssParser do
|
7
|
+
describe ".extract_imports" do
|
8
|
+
it "extracts @import statements with double quotes" do
|
9
|
+
css = '@import "reset.css"; body { margin: 0; }'
|
10
|
+
imports = Mint::CssParser.extract_imports(css)
|
11
|
+
expect(imports).to eq(["reset.css"])
|
12
|
+
end
|
13
|
+
|
14
|
+
it "extracts @import statements with single quotes" do
|
15
|
+
css = "@import 'normalize.css'; .class { color: red; }"
|
16
|
+
imports = Mint::CssParser.extract_imports(css)
|
17
|
+
expect(imports).to eq(["normalize.css"])
|
18
|
+
end
|
19
|
+
|
20
|
+
it "extracts @import url() statements" do
|
21
|
+
css = '@import url("fonts.css"); @import url(\'colors.css\');'
|
22
|
+
imports = Mint::CssParser.extract_imports(css)
|
23
|
+
expect(imports).to eq(["fonts.css", "colors.css"])
|
24
|
+
end
|
25
|
+
|
26
|
+
it "extracts multiple @import statements" do
|
27
|
+
css = <<~CSS
|
28
|
+
@import "reset.css";
|
29
|
+
@import 'normalize.css';
|
30
|
+
@import url("fonts.css");
|
31
|
+
body { margin: 0; }
|
32
|
+
CSS
|
33
|
+
imports = Mint::CssParser.extract_imports(css)
|
34
|
+
expect(imports).to eq(["reset.css", "normalize.css", "fonts.css"])
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns empty array when no imports found" do
|
38
|
+
css = "body { margin: 0; color: blue; }"
|
39
|
+
imports = Mint::CssParser.extract_imports(css)
|
40
|
+
expect(imports).to eq([])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".resolve_css_files" do
|
45
|
+
let(:temp_dir) { Dir.mktmpdir }
|
46
|
+
|
47
|
+
after do
|
48
|
+
FileUtils.rm_rf(temp_dir)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "resolves main CSS file path relative to HTML output" do
|
52
|
+
# Create directory structure:
|
53
|
+
# temp_dir/
|
54
|
+
# css/
|
55
|
+
# main.css
|
56
|
+
# output/
|
57
|
+
# index.html (output file)
|
58
|
+
|
59
|
+
css_dir = File.join(temp_dir, "css")
|
60
|
+
output_dir = File.join(temp_dir, "output")
|
61
|
+
FileUtils.mkdir_p([css_dir, output_dir])
|
62
|
+
|
63
|
+
main_css = File.join(css_dir, "main.css")
|
64
|
+
html_output = File.join(output_dir, "index.html")
|
65
|
+
|
66
|
+
File.write(main_css, "body { margin: 0; }")
|
67
|
+
|
68
|
+
css_files = Mint::CssParser.resolve_css_files(main_css, html_output)
|
69
|
+
expect(css_files).to eq(["../css/main.css"])
|
70
|
+
end
|
71
|
+
|
72
|
+
it "resolves main CSS and imported files" do
|
73
|
+
# Create directory structure:
|
74
|
+
# temp_dir/
|
75
|
+
# css/
|
76
|
+
# main.css (imports reset.css)
|
77
|
+
# reset.css
|
78
|
+
# output/
|
79
|
+
# index.html
|
80
|
+
|
81
|
+
css_dir = File.join(temp_dir, "css")
|
82
|
+
output_dir = File.join(temp_dir, "output")
|
83
|
+
FileUtils.mkdir_p([css_dir, output_dir])
|
84
|
+
|
85
|
+
main_css = File.join(css_dir, "main.css")
|
86
|
+
reset_css = File.join(css_dir, "reset.css")
|
87
|
+
html_output = File.join(output_dir, "index.html")
|
88
|
+
|
89
|
+
File.write(main_css, '@import "reset.css"; body { margin: 0; }')
|
90
|
+
File.write(reset_css, "* { box-sizing: border-box; }")
|
91
|
+
|
92
|
+
css_files = Mint::CssParser.resolve_css_files(main_css, html_output)
|
93
|
+
expect(css_files).to eq(["../css/main.css", "../css/reset.css"])
|
94
|
+
end
|
95
|
+
|
96
|
+
it "ignores non-existent imported files" do
|
97
|
+
css_dir = File.join(temp_dir, "css")
|
98
|
+
output_dir = File.join(temp_dir, "output")
|
99
|
+
FileUtils.mkdir_p([css_dir, output_dir])
|
100
|
+
|
101
|
+
main_css = File.join(css_dir, "main.css")
|
102
|
+
html_output = File.join(output_dir, "index.html")
|
103
|
+
|
104
|
+
File.write(main_css, '@import "nonexistent.css"; body { margin: 0; }')
|
105
|
+
|
106
|
+
css_files = Mint::CssParser.resolve_css_files(main_css, html_output)
|
107
|
+
expect(css_files).to eq(["../css/main.css"])
|
108
|
+
end
|
109
|
+
|
110
|
+
it "only processes .css files" do
|
111
|
+
scss_dir = File.join(temp_dir, "scss")
|
112
|
+
output_dir = File.join(temp_dir, "output")
|
113
|
+
FileUtils.mkdir_p([scss_dir, output_dir])
|
114
|
+
|
115
|
+
main_scss = File.join(scss_dir, "main.scss")
|
116
|
+
html_output = File.join(output_dir, "index.html")
|
117
|
+
|
118
|
+
File.write(main_scss, '@import "reset"; body { margin: 0; }')
|
119
|
+
|
120
|
+
css_files = Mint::CssParser.resolve_css_files(main_scss, html_output)
|
121
|
+
expect(css_files).to eq(["../scss/main.scss"])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe ".generate_link_tags" do
|
126
|
+
it "generates HTML link tags for CSS files" do
|
127
|
+
css_paths = ["../css/main.css", "../css/reset.css"]
|
128
|
+
|
129
|
+
html = Mint::CssParser.generate_link_tags(css_paths)
|
130
|
+
|
131
|
+
expected = <<~HTML.strip
|
132
|
+
<link rel="stylesheet" href="../css/main.css">
|
133
|
+
<link rel="stylesheet" href="../css/reset.css">
|
134
|
+
HTML
|
135
|
+
|
136
|
+
expect(html).to eq(expected)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "handles empty array" do
|
140
|
+
html = Mint::CssParser.generate_link_tags([])
|
141
|
+
expect(html).to eq("")
|
142
|
+
end
|
143
|
+
|
144
|
+
it "handles single CSS file" do
|
145
|
+
html = Mint::CssParser.generate_link_tags(["styles.css"])
|
146
|
+
expect(html).to eq('<link rel="stylesheet" href="styles.css">')
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/spec/plugin_spec.rb
CHANGED
@@ -188,21 +188,21 @@ describe Mint do
|
|
188
188
|
end
|
189
189
|
|
190
190
|
# TODO: Document expected document functionality changes related to plugins
|
191
|
-
describe Mint::Document do
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
end
|
191
|
+
# describe Mint::Document do
|
192
|
+
# context "when plugins are registered with Mint" do
|
193
|
+
# describe "#content=" do
|
194
|
+
# it "applies each registered plugin's before_render filter"
|
195
|
+
# end
|
196
|
+
|
197
|
+
# describe "#render" do
|
198
|
+
# it "applies each registered plugin's after_render filter"
|
199
|
+
# end
|
200
|
+
|
201
|
+
# describe "#publish!" do
|
202
|
+
# it "applies each registered plugin's after_publish filter"
|
203
|
+
# end
|
204
|
+
# end
|
205
|
+
# end
|
206
206
|
|
207
207
|
describe Mint::Plugin do
|
208
208
|
# We have to instantiate these plugins in a before block,
|
@@ -217,7 +217,7 @@ describe Mint do
|
|
217
217
|
describe ".underscore" do
|
218
218
|
let(:plugin) { Class.new(Mint::Plugin) }
|
219
219
|
|
220
|
-
it "when anonymous, returns a random identifier"
|
220
|
+
# it "when anonymous, returns a random identifier"
|
221
221
|
|
222
222
|
it "when named, returns its name, underscored" do
|
223
223
|
expect(plugin).to receive(:name).and_return("EPub")
|
@@ -255,7 +255,7 @@ describe Mint do
|
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
258
|
-
it "returns a hash of options the plugin can take, including constraints"
|
258
|
+
# it "returns a hash of options the plugin can take, including constraints"
|
259
259
|
end
|
260
260
|
|
261
261
|
context "plugin callbacks" do
|
@@ -328,47 +328,47 @@ describe Mint do
|
|
328
328
|
expect(File.exist?("second-half.html")).to be_truthy
|
329
329
|
end
|
330
330
|
|
331
|
-
it "allows changes to the style file" do
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
end
|
353
|
-
|
354
|
-
context "when the output is in the default directory" do
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
end
|
331
|
+
# it "allows changes to the style file" do
|
332
|
+
# pending "figure out a better strategy for style manipulation"
|
333
|
+
# document = Mint::Document.new "content.md", style: "style.css"
|
334
|
+
|
335
|
+
# plugin.instance_eval do
|
336
|
+
# def after_publish(document)
|
337
|
+
# # I'd like to take document.style_destination_file,
|
338
|
+
# # but the current Mint API doesn't allow for this
|
339
|
+
# # if we're setting the style via a concrete
|
340
|
+
# # stylesheet in our current directory
|
341
|
+
# style_source = document.style.source_file
|
342
|
+
# style = File.read style_source
|
343
|
+
# File.open style_source, "w" do |file|
|
344
|
+
# file << style.gsub(/#/, ".")
|
345
|
+
# end
|
346
|
+
# end
|
347
|
+
# end
|
348
|
+
|
349
|
+
# document.publish! :plugins => [plugin]
|
350
|
+
|
351
|
+
# File.read(document.style.source_file).should =~ /\#container/
|
352
|
+
# end
|
353
|
+
|
354
|
+
# context "when the output is in the default directory" do
|
355
|
+
# it "doesn't allow changes to the document directory" do
|
356
|
+
# pending "figuring out the best way to prevent directory manipulation"
|
357
|
+
# document = Mint::Document.new "content.md"
|
358
|
+
# plugin.instance_eval do
|
359
|
+
# def after_publish
|
360
|
+
# original = document.destination_directory
|
361
|
+
# new = File.expand_path "invalid"
|
362
|
+
# FileUtils.mv original, new
|
363
|
+
# document.destination = "invalid"
|
364
|
+
# end
|
365
|
+
|
366
|
+
# expect do
|
367
|
+
# document.publish! :plugins => [plugin]
|
368
|
+
# end.to raise_error(InvalidPluginAction)
|
369
|
+
# end
|
370
|
+
# end
|
371
|
+
# end
|
372
372
|
|
373
373
|
context "when the output is a new directory" do
|
374
374
|
it "allows changes to the document directory" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Jacobs
|
@@ -182,24 +182,21 @@ files:
|
|
182
182
|
- bin/mint
|
183
183
|
- bin/mint-epub
|
184
184
|
- config/templates/base/style.css
|
185
|
-
- config/templates/default/css/style.css
|
186
185
|
- config/templates/default/layout.erb
|
187
186
|
- config/templates/default/style.css
|
188
187
|
- config/templates/garden/layout.erb
|
189
188
|
- config/templates/garden/style.css
|
190
|
-
- config/templates/newspaper/layout.erb
|
191
189
|
- config/templates/nord-dark/layout.erb
|
192
190
|
- config/templates/nord-dark/style.css
|
193
191
|
- config/templates/nord/layout.erb
|
194
192
|
- config/templates/nord/style.css
|
195
|
-
- config/templates/protocol/layout.erb
|
196
|
-
- config/templates/protocol/style.css
|
197
193
|
- config/templates/reset.css
|
198
194
|
- config/templates/zen/layout.erb
|
199
195
|
- config/templates/zen/style.css
|
200
196
|
- lib/mint.rb
|
201
197
|
- lib/mint/command_line.rb
|
202
198
|
- lib/mint/css.rb
|
199
|
+
- lib/mint/css_parser.rb
|
203
200
|
- lib/mint/css_template.rb
|
204
201
|
- lib/mint/document.rb
|
205
202
|
- lib/mint/exceptions.rb
|
@@ -225,6 +222,7 @@ files:
|
|
225
222
|
- spec/cli/full_workflow_integration_spec.rb
|
226
223
|
- spec/cli/publish_workflow_spec.rb
|
227
224
|
- spec/cli/template_management_spec.rb
|
225
|
+
- spec/css_parser_spec.rb
|
228
226
|
- spec/css_spec.rb
|
229
227
|
- spec/document_spec.rb
|
230
228
|
- spec/helpers_spec.rb
|
@@ -271,6 +269,7 @@ test_files:
|
|
271
269
|
- spec/cli/full_workflow_integration_spec.rb
|
272
270
|
- spec/cli/publish_workflow_spec.rb
|
273
271
|
- spec/cli/template_management_spec.rb
|
272
|
+
- spec/css_parser_spec.rb
|
274
273
|
- spec/css_spec.rb
|
275
274
|
- spec/document_spec.rb
|
276
275
|
- spec/helpers_spec.rb
|
@@ -1,205 +0,0 @@
|
|
1
|
-
@import '../reset.css';
|
2
|
-
body {
|
3
|
-
font-family: Ubuntu, "Hoefler Text", "Grandesign Neue Serif", Ubuntu, Georgia, FreeSerif, serif, Georgia, serif;
|
4
|
-
}
|
5
|
-
|
6
|
-
h1, h2 {
|
7
|
-
line-height: 1.3;
|
8
|
-
}
|
9
|
-
|
10
|
-
h2, h3, h4, h5, h6 {
|
11
|
-
line-height: 22.5px;
|
12
|
-
}
|
13
|
-
|
14
|
-
h1, h2, h3, h4, h5, h6 {
|
15
|
-
font-family: "Hoefler Text", Garamond, Georgia;
|
16
|
-
font-weight: normal;
|
17
|
-
}
|
18
|
-
|
19
|
-
h1 {
|
20
|
-
font-size: 22.5px;
|
21
|
-
margin-top: 22.5px;
|
22
|
-
margin-bottom: 22.5px;
|
23
|
-
}
|
24
|
-
|
25
|
-
h2 {
|
26
|
-
font-size: 18px;
|
27
|
-
margin-top: 33.75px;
|
28
|
-
margin-bottom: 11.25px;
|
29
|
-
}
|
30
|
-
|
31
|
-
h3 {
|
32
|
-
font-size: 16.5px;
|
33
|
-
margin-top: 39.375px;
|
34
|
-
margin-bottom: 5.625px;
|
35
|
-
}
|
36
|
-
|
37
|
-
h4 {
|
38
|
-
font-size: 15.75px;
|
39
|
-
margin-top: 19.6875px;
|
40
|
-
margin-bottom: 2.8125px;
|
41
|
-
}
|
42
|
-
|
43
|
-
h5, h6 {
|
44
|
-
font-size: 15px;
|
45
|
-
margin-top: 19.6875px;
|
46
|
-
margin-bottom: 2.8125px;
|
47
|
-
}
|
48
|
-
|
49
|
-
ul {
|
50
|
-
list-style-type: square;
|
51
|
-
}
|
52
|
-
ul ul {
|
53
|
-
list-style-type: circle;
|
54
|
-
}
|
55
|
-
|
56
|
-
ul, ol {
|
57
|
-
margin: 5.625px 0 0 11.25px;
|
58
|
-
padding-left: 27px;
|
59
|
-
}
|
60
|
-
ul li p, ol li p {
|
61
|
-
text-indent: 0 !important;
|
62
|
-
}
|
63
|
-
ul li + li, ol li + li {
|
64
|
-
margin-top: 5.625px;
|
65
|
-
}
|
66
|
-
|
67
|
-
p {
|
68
|
-
margin: 11.25px 0;
|
69
|
-
}
|
70
|
-
|
71
|
-
ul + p, ol + p, blockquote + p, pre + p {
|
72
|
-
text-indent: 0;
|
73
|
-
}
|
74
|
-
|
75
|
-
a:link, a:visited, a:active {
|
76
|
-
color: #cb0018;
|
77
|
-
text-decoration: none;
|
78
|
-
}
|
79
|
-
a:hover {
|
80
|
-
text-decoration: underline;
|
81
|
-
}
|
82
|
-
|
83
|
-
code {
|
84
|
-
font-family: Monaco, Menlo, Mensch, Consolas, Monotype, mono;
|
85
|
-
font-style: normal;
|
86
|
-
}
|
87
|
-
|
88
|
-
pre, blockquote {
|
89
|
-
display: block;
|
90
|
-
margin-left: 22.5px;
|
91
|
-
margin-right: 45px;
|
92
|
-
padding: 7.5px 22.5px;
|
93
|
-
padding-left: 16.875px;
|
94
|
-
white-space: pre;
|
95
|
-
}
|
96
|
-
pre p, blockquote p {
|
97
|
-
margin: 0;
|
98
|
-
line-height: 1.35;
|
99
|
-
}
|
100
|
-
|
101
|
-
img {
|
102
|
-
display: block;
|
103
|
-
}
|
104
|
-
|
105
|
-
@media screen {
|
106
|
-
body {
|
107
|
-
font-size: 15px;
|
108
|
-
line-height: 22.5px;
|
109
|
-
background-color: #666;
|
110
|
-
color: #333;
|
111
|
-
}
|
112
|
-
#container {
|
113
|
-
display: block;
|
114
|
-
border: solid 1px #999;
|
115
|
-
width: 780px;
|
116
|
-
padding: 40px 60px;
|
117
|
-
margin: 11.25px auto;
|
118
|
-
background-color: #fff;
|
119
|
-
box-sizing: border-box;
|
120
|
-
-moz-box-sizing: border-box;
|
121
|
-
-webkit-box-sizing: border-box;
|
122
|
-
}
|
123
|
-
code {
|
124
|
-
font-size: 13.125px;
|
125
|
-
}
|
126
|
-
pre {
|
127
|
-
white-space: pre-wrap;
|
128
|
-
white-space: -moz-pre-wrap;
|
129
|
-
white-space: -o-pre-wrap;
|
130
|
-
word-wrap: break-word;
|
131
|
-
}
|
132
|
-
pre code {
|
133
|
-
font-size: 11.25px;
|
134
|
-
}
|
135
|
-
}
|
136
|
-
@media print {
|
137
|
-
@page {
|
138
|
-
margin-left: 1in;
|
139
|
-
margin-right: 1in;
|
140
|
-
margin-top: 1in;
|
141
|
-
margin-bottom: 1in;
|
142
|
-
}
|
143
|
-
body {
|
144
|
-
font-size: 12pt;
|
145
|
-
line-height: 15.6pt;
|
146
|
-
width: auto;
|
147
|
-
margin: 0;
|
148
|
-
padding: 0;
|
149
|
-
}
|
150
|
-
code {
|
151
|
-
font-size: 10.5pt;
|
152
|
-
}
|
153
|
-
pre code {
|
154
|
-
font-size: 9pt;
|
155
|
-
}
|
156
|
-
h1, h2, h3, h4, h5, h6, li, blockquote {
|
157
|
-
page-break-inside: avoid;
|
158
|
-
}
|
159
|
-
p {
|
160
|
-
widows: 3;
|
161
|
-
orphans: 3;
|
162
|
-
}
|
163
|
-
}
|
164
|
-
body {
|
165
|
-
text-rendering: optimizeLegibility;
|
166
|
-
}
|
167
|
-
|
168
|
-
h1 {
|
169
|
-
font-size: 25.5px;
|
170
|
-
border-bottom: solid 2px #666;
|
171
|
-
}
|
172
|
-
|
173
|
-
h2 {
|
174
|
-
font-size: 19.5px;
|
175
|
-
}
|
176
|
-
|
177
|
-
h3 {
|
178
|
-
font-size: 18px;
|
179
|
-
font-style: italic;
|
180
|
-
}
|
181
|
-
|
182
|
-
h4 {
|
183
|
-
font-variant: small-caps;
|
184
|
-
}
|
185
|
-
|
186
|
-
h5, h6 {
|
187
|
-
font-weight: bold;
|
188
|
-
}
|
189
|
-
|
190
|
-
p + p {
|
191
|
-
text-indent: 22.5px;
|
192
|
-
}
|
193
|
-
|
194
|
-
pre, blockquote {
|
195
|
-
border-left: solid 2px #ddd;
|
196
|
-
background-color: #fdffe8;
|
197
|
-
}
|
198
|
-
|
199
|
-
blockquote {
|
200
|
-
font-style: italic;
|
201
|
-
}
|
202
|
-
|
203
|
-
code {
|
204
|
-
font-family: "Ubuntu Mono";
|
205
|
-
}
|
@@ -1,16 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="en">
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8">
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
7
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
8
|
-
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=Old+Standard+TT:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
|
9
|
-
<%= stylesheet_tag %>
|
10
|
-
</head>
|
11
|
-
<body>
|
12
|
-
<main id="container">
|
13
|
-
<div class="newspaper-columns"><%= content %></div>
|
14
|
-
</main>
|
15
|
-
</body>
|
16
|
-
</html>
|
@@ -1,25 +0,0 @@
|
|
1
|
-
:root {
|
2
|
-
--screen-font-size: 16px;
|
3
|
-
--screen-line-height: calc(var(--screen-font-size) * 1.3);
|
4
|
-
--screen-unit: var(--screen-line-height);
|
5
|
-
|
6
|
-
--print-font-size: 12pt;
|
7
|
-
--print-line-height: calc(var(--print-font-size) * 1.3);
|
8
|
-
--print-unit: var(--print-line-height);
|
9
|
-
|
10
|
-
--link-color: #cb0018;
|
11
|
-
}
|
12
|
-
|
13
|
-
@import "../base/style.css";
|
14
|
-
|
15
|
-
body {
|
16
|
-
font-family: ScalaSansPro, "Helvetica Neue";
|
17
|
-
}
|
18
|
-
|
19
|
-
p + h2, p + h3, p + h4, p + h5, p + h6 {
|
20
|
-
margin-top: calc(var(--screen-unit) * 1.5);
|
21
|
-
}
|
22
|
-
|
23
|
-
p {
|
24
|
-
line-height: 1.25;
|
25
|
-
}
|