fronde 0.3.4 → 0.4.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 +4 -4
- data/bin/fronde +15 -30
- data/lib/ext/nil_time.rb +25 -0
- data/lib/ext/r18n.rb +17 -0
- data/lib/ext/time.rb +49 -0
- data/lib/fronde/cli/commands.rb +92 -103
- data/lib/fronde/cli/data/Rakefile +8 -0
- data/lib/fronde/cli/data/config.yml +13 -0
- data/lib/fronde/cli/data/gitignore +7 -0
- data/lib/fronde/cli/data/zsh_completion +37 -0
- data/lib/fronde/cli/helpers.rb +55 -0
- data/lib/fronde/cli/opt_parse.rb +143 -0
- data/lib/fronde/cli/throbber.rb +99 -0
- data/lib/fronde/cli.rb +41 -42
- data/lib/fronde/config/data/org-config.el +24 -0
- data/lib/fronde/config/{ox-fronde.el → data/ox-fronde.el} +1 -1
- data/lib/fronde/config/helpers.rb +80 -0
- data/lib/fronde/config/lisp.rb +70 -0
- data/lib/fronde/config.rb +135 -99
- data/lib/fronde/emacs.rb +23 -20
- data/lib/fronde/index/atom_generator.rb +55 -66
- data/lib/fronde/index/data/all_tags.org +14 -0
- data/lib/fronde/index/data/template.org +22 -0
- data/lib/fronde/index/data/template.xml +37 -0
- data/lib/fronde/index/org_generator.rb +70 -88
- data/lib/fronde/index.rb +56 -82
- data/lib/fronde/org/file.rb +287 -0
- data/lib/fronde/org/file_extracter.rb +98 -0
- data/lib/fronde/org.rb +103 -0
- data/lib/fronde/preview.rb +43 -39
- data/lib/fronde/slug.rb +27 -0
- data/lib/fronde/source/gemini.rb +39 -0
- data/lib/fronde/source/html.rb +67 -0
- data/lib/fronde/source.rb +204 -0
- data/lib/fronde/templater.rb +94 -71
- data/lib/fronde/version.rb +1 -1
- data/lib/tasks/cli.rake +33 -0
- data/lib/tasks/org.rake +62 -42
- data/lib/tasks/site.rake +68 -30
- data/lib/tasks/sync.rake +41 -21
- data/lib/tasks/tags.rake +11 -7
- data/locales/en.yml +60 -14
- data/locales/fr.yml +68 -14
- metadata +53 -110
- data/lib/fronde/config/lisp_config.rb +0 -340
- data/lib/fronde/config/org-config.el +0 -19
- data/lib/fronde/org_file/class_methods.rb +0 -72
- data/lib/fronde/org_file/extracter.rb +0 -72
- data/lib/fronde/org_file/htmlizer.rb +0 -43
- data/lib/fronde/org_file.rb +0 -298
- data/lib/fronde/utils.rb +0 -229
@@ -1,340 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'json'
|
4
|
-
require 'open-uri'
|
5
|
-
require 'fronde/version'
|
6
|
-
|
7
|
-
def fetch_org_version
|
8
|
-
# Retrieve last org version from git repository tags page.
|
9
|
-
tag_rx = Regexp.new(
|
10
|
-
'<a href=\'/cgit/emacs/org-mode.git/tag/\?h=' \
|
11
|
-
'(?<tag>release_(?<number>[^\']+))\'>\k<tag></a>'
|
12
|
-
)
|
13
|
-
versions = URI(
|
14
|
-
'https://git.savannah.gnu.org/cgit/emacs/org-mode.git/refs/'
|
15
|
-
).open.readlines.map do |line|
|
16
|
-
line.match(tag_rx) { |matchdata| matchdata[:number] }
|
17
|
-
end
|
18
|
-
versions.compact.first
|
19
|
-
end
|
20
|
-
|
21
|
-
module Fronde
|
22
|
-
# This module contains utilitary methods to ease ~org-config.el~
|
23
|
-
# file generation
|
24
|
-
module LispConfig
|
25
|
-
# Fetch and return the last published version of Org.
|
26
|
-
#
|
27
|
-
# @return [String] the new x.x.x version string of Org
|
28
|
-
def org_last_version
|
29
|
-
return @org_version if @org_version
|
30
|
-
if File.exist?('var/tmp/last_org_version')
|
31
|
-
@org_version = File.read('var/tmp/last_org_version')
|
32
|
-
return @org_version
|
33
|
-
end
|
34
|
-
@org_version = fetch_org_version
|
35
|
-
FileUtils.mkdir_p 'var/tmp'
|
36
|
-
File.write('var/tmp/last_org_version', @org_version)
|
37
|
-
@org_version
|
38
|
-
end
|
39
|
-
|
40
|
-
# Generate emacs lisp configuration file for Org and write it.
|
41
|
-
#
|
42
|
-
# This method saves the generated configuration in the file
|
43
|
-
# ~org-config.el~ at the root of your project, overwriting it if it
|
44
|
-
# existed already.
|
45
|
-
#
|
46
|
-
# @return [Integer] the length written (as returned by the
|
47
|
-
# underlying ~File.write~ method call)
|
48
|
-
# rubocop:disable Metrics/MethodLength
|
49
|
-
def write_org_lisp_config(with_tags: false)
|
50
|
-
projects = org_generate_projects(with_tags: with_tags)
|
51
|
-
workdir = Dir.pwd
|
52
|
-
content = File.read(File.expand_path('./org-config.el', __dir__))
|
53
|
-
.gsub('__VERSION__', Fronde::VERSION)
|
54
|
-
.gsub('__WORK_DIR__', workdir)
|
55
|
-
.gsub('__FRONDE_DIR__', __dir__)
|
56
|
-
.gsub('__ORG_VER__', org_last_version)
|
57
|
-
.gsub(
|
58
|
-
'__ALL_PROJECTS__',
|
59
|
-
projects.values.join("\n ")
|
60
|
-
)
|
61
|
-
.gsub('__THEME_CONFIG__', org_default_theme_config)
|
62
|
-
.gsub('__ALL_PROJECTS_NAMES__', project_names(projects))
|
63
|
-
.gsub('__LONG_DATE_FMT__', r18n_full_datetime_format)
|
64
|
-
.gsub('__AUTHOR_EMAIL__', get('author_email', ''))
|
65
|
-
.gsub('__AUTHOR_NAME__', get('author'))
|
66
|
-
FileUtils.mkdir_p "#{workdir}/var/lib"
|
67
|
-
File.write("#{workdir}/var/lib/org-config.el", content)
|
68
|
-
end
|
69
|
-
# rubocop:enable Metrics/MethodLength
|
70
|
-
|
71
|
-
# Generate emacs directory variables file.
|
72
|
-
#
|
73
|
-
# This method generate the file ~.dir-locals.el~, which is
|
74
|
-
# responsible to load fronde Org settings when visiting an Org file
|
75
|
-
# of this fronde instance.
|
76
|
-
#
|
77
|
-
# @return [Integer] the length written (as returned by the
|
78
|
-
# underlying ~File.write~ method call)
|
79
|
-
def write_dir_locals
|
80
|
-
workdir = Dir.pwd
|
81
|
-
# rubocop:disable Layout/LineLength
|
82
|
-
File.write(
|
83
|
-
"#{workdir}/.dir-locals.el",
|
84
|
-
"((org-mode . ((eval . (load-file \"#{workdir}/var/lib/org-config.el\")))))"
|
85
|
-
)
|
86
|
-
# rubocop:enable Layout/LineLength
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def r18n_full_datetime_format
|
92
|
-
locale = R18n.get.locale
|
93
|
-
date_fmt = R18n.t.fronde.index.full_date_format(
|
94
|
-
date: locale.full_format
|
95
|
-
)
|
96
|
-
date_fmt = locale.year_format.sub('_', date_fmt)
|
97
|
-
time_fmt = locale.time_format.delete('_').strip
|
98
|
-
R18n.t.fronde.index.full_date_with_time_format(
|
99
|
-
date: date_fmt, time: time_fmt
|
100
|
-
)
|
101
|
-
end
|
102
|
-
|
103
|
-
def ruby_to_lisp_boolean(value)
|
104
|
-
return 't' if value == true
|
105
|
-
'nil'
|
106
|
-
end
|
107
|
-
|
108
|
-
def project_names(projects)
|
109
|
-
names = projects.keys.map do |p|
|
110
|
-
["\"#{p}\"", "\"#{p}-assets\""]
|
111
|
-
end.flatten
|
112
|
-
names << "\"theme-#{get('theme')}\"" unless get('theme') == 'default'
|
113
|
-
sources.each do |s|
|
114
|
-
# Default theme defined in settings is already included
|
115
|
-
next unless s['theme'] && s['theme'] != get('theme')
|
116
|
-
# Never include theme named 'default' as it does not rely on any
|
117
|
-
# file to export.
|
118
|
-
next if s['theme'] == 'default'
|
119
|
-
theme = "\"theme-#{s['theme']}\""
|
120
|
-
next if names.include? theme
|
121
|
-
names << theme
|
122
|
-
end
|
123
|
-
names.join(' ')
|
124
|
-
end
|
125
|
-
|
126
|
-
# Return the full path to the publication path of a given project
|
127
|
-
# configuration.
|
128
|
-
#
|
129
|
-
# @param project [Hash] a project configuration (as extracted from
|
130
|
-
# the ~sources~ key)
|
131
|
-
# @return [String] the full path to the target dir of this project
|
132
|
-
def publication_path(project)
|
133
|
-
publish_in = [Dir.pwd]
|
134
|
-
if project['type'] == 'gemini'
|
135
|
-
publish_in << get('gemini_public_folder', 'public_gmi')
|
136
|
-
else
|
137
|
-
publish_in << get('public_folder')
|
138
|
-
end
|
139
|
-
publish_in << project['target'] unless project['target'] == '.'
|
140
|
-
publish_in.join('/')
|
141
|
-
end
|
142
|
-
|
143
|
-
# Return the publication function needed for a given project
|
144
|
-
# configuration.
|
145
|
-
#
|
146
|
-
# @param project [Hash] a project configuration (as extracted from
|
147
|
-
# the ~sources~ key)
|
148
|
-
# @return [String] the org publication function name
|
149
|
-
def publication_function(project)
|
150
|
-
case project['type']
|
151
|
-
when 'gemini'
|
152
|
-
'org-gmi-publish-to-gemini'
|
153
|
-
else
|
154
|
-
'org-html-publish-to-html'
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def org_project(project_name, opts)
|
159
|
-
shared_lines = org_project_shared_lines(opts)
|
160
|
-
project_config = [
|
161
|
-
org_project_config(project_name, opts, shared_lines),
|
162
|
-
org_assets_config(project_name, shared_lines)
|
163
|
-
]
|
164
|
-
themeconf = org_theme_config(opts['theme'])
|
165
|
-
project_config << themeconf unless themeconf == ''
|
166
|
-
project_config.join("\n ")
|
167
|
-
end
|
168
|
-
|
169
|
-
def org_default_html_postamble
|
170
|
-
<<~POSTAMBLE
|
171
|
-
<p><span class="author">#{R18n.t.fronde.org.postamble.written_by}</span>
|
172
|
-
#{R18n.t.fronde.org.postamble.with_emacs_html}</p>
|
173
|
-
<p class="date">#{R18n.t.fronde.org.postamble.last_modification}</p>
|
174
|
-
<p class="validation">%v</p>
|
175
|
-
POSTAMBLE
|
176
|
-
end
|
177
|
-
|
178
|
-
def org_default_gemini_postamble
|
179
|
-
format(
|
180
|
-
"📅 %<date>s\n📝 %<author>s %<creator>s",
|
181
|
-
author: R18n.t.fronde.org.postamble.written_by,
|
182
|
-
creator: R18n.t.fronde.org.postamble.with_emacs,
|
183
|
-
date: R18n.t.fronde.org.postamble.last_modification
|
184
|
-
)
|
185
|
-
end
|
186
|
-
|
187
|
-
def org_default_html_head
|
188
|
-
<<~HTMLHEAD
|
189
|
-
<link rel="stylesheet" type="text/css" media="screen"
|
190
|
-
href="__DOMAIN__/assets/__THEME__/css/style.css">
|
191
|
-
<link rel="stylesheet" type="text/css" media="screen"
|
192
|
-
href="__DOMAIN__/assets/__THEME__/css/htmlize.css">
|
193
|
-
__ATOM_FEED__
|
194
|
-
HTMLHEAD
|
195
|
-
end
|
196
|
-
|
197
|
-
def org_default_html_options(project)
|
198
|
-
defaults = {
|
199
|
-
'html-postamble' => org_default_html_postamble,
|
200
|
-
'html-head' => '__ATOM_FEED__',
|
201
|
-
'html-head-include-default-style' => 't',
|
202
|
-
'html-head-include-scripts' => 't'
|
203
|
-
}
|
204
|
-
curtheme = project['theme'] || get('theme')
|
205
|
-
return defaults if curtheme.nil? || curtheme == 'default'
|
206
|
-
defaults['html-head'] = org_default_html_head
|
207
|
-
defaults['html-head-include-default-style'] = 'nil'
|
208
|
-
defaults['html-head-include-scripts'] = 'nil'
|
209
|
-
defaults
|
210
|
-
end
|
211
|
-
|
212
|
-
def org_publish_options(project)
|
213
|
-
defaults = {
|
214
|
-
'section-numbers' => 'nil',
|
215
|
-
'with-toc' => 'nil'
|
216
|
-
}
|
217
|
-
if project['type'] == 'gemini'
|
218
|
-
defaults['gemini-postamble'] = org_default_gemini_postamble
|
219
|
-
else
|
220
|
-
defaults.merge!(
|
221
|
-
org_default_html_options(project),
|
222
|
-
get('org-html', {}),
|
223
|
-
project['org-html'] || {}
|
224
|
-
)
|
225
|
-
end
|
226
|
-
defaults.merge(project['org-options'] || {})
|
227
|
-
end
|
228
|
-
|
229
|
-
def expand_vars_in_html_head(head, project)
|
230
|
-
curtheme = project['theme'] || get('theme')
|
231
|
-
# Head may be frozen when coming from settings
|
232
|
-
head = head.gsub('__THEME__', curtheme)
|
233
|
-
.gsub('__DOMAIN__', get('domain'))
|
234
|
-
return head.gsub('__ATOM_FEED__', '') unless project['is_blog']
|
235
|
-
atomfeed = <<~ATOMFEED
|
236
|
-
<link rel="alternate" type="application/atom+xml" title="Atom 1.0"
|
237
|
-
href="#{get('domain')}/feeds/index.xml" />
|
238
|
-
ATOMFEED
|
239
|
-
head.gsub('__ATOM_FEED__', atomfeed)
|
240
|
-
end
|
241
|
-
|
242
|
-
def cast_lisp_value(value)
|
243
|
-
return 't' if value.is_a?(TrueClass)
|
244
|
-
return 'nil' if value.nil? || value.is_a?(FalseClass)
|
245
|
-
value.strip.gsub(/"/, '\"')
|
246
|
-
end
|
247
|
-
|
248
|
-
def build_project_org_headers(project)
|
249
|
-
orgtplopts = org_publish_options(project)
|
250
|
-
lisp_keywords = ['t', 'nil', '1', '-1', '0'].freeze
|
251
|
-
orgtplopts.map do |k, v|
|
252
|
-
v = expand_vars_in_html_head(v, project) if k == 'html-head'
|
253
|
-
val = cast_lisp_value(v)
|
254
|
-
if lisp_keywords.include? val
|
255
|
-
":#{k} #{val}"
|
256
|
-
else
|
257
|
-
":#{k} \"#{val}\""
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
def org_generate_projects(with_tags: false)
|
263
|
-
projects = {}
|
264
|
-
projects_sources = sources
|
265
|
-
if with_tags
|
266
|
-
tags_conf = build_source('tags')
|
267
|
-
tags_conf['recursive'] = false
|
268
|
-
projects_sources << tags_conf
|
269
|
-
end
|
270
|
-
projects_sources.each do |opts|
|
271
|
-
opts['org_headers'] = build_project_org_headers(opts)
|
272
|
-
projects[opts['name']] = org_project(opts['name'], opts)
|
273
|
-
end
|
274
|
-
projects
|
275
|
-
end
|
276
|
-
|
277
|
-
def org_default_theme_config
|
278
|
-
theme_config = org_theme_config(get('theme'))
|
279
|
-
return theme_config if theme_config == ''
|
280
|
-
format("\n %<conf>s", conf: theme_config)
|
281
|
-
end
|
282
|
-
|
283
|
-
def org_theme_config(theme)
|
284
|
-
return '' if theme.nil? || theme == 'default'
|
285
|
-
workdir = Dir.pwd
|
286
|
-
[
|
287
|
-
format('("theme-%<theme>s"', theme: theme),
|
288
|
-
format(' :base-directory "%<wd>s/themes/%<theme>s"',
|
289
|
-
wd: workdir, theme: theme),
|
290
|
-
# rubocop:disable Layout/LineLength
|
291
|
-
' :base-extension "jpg\\\\\\|gif\\\\\\|png\\\\\\|js\\\\\\|css\\\\\\|otf\\\\\\|ttf\\\\\\|woff2?"',
|
292
|
-
# rubocop:enable Layout/LineLength
|
293
|
-
' :recursive t',
|
294
|
-
format(' :publishing-directory "%<wd>s/%<pub>s/assets/%<theme>s"',
|
295
|
-
wd: workdir, pub: get('public_folder'), theme: theme),
|
296
|
-
' :publishing-function org-publish-attachment)'
|
297
|
-
].join("\n ").strip
|
298
|
-
end
|
299
|
-
|
300
|
-
def org_project_shared_lines(project)
|
301
|
-
[
|
302
|
-
format(':base-directory "%<path>s"', path: project['path']),
|
303
|
-
format(
|
304
|
-
':publishing-directory "%<path>s"',
|
305
|
-
path: publication_path(project)
|
306
|
-
),
|
307
|
-
format(
|
308
|
-
':recursive %<rec>s',
|
309
|
-
rec: ruby_to_lisp_boolean(project['recursive'])
|
310
|
-
)
|
311
|
-
]
|
312
|
-
end
|
313
|
-
|
314
|
-
def org_project_config(project_name, project, shared_lines)
|
315
|
-
project_lines = [
|
316
|
-
format('"%<name>s"', name: project_name),
|
317
|
-
':base-extension "org"',
|
318
|
-
format(
|
319
|
-
':publishing-function %<fun>s',
|
320
|
-
fun: publication_function(project)
|
321
|
-
)
|
322
|
-
] + shared_lines + project['org_headers']
|
323
|
-
if project['exclude']
|
324
|
-
project_lines << format(
|
325
|
-
':exclude "%<value>s"', value: project['exclude']
|
326
|
-
)
|
327
|
-
end
|
328
|
-
format('(%<pr>s)', pr: project_lines.join("\n "))
|
329
|
-
end
|
330
|
-
|
331
|
-
def org_assets_config(project_name, shared_lines)
|
332
|
-
assets_lines = [
|
333
|
-
format('"%<name>s-assets"', name: project_name),
|
334
|
-
':base-extension "jpg\\\\\\|gif\\\\\\|png\\\\\\|svg\\\\\\|pdf"',
|
335
|
-
':publishing-function org-publish-attachment'
|
336
|
-
] + shared_lines
|
337
|
-
format('(%<assets>s)', assets: assets_lines.join("\n "))
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
;; Add org-mode to load path
|
2
|
-
(add-to-list 'load-path (expand-file-name "org-__ORG_VER__/lisp" "__WORK_DIR__/lib"))
|
3
|
-
;; Load last version of htmlize.el
|
4
|
-
(load-file (expand-file-name "htmlize.el" "__WORK_DIR__/lib"))
|
5
|
-
|
6
|
-
;; Current project options
|
7
|
-
(setq fronde/version "__VERSION__"
|
8
|
-
fronde/current-work-dir "__WORK_DIR__"
|
9
|
-
user-mail-address "__AUTHOR_EMAIL__"
|
10
|
-
user-full-name "__AUTHOR_NAME__"
|
11
|
-
org-html-metadata-timestamp-format "__LONG_DATE_FMT__"
|
12
|
-
org-gmi-timestamp-format "__LONG_DATE_FMT__"
|
13
|
-
org-publish-project-alist
|
14
|
-
`(__ALL_PROJECTS____THEME_CONFIG__
|
15
|
-
("website" :components (__ALL_PROJECTS_NAMES__))))
|
16
|
-
|
17
|
-
;; Load fronde lib
|
18
|
-
(load-file (expand-file-name "ox-gmi.el" "__WORK_DIR__/lib"))
|
19
|
-
(load-file (expand-file-name "ox-fronde.el" "__FRONDE_DIR__"))
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Fronde
|
4
|
-
# This module holds class methods for the {Fronde::OrgFile} class.
|
5
|
-
module OrgFileClassMethods
|
6
|
-
def source_for_target(file_name)
|
7
|
-
# file_name may be frozen...
|
8
|
-
src = file_name.sub(/\.html\z/, '.org')
|
9
|
-
pubfolder = Fronde::Config.get('public_folder')
|
10
|
-
src.sub!(/^#{pubfolder}\//, '')
|
11
|
-
# Look for match in each possible sources. The first found wins.
|
12
|
-
Fronde::Config.sources.each do |project|
|
13
|
-
if project['target'] == '.'
|
14
|
-
origin = File.join(project['path'], src)
|
15
|
-
else
|
16
|
-
origin = File.join(
|
17
|
-
project['path'], src.sub(/^#{project['target']}\//, '')
|
18
|
-
)
|
19
|
-
end
|
20
|
-
return origin if File.exist?(origin)
|
21
|
-
end
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
def target_for_source(file_name, project, with_public_folder: true)
|
26
|
-
return nil if file_name.nil?
|
27
|
-
# file_name may be frozen...
|
28
|
-
target = file_name.sub(/\.org\z/, '.html').sub(/^#{Dir.pwd}\//, '')
|
29
|
-
if project.nil?
|
30
|
-
subfolder = File.basename(File.dirname(target))
|
31
|
-
target = File.basename(target)
|
32
|
-
target = "#{subfolder}/#{target}" if subfolder != '.'
|
33
|
-
else
|
34
|
-
project_relative_path = project['path'].sub(/^#{Dir.pwd}\//, '')
|
35
|
-
target.sub!(/^#{project_relative_path}\//, '')
|
36
|
-
target = "#{project['target']}/#{target}" if project['target'] != '.'
|
37
|
-
end
|
38
|
-
return target unless with_public_folder
|
39
|
-
pubfolder = Fronde::Config.get('public_folder')
|
40
|
-
"#{pubfolder}/#{target}"
|
41
|
-
end
|
42
|
-
|
43
|
-
def project_for_source(file_name)
|
44
|
-
# Look for match in each possible sources. The first found wins.
|
45
|
-
Fronde::Config.sources.each do |project|
|
46
|
-
project_relative_path = project['path'].sub(/^#{Dir.pwd}\//, '')
|
47
|
-
return project if file_name.match?(/^#{project_relative_path}\//)
|
48
|
-
end
|
49
|
-
nil
|
50
|
-
end
|
51
|
-
|
52
|
-
def slug(title)
|
53
|
-
title.downcase.tr(' ', '-')
|
54
|
-
.encode('ascii', fallback: ->(k) { translit(k) })
|
55
|
-
.gsub(/[^\w-]/, '').delete_suffix('-')
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def translit(char)
|
61
|
-
return 'a' if ['á', 'à', 'â', 'ä', 'ǎ', 'ã', 'å'].include?(char)
|
62
|
-
return 'e' if ['é', 'è', 'ê', 'ë', 'ě', 'ẽ'].include?(char)
|
63
|
-
return 'i' if ['í', 'ì', 'î', 'ï', 'ǐ', 'ĩ'].include?(char)
|
64
|
-
return 'o' if ['ó', 'ò', 'ô', 'ö', 'ǒ', 'õ'].include?(char)
|
65
|
-
return 'u' if ['ú', 'ù', 'û', 'ü', 'ǔ', 'ũ'].include?(char)
|
66
|
-
return 'y' if ['ý', 'ỳ', 'ŷ', 'ÿ', 'ỹ'].include?(char)
|
67
|
-
return 'c' if char == 'ç'
|
68
|
-
return 'n' if char == 'ñ'
|
69
|
-
'-'
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Fronde
|
4
|
-
# This module holds extracter methods for the {Fronde::OrgFile} class.
|
5
|
-
module OrgFileExtracter
|
6
|
-
private
|
7
|
-
|
8
|
-
# Main method, which will call the other to initialize an
|
9
|
-
# {Fronde::OrgFile} instance.
|
10
|
-
def extract_data
|
11
|
-
@content = File.read @file
|
12
|
-
@title = extract_title
|
13
|
-
@subtitle = extract_subtitle
|
14
|
-
@date = extract_date
|
15
|
-
@author = extract_author
|
16
|
-
@keywords = extract_keywords
|
17
|
-
@lang = extract_lang
|
18
|
-
@excerpt = extract_excerpt
|
19
|
-
end
|
20
|
-
|
21
|
-
def extract_date
|
22
|
-
timerx = '([0-9:]{5})(?::([0-9]{2}))?'
|
23
|
-
m = /^#\+date: *<([0-9-]{10}) [\w.]+(?: #{timerx})?> *$/i.match(@content)
|
24
|
-
return nil if m.nil?
|
25
|
-
@notime = m[2].nil?
|
26
|
-
if @notime
|
27
|
-
time = '00:00:00'
|
28
|
-
else
|
29
|
-
time = "#{m[2]}:#{m[3] || '00'}"
|
30
|
-
end
|
31
|
-
DateTime.strptime("#{m[1]} #{time}", '%Y-%m-%d %H:%M:%S')
|
32
|
-
end
|
33
|
-
|
34
|
-
def extract_title
|
35
|
-
m = /^#\+title:(.+)$/i.match(@content)
|
36
|
-
if m.nil?
|
37
|
-
# Avoid to leak absolute path
|
38
|
-
project_relative_path = @file.sub(/^#{Dir.pwd}\//, '')
|
39
|
-
return project_relative_path
|
40
|
-
end
|
41
|
-
m[1].strip
|
42
|
-
end
|
43
|
-
|
44
|
-
def extract_subtitle
|
45
|
-
m = /^#\+subtitle:(.+)$/i.match(@content)
|
46
|
-
return '' if m.nil?
|
47
|
-
m[1].strip
|
48
|
-
end
|
49
|
-
|
50
|
-
def extract_author
|
51
|
-
m = /^#\+author:(.+)$/i.match(@content)
|
52
|
-
return Fronde::Config.get('author') if m.nil?
|
53
|
-
m[1].strip
|
54
|
-
end
|
55
|
-
|
56
|
-
def extract_keywords
|
57
|
-
m = /^#\+keywords:(.+)$/i.match(@content)
|
58
|
-
return [] if m.nil?
|
59
|
-
m[1].split(',').map(&:strip)
|
60
|
-
end
|
61
|
-
|
62
|
-
def extract_lang
|
63
|
-
m = /^#\+language:(.+)$/i.match(@content)
|
64
|
-
return Fronde::Config.get('lang') if m.nil?
|
65
|
-
m[1].strip
|
66
|
-
end
|
67
|
-
|
68
|
-
def extract_excerpt
|
69
|
-
@content.scan(/^#\+description:(.+)$/i).map { |l| l[0].strip }.join(' ')
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'fronde/config'
|
4
|
-
require 'fronde/emacs'
|
5
|
-
|
6
|
-
module Fronde
|
7
|
-
# This module holds HTML formatter methods for the {Fronde::OrgFile}
|
8
|
-
# class.
|
9
|
-
module OrgFileHtmlizer
|
10
|
-
private
|
11
|
-
|
12
|
-
# Format {Fronde::OrgFile#keywords} list in an HTML listing.
|
13
|
-
#
|
14
|
-
# @return [String] the HTML keywords list
|
15
|
-
def keywords_to_html
|
16
|
-
domain = Fronde::Config.get('domain')
|
17
|
-
klist = @keywords.map do |k|
|
18
|
-
<<~KEYWORDLINK
|
19
|
-
<li class="keyword">
|
20
|
-
<a href="#{domain}/tags/#{Fronde::OrgFile.slug(k)}.html">#{k}</a>
|
21
|
-
</li>
|
22
|
-
KEYWORDLINK
|
23
|
-
end.join
|
24
|
-
"<ul class=\"keywords-list\">#{klist}</ul>"
|
25
|
-
end
|
26
|
-
|
27
|
-
# Format {Fronde::OrgFile#date} as a HTML `time` tag.
|
28
|
-
#
|
29
|
-
# @return [String] the HTML `time` tag
|
30
|
-
def date_to_html(dateformat = :full)
|
31
|
-
return '<time></time>' if @date.nil?
|
32
|
-
"<time datetime=\"#{@date.rfc3339}\">#{datestring(dateformat)}</time>"
|
33
|
-
end
|
34
|
-
|
35
|
-
# Format {Fronde::OrgFile#author} in a HTML `span` tag with a
|
36
|
-
# specific class.
|
37
|
-
#
|
38
|
-
# @return [String] the author HTML `span`
|
39
|
-
def author_to_html
|
40
|
-
"<span class=\"author\">#{@author}</span>"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|