mint 0.7.4 → 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 +7 -0
- data/Gemfile +23 -14
- data/LICENSE +22 -0
- data/README.md +68 -79
- data/bin/mint +47 -10
- data/bin/mint-epub +1 -4
- data/config/templates/base/style.css +187 -0
- data/config/templates/default/layout.erb +10 -0
- data/config/templates/default/style.css +237 -0
- data/config/templates/garden/layout.erb +38 -0
- data/config/templates/garden/style.css +303 -0
- data/config/templates/nord/layout.erb +11 -0
- data/config/templates/nord/style.css +339 -0
- data/config/templates/nord-dark/layout.erb +11 -0
- data/config/templates/nord-dark/style.css +339 -0
- data/config/templates/zen/layout.erb +11 -0
- data/config/templates/zen/style.css +114 -0
- data/lib/mint/command_line.rb +253 -111
- data/lib/mint/css.rb +11 -4
- data/lib/mint/css_parser.rb +76 -0
- data/lib/mint/css_template.rb +37 -0
- data/lib/mint/document.rb +203 -43
- data/lib/mint/helpers.rb +50 -10
- data/lib/mint/layout.rb +2 -3
- data/lib/mint/markdown_template.rb +47 -0
- data/lib/mint/mint.rb +181 -114
- data/lib/mint/plugin.rb +3 -3
- data/lib/mint/plugins/epub.rb +1 -2
- data/lib/mint/resource.rb +19 -9
- data/lib/mint/style.rb +10 -14
- data/lib/mint/version.rb +1 -1
- data/lib/mint.rb +1 -0
- data/man/mint.1 +135 -0
- data/spec/cli/README.md +99 -0
- data/spec/cli/argument_parsing_spec.rb +237 -0
- data/spec/cli/bin_integration_spec.rb +348 -0
- data/spec/cli/configuration_management_spec.rb +363 -0
- data/spec/cli/full_workflow_integration_spec.rb +527 -0
- data/spec/cli/publish_workflow_spec.rb +368 -0
- data/spec/cli/template_management_spec.rb +300 -0
- data/spec/css_parser_spec.rb +149 -0
- data/spec/css_spec.rb +1 -1
- data/spec/document_spec.rb +102 -69
- data/spec/helpers_spec.rb +42 -42
- data/spec/mint_spec.rb +104 -80
- data/spec/plugin_spec.rb +141 -143
- data/spec/run_cli_tests.rb +95 -0
- data/spec/spec_helper.rb +8 -1
- data/spec/style_spec.rb +18 -16
- data/spec/support/cli_helpers.rb +169 -0
- data/spec/support/fixtures/content-2.md +16 -0
- data/spec/support/matchers.rb +1 -1
- metadata +116 -224
- data/config/syntax.yaml +0 -71
- data/config/templates/base/style.sass +0 -144
- data/config/templates/default/css/style.css +0 -158
- data/config/templates/default/layout.haml +0 -8
- data/config/templates/default/style.sass +0 -36
- data/config/templates/protocol/layout.haml +0 -7
- data/config/templates/protocol/style.sass +0 -20
- data/config/templates/zen/css/style.css +0 -145
- data/config/templates/zen/layout.haml +0 -7
- data/config/templates/zen/style.sass +0 -24
- data/features/config.feature +0 -21
- data/features/plugins/epub.feature +0 -23
- data/features/publish.feature +0 -73
- data/features/support/env.rb +0 -15
- data/features/templates.feature +0 -79
- data/spec/command_line_spec.rb +0 -87
- data/spec/plugins/epub_spec.rb +0 -242
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
|
3
|
+
module Mint
|
4
|
+
class CSSTemplate < Tilt::Template
|
5
|
+
self.default_mime_type = 'text/css'
|
6
|
+
|
7
|
+
def prepare
|
8
|
+
@data = data
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate(scope, locals, &block)
|
12
|
+
process_imports(@data, File.dirname(file))
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_imports(css_content, base_dir)
|
16
|
+
css_content.gsub(/@import\s+["']([^"']+)["'];?/) do |match|
|
17
|
+
import_path = $1
|
18
|
+
|
19
|
+
# If we find a relative path, resolve it
|
20
|
+
if import_path.start_with?('../', './')
|
21
|
+
full_path = File.expand_path(import_path, base_dir)
|
22
|
+
else
|
23
|
+
full_path = File.join(base_dir, import_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
full_path += '.css' unless full_path.end_with?('.css')
|
27
|
+
|
28
|
+
if File.exist?(full_path)
|
29
|
+
imported_content = File.read(full_path)
|
30
|
+
process_imports(imported_content, File.dirname(full_path))
|
31
|
+
else
|
32
|
+
match
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/mint/document.rb
CHANGED
@@ -1,57 +1,81 @@
|
|
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
|
7
8
|
METADATA_DELIM = "\n\n"
|
8
9
|
|
9
10
|
# Creates a new Mint Document object. Can be block initialized.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def initialize(source,
|
12
|
+
root: nil,
|
13
|
+
destination: nil,
|
14
|
+
context: nil,
|
15
|
+
name: nil,
|
16
|
+
style_mode: :inline,
|
17
|
+
style_destination: nil,
|
18
|
+
layout: nil,
|
19
|
+
style: nil,
|
20
|
+
template: nil,
|
21
|
+
layout_or_style_or_template: [:template, 'default'],
|
22
|
+
all_files: nil,
|
23
|
+
&block)
|
24
|
+
|
25
|
+
destination = preserve_folder_structure!(source, root, destination)
|
26
|
+
|
27
|
+
@all_files = all_files if all_files && all_files.any?
|
28
|
+
|
29
|
+
style_mode = :external if style_destination && style_mode == :inline
|
14
30
|
|
15
31
|
# Loads source and destination, which will be used for
|
16
32
|
# all source_* and destination_* virtual attributes.
|
17
|
-
super(source,
|
18
|
-
self.type
|
33
|
+
super(source, root: root, destination: destination, context: context, name: name)
|
34
|
+
self.type = :document
|
19
35
|
|
20
36
|
# Each of these should invoke explicitly defined method
|
21
|
-
self.content
|
22
|
-
self.
|
23
|
-
self.
|
24
|
-
|
37
|
+
self.content = source
|
38
|
+
self.style_mode = style_mode
|
39
|
+
self.style_destination = style_destination
|
40
|
+
|
41
|
+
if layout_or_style_or_template
|
42
|
+
type, name = layout_or_style_or_template
|
43
|
+
case type
|
44
|
+
when :template
|
45
|
+
self.template = name
|
46
|
+
when :layout
|
47
|
+
self.layout = name
|
48
|
+
when :style
|
49
|
+
self.style = name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Individual layout/style options can override the above
|
54
|
+
self.layout = layout if layout
|
55
|
+
self.style = style if style
|
25
56
|
|
26
57
|
# The template option will override layout and style choices
|
27
|
-
self.template =
|
58
|
+
self.template = template if template
|
28
59
|
|
29
60
|
# Yield self to block after all other parameters are loaded,
|
30
61
|
# so we only have to tweak. (We don't have to give up our
|
31
62
|
# defaults or re-test blocks beyond them being tweaked.)
|
32
|
-
yield self if
|
63
|
+
yield self if block
|
33
64
|
end
|
34
65
|
|
35
66
|
# Renders content in the context of layout and returns as a String.
|
36
67
|
def render(args={})
|
37
68
|
intermediate_content = layout.render self, args
|
38
|
-
Mint.after_render(intermediate_content)
|
69
|
+
Mint.after_render(intermediate_content, {})
|
39
70
|
end
|
40
71
|
|
41
72
|
# Writes all rendered content where a) possible, b) required,
|
42
73
|
# and c) specified. Outputs to specified file.
|
43
|
-
def publish!(opts={})
|
74
|
+
def publish!(opts={})
|
44
75
|
options = { :render_style => true }.merge(opts)
|
45
|
-
|
46
|
-
File.open(self.destination_file, "w+") do |f|
|
47
|
-
f << self.render
|
48
|
-
end
|
76
|
+
super
|
49
77
|
|
50
|
-
|
51
|
-
# b) it actually needs rendering (i.e., it's in template form and
|
52
|
-
# not raw, browser-parseable CSS) or it if it doesn't need
|
53
|
-
# rendering but there is an explicit style_destination.
|
54
|
-
if options[:render_style]
|
78
|
+
if @style_mode == :external && options[:render_style]
|
55
79
|
FileUtils.mkdir_p style_destination_directory
|
56
80
|
File.open(self.style_destination_file, "w+") do |f|
|
57
81
|
f << self.style.render
|
@@ -63,7 +87,12 @@ module Mint
|
|
63
87
|
|
64
88
|
# Implicit readers are paired with explicit accessors. This
|
65
89
|
# allows for processing variables before storing them.
|
66
|
-
attr_reader :
|
90
|
+
attr_reader :metadata, :layout, :style
|
91
|
+
|
92
|
+
# Returns HTML content marked as safe for template rendering
|
93
|
+
def content
|
94
|
+
@content.html_safe
|
95
|
+
end
|
67
96
|
|
68
97
|
# Passes content through a renderer before assigning it to be
|
69
98
|
# the Document's content
|
@@ -76,7 +105,8 @@ module Mint
|
|
76
105
|
original_content = File.read content
|
77
106
|
|
78
107
|
@metadata, text = Document.parse_metadata_from original_content
|
79
|
-
|
108
|
+
text_with_links = Helpers.transform_markdown_links text
|
109
|
+
intermediate_content = Mint.before_render text_with_links, {}
|
80
110
|
|
81
111
|
File.open(tempfile, "w") do |file|
|
82
112
|
file << intermediate_content
|
@@ -91,33 +121,29 @@ module Mint
|
|
91
121
|
# @param [String, Layout, #render] layout a Layout object or name
|
92
122
|
# of a layout to be looked up
|
93
123
|
# @return [void]
|
94
|
-
def layout=(layout)
|
95
|
-
@layout =
|
124
|
+
def layout=(layout)
|
125
|
+
@layout =
|
96
126
|
if layout.respond_to? :render
|
97
127
|
layout
|
98
128
|
else
|
99
|
-
layout_file = Mint.
|
100
|
-
Layout.new
|
129
|
+
layout_file = Mint.lookup_layout layout
|
130
|
+
Layout.new(layout_file, root: self.root, destination: self.destination, context: self.context)
|
101
131
|
end
|
102
|
-
rescue TemplateNotFoundException
|
103
|
-
abort "Template '#{layout}' does not exist."
|
104
132
|
end
|
105
|
-
|
133
|
+
|
106
134
|
# Sets layout to an existing Style object or looks it up by name
|
107
135
|
#
|
108
136
|
# @param [String, Style, #render] layout a Layout object or name
|
109
137
|
# of a layout to be looked up
|
110
138
|
# @return [void]
|
111
139
|
def style=(style)
|
112
|
-
@style =
|
140
|
+
@style =
|
113
141
|
if style.respond_to? :render
|
114
142
|
style
|
115
143
|
else
|
116
|
-
style_file = Mint.
|
117
|
-
Style.new
|
144
|
+
style_file = Mint.lookup_style style
|
145
|
+
Style.new(style_file, root: self.root, destination: self.destination, context: self.context)
|
118
146
|
end
|
119
|
-
rescue TemplateNotFoundException
|
120
|
-
abort "Template '#{style}' does not exist."
|
121
147
|
end
|
122
148
|
|
123
149
|
# Overrides layout and style settings with named template.
|
@@ -148,8 +174,14 @@ module Mint
|
|
148
174
|
#
|
149
175
|
# The style_destination attribute is lazy. It's exposed via
|
150
176
|
# virtual attributes like #style_destination_file.
|
151
|
-
attr_reader :style_destination
|
152
|
-
|
177
|
+
attr_reader :style_destination, :style_mode
|
178
|
+
|
179
|
+
# @param [Symbol] style_mode how styles should be incorporated (:inline or :external)
|
180
|
+
# @return [void]
|
181
|
+
def style_mode=(style_mode)
|
182
|
+
@style_mode = style_mode
|
183
|
+
end
|
184
|
+
|
153
185
|
# @param [String] style_destination the subdirectory into
|
154
186
|
# which styles will be rendered or copied
|
155
187
|
# @return [void]
|
@@ -163,7 +195,7 @@ module Mint
|
|
163
195
|
def style_destination_file_path
|
164
196
|
if style_destination
|
165
197
|
path = Pathname.new style_destination
|
166
|
-
dir = path.absolute? ?
|
198
|
+
dir = path.absolute? ?
|
167
199
|
path : destination_directory_path + path
|
168
200
|
dir + style.name
|
169
201
|
else
|
@@ -197,16 +229,140 @@ module Mint
|
|
197
229
|
# Returns a relative path from the document to its stylesheet. Can
|
198
230
|
# be called directly from inside a layout template.
|
199
231
|
def stylesheet
|
200
|
-
|
232
|
+
tmp_style_dir = Mint.path_for_scope(:user) + "tmp"
|
233
|
+
tmp_style_file = tmp_style_dir + File.basename(style.name)
|
234
|
+
Helpers.normalize_path(tmp_style_file.to_s,
|
201
235
|
self.destination_directory).to_s
|
202
236
|
end
|
203
237
|
|
238
|
+
# Returns the rendered CSS content for inline inclusion
|
239
|
+
def inline_stylesheet
|
240
|
+
self.style.render
|
241
|
+
end
|
242
|
+
|
243
|
+
# Returns either inline CSS or stylesheet link based on style mode
|
244
|
+
# Use this helper in layouts instead of stylesheet or inline_stylesheet directly
|
245
|
+
def stylesheet_tag
|
246
|
+
case @style_mode
|
247
|
+
when :external
|
248
|
+
"<link rel=\"stylesheet\" href=\"#{stylesheet}\">".html_safe
|
249
|
+
when :original
|
250
|
+
original_stylesheet_tags.html_safe
|
251
|
+
else # :inline (default)
|
252
|
+
"<style>#{self.style.render}</style>".html_safe
|
253
|
+
end
|
254
|
+
end
|
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
|
+
|
271
|
+
# Parses styles defined in YAML metadata in content, including it
|
272
|
+
# in output CSS style
|
273
|
+
#
|
274
|
+
# TODO: Implement injection of these styles
|
204
275
|
def inline_styles
|
205
276
|
CSS.parse(metadata)
|
206
277
|
end
|
207
278
|
|
279
|
+
# Returns information about all files for navigation in some templates (e.g., garden)
|
280
|
+
# Available when processing multiple files
|
281
|
+
def files
|
282
|
+
return [] unless @all_files
|
283
|
+
|
284
|
+
# Get the base directories
|
285
|
+
source_base_dir = Pathname.new(root_directory_path).expand_path
|
286
|
+
|
287
|
+
# Calculate where the current file will actually be placed
|
288
|
+
current_source_path = Pathname.new(source_file_path).expand_path
|
289
|
+
current_relative_to_source = current_source_path.relative_path_from(source_base_dir)
|
290
|
+
current_html_filename = current_relative_to_source.to_s.gsub(/\.(#{Mint::MARKDOWN_EXTENSIONS.join('|')})$/i, '.html')
|
291
|
+
|
292
|
+
dest_base = Pathname.new(root_directory_path).expand_path
|
293
|
+
if destination && !destination.empty?
|
294
|
+
dest_base = dest_base + destination
|
295
|
+
end
|
296
|
+
|
297
|
+
current_full_path = dest_base + current_html_filename
|
298
|
+
current_destination_dir = current_full_path.dirname
|
299
|
+
|
300
|
+
@all_files.map do |file|
|
301
|
+
title = extract_title_from_file(file)
|
302
|
+
|
303
|
+
# Calculate where this target file will be placed
|
304
|
+
file_path = Pathname.new(file).expand_path
|
305
|
+
relative_to_source = file_path.relative_path_from(source_base_dir)
|
306
|
+
html_filename = relative_to_source.to_s.gsub(/\.(#{Mint::MARKDOWN_EXTENSIONS.join('|')})$/i, '.html')
|
307
|
+
|
308
|
+
target_full_path = dest_base + html_filename
|
309
|
+
|
310
|
+
# Calculate the relative path from the current file's destination directory to the target file
|
311
|
+
relative_link = target_full_path.relative_path_from(current_destination_dir)
|
312
|
+
|
313
|
+
{
|
314
|
+
source_path: relative_to_source.to_s,
|
315
|
+
html_path: relative_link.to_s,
|
316
|
+
title: title,
|
317
|
+
depth: relative_to_source.to_s.count('/')
|
318
|
+
}
|
319
|
+
end.sort_by {|f| f[:source_path] }
|
320
|
+
end
|
321
|
+
|
208
322
|
# Functions
|
209
323
|
|
324
|
+
private
|
325
|
+
|
326
|
+
# Extracts the title from a markdown file, trying H1 first, then filename
|
327
|
+
def extract_title_from_file(file)
|
328
|
+
content = File.read(file)
|
329
|
+
|
330
|
+
if content =~ /^#\s+(.+)$/
|
331
|
+
return $1.strip
|
332
|
+
end
|
333
|
+
|
334
|
+
File.basename(file, '.*').tr('_-', ' ').split.map(&:capitalize).join(' ')
|
335
|
+
rescue
|
336
|
+
File.basename(file, '.*').tr('_-', ' ').split.map(&:capitalize).join(' ')
|
337
|
+
end
|
338
|
+
|
339
|
+
# Preserves folder structure when --recursive is used
|
340
|
+
#
|
341
|
+
# @param [String] source the source file path
|
342
|
+
# @param [Hash] options the options hash to modify
|
343
|
+
def preserve_folder_structure!(source, root, destination)
|
344
|
+
source_path = Pathname.new(source).expand_path
|
345
|
+
root_path = Pathname.new(root || Dir.getwd).expand_path
|
346
|
+
|
347
|
+
relative_path = source_path.relative_path_from(root_path)
|
348
|
+
|
349
|
+
relative_dir = relative_path.dirname
|
350
|
+
filename = relative_path.basename
|
351
|
+
|
352
|
+
# Set destination to preserve directory structure
|
353
|
+
if relative_dir.to_s != "."
|
354
|
+
# Combine base destination with relative directory structure
|
355
|
+
base_destination = destination || ""
|
356
|
+
if base_destination.empty?
|
357
|
+
destination = relative_dir.to_s
|
358
|
+
else
|
359
|
+
destination = File.join(base_destination, relative_dir.to_s)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
destination
|
364
|
+
end
|
365
|
+
|
210
366
|
class << self
|
211
367
|
def metadata_chunk(text)
|
212
368
|
text.split(METADATA_DELIM).first
|
@@ -214,16 +370,20 @@ module Mint
|
|
214
370
|
|
215
371
|
def metadata_from(text)
|
216
372
|
raw_metadata = YAML.load metadata_chunk(text)
|
217
|
-
|
373
|
+
|
218
374
|
case raw_metadata
|
219
375
|
when String
|
220
376
|
{}
|
221
377
|
when false
|
222
378
|
{}
|
379
|
+
when nil
|
380
|
+
{}
|
223
381
|
else
|
224
382
|
raw_metadata
|
225
383
|
end
|
226
|
-
rescue
|
384
|
+
rescue Psych::SyntaxError
|
385
|
+
{}
|
386
|
+
rescue Exception
|
227
387
|
{}
|
228
388
|
end
|
229
389
|
|
data/lib/mint/helpers.rb
CHANGED
@@ -4,7 +4,7 @@ require "yaml"
|
|
4
4
|
require "active_support/core_ext/string/inflections"
|
5
5
|
|
6
6
|
module Mint
|
7
|
-
module Helpers
|
7
|
+
module Helpers
|
8
8
|
def self.underscore(obj, opts={})
|
9
9
|
namespaces = obj.to_s.split("::").map do |namespace|
|
10
10
|
if opts[:ignore_prefix]
|
@@ -38,7 +38,7 @@ module Mint
|
|
38
38
|
def self.symbolize(obj)
|
39
39
|
slugize(obj).gsub(/-/, "_").to_sym
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# Transforms a String or Pathname into a fully expanded Pathname.
|
43
43
|
#
|
44
44
|
# @param [String, Pathname] str_or_path a path to be expanded
|
@@ -59,8 +59,8 @@ module Mint
|
|
59
59
|
def self.symbolize_keys(map, opts={})
|
60
60
|
transform = lambda {|x| opts[:downcase] ? x.downcase : x }
|
61
61
|
|
62
|
-
map.reduce(Hash.new) do |syms,(k,v)|
|
63
|
-
syms[transform[k].to_sym] =
|
62
|
+
map.reduce(Hash.new) do |syms,(k,v)|
|
63
|
+
syms[transform[k].to_sym] =
|
64
64
|
case v
|
65
65
|
when Hash
|
66
66
|
self.symbolize_keys(v, opts)
|
@@ -107,19 +107,19 @@ module Mint
|
|
107
107
|
Hash[*list1.zip(list2).flatten]
|
108
108
|
end
|
109
109
|
|
110
|
-
# Returns the relative path to to_directory from from_directory.
|
111
|
-
# If to_directory and from_directory have no parents in common besides
|
110
|
+
# Returns the relative path to to_directory from from_directory.
|
111
|
+
# If to_directory and from_directory have no parents in common besides
|
112
112
|
# /, returns the absolute directory of to_directory. Assumes no symlinks.
|
113
113
|
#
|
114
114
|
# @param [String, Pathname] to_directory the target directory
|
115
115
|
# @param [String, Pathname] from_directory the starting directory
|
116
|
-
# @return [Pathname] the relative path to to_directory from
|
116
|
+
# @return [Pathname] the relative path to to_directory from
|
117
117
|
# from_directory, or an absolute path if they have no parents in common
|
118
118
|
# other than /
|
119
119
|
def self.normalize_path(to_directory, from_directory)
|
120
120
|
to_path, from_path = [to_directory, from_directory].map {|d| pathize d }
|
121
121
|
to_root, from_root = [to_path, from_path].map {|p| p.each_filename.first }
|
122
|
-
to_root == from_root ?
|
122
|
+
to_root == from_root ?
|
123
123
|
to_path.relative_path_from(from_path) :
|
124
124
|
to_path
|
125
125
|
end
|
@@ -129,15 +129,33 @@ module Mint
|
|
129
129
|
#
|
130
130
|
# @param [Hash, #[]] new_opts a set of options to add to the Yaml file
|
131
131
|
# @param [Pathname, #exist] file a file to read from and write to
|
132
|
-
# @return [void]
|
132
|
+
# @return [void]
|
133
133
|
def self.update_yaml!(file, opts={})
|
134
|
-
curr_opts = File.exist?(file)
|
134
|
+
curr_opts = if File.exist?(file)
|
135
|
+
begin
|
136
|
+
YAML.load_file(file) || {}
|
137
|
+
rescue Psych::SyntaxError, StandardError
|
138
|
+
# Handle corrupted YAML gracefully by treating it as empty
|
139
|
+
{}
|
140
|
+
end
|
141
|
+
else
|
142
|
+
{}
|
143
|
+
end
|
135
144
|
|
136
145
|
File.open file, "w" do |f|
|
137
146
|
YAML.dump(curr_opts.merge(opts), f)
|
138
147
|
end
|
139
148
|
end
|
140
149
|
|
150
|
+
def self.create_temp_file!(basename, extension=nil, &block)
|
151
|
+
tmp_args = basename && extension ? [basename, extension] : basename
|
152
|
+
tempfile = Tempfile.new(tmp_args)
|
153
|
+
block.call(tempfile)
|
154
|
+
tempfile.flush
|
155
|
+
tempfile.close
|
156
|
+
tempfile.path
|
157
|
+
end
|
158
|
+
|
141
159
|
def self.generate_temp_file!(file)
|
142
160
|
basename = File.basename file
|
143
161
|
extension = File.extname file
|
@@ -149,5 +167,27 @@ module Mint
|
|
149
167
|
tempfile.close
|
150
168
|
tempfile.path
|
151
169
|
end
|
170
|
+
|
171
|
+
# Transforms markdown links from .md extensions to .html for digital gardens
|
172
|
+
#
|
173
|
+
# @param [String] text the markdown text containing links
|
174
|
+
# @return [String] the text with transformed links
|
175
|
+
def self.transform_markdown_links(text)
|
176
|
+
# Transform relative markdown links like [text](path/file.md) to [text](path/file.html)
|
177
|
+
text.gsub(/(\[([^\]]*)\]\()([^)]*\.md)(\))/) do |match|
|
178
|
+
link_start = $1
|
179
|
+
link_text = $2
|
180
|
+
link_url = $3
|
181
|
+
link_end = $4
|
182
|
+
|
183
|
+
# Only transform relative links (not absolute URLs)
|
184
|
+
if link_url !~ /^https?:\/\//
|
185
|
+
new_url = link_url.gsub(/\.md$/, '.html')
|
186
|
+
"#{link_start}#{new_url}#{link_end}"
|
187
|
+
else
|
188
|
+
match
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
152
192
|
end
|
153
193
|
end
|
data/lib/mint/layout.rb
CHANGED
@@ -6,9 +6,8 @@ module Mint
|
|
6
6
|
# and optional configuration options.
|
7
7
|
#
|
8
8
|
# @param [String] source the absolute or relative file path
|
9
|
-
|
10
|
-
|
11
|
-
super(source, opts)
|
9
|
+
def initialize(source, root: nil, destination: nil, context: nil, name: nil, &block)
|
10
|
+
super(source, root: root, destination: destination, context: context, name: name, &block)
|
12
11
|
self.type = :layout
|
13
12
|
end
|
14
13
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
require 'redcarpet'
|
3
|
+
|
4
|
+
module Mint
|
5
|
+
class MarkdownTemplate < Tilt::Template
|
6
|
+
self.default_mime_type = 'text/html'
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
@options = options.dup
|
10
|
+
|
11
|
+
renderer_options = {
|
12
|
+
filter_html: false,
|
13
|
+
no_images: false,
|
14
|
+
no_links: false,
|
15
|
+
no_styles: false,
|
16
|
+
escape_html: false,
|
17
|
+
safe_links_only: false,
|
18
|
+
with_toc_data: false,
|
19
|
+
hard_wrap: false,
|
20
|
+
prettify: false
|
21
|
+
}.merge(@options)
|
22
|
+
|
23
|
+
markdown_options = {
|
24
|
+
tables: true,
|
25
|
+
autolink: true,
|
26
|
+
no_intra_emphasis: true,
|
27
|
+
fenced_code_blocks: true,
|
28
|
+
lax_html_blocks: false,
|
29
|
+
strikethrough: true,
|
30
|
+
superscript: false,
|
31
|
+
footnotes: false,
|
32
|
+
highlight: false,
|
33
|
+
quote: false,
|
34
|
+
disable_indented_code_blocks: false,
|
35
|
+
space_after_headers: false,
|
36
|
+
underline: false
|
37
|
+
}
|
38
|
+
|
39
|
+
@renderer = @options.delete(:renderer) || Redcarpet::Render::HTML.new(renderer_options)
|
40
|
+
@markdown = Redcarpet::Markdown.new(@renderer, markdown_options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def evaluate(scope, locals, &block)
|
44
|
+
@markdown.render(data)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|