markita 4.1.230214 → 6.0.250327

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +194 -237
  3. data/bin/markita +16 -19
  4. data/lib/markita/base.rb +37 -38
  5. data/lib/markita/config.rb +41 -10
  6. data/lib/markita/html.rb +35 -20
  7. data/lib/markita/markdown/attributes.rb +23 -0
  8. data/lib/markita/markdown/blockquote.rb +41 -0
  9. data/lib/markita/markdown/code.rb +44 -0
  10. data/lib/markita/markdown/code_block.rb +29 -0
  11. data/lib/markita/markdown/definitions.rb +42 -0
  12. data/lib/markita/markdown/embed.rb +63 -0
  13. data/lib/markita/markdown/empty.rb +22 -0
  14. data/lib/markita/markdown/fold.rb +39 -0
  15. data/lib/markita/markdown/footnotes.rb +28 -0
  16. data/lib/markita/markdown/form.rb +125 -0
  17. data/lib/markita/markdown/heading.rb +33 -0
  18. data/lib/markita/markdown/horizontal_rule.rb +25 -0
  19. data/lib/markita/markdown/image.rb +60 -0
  20. data/lib/markita/markdown/inline.rb +123 -0
  21. data/lib/markita/markdown/list.rb +65 -0
  22. data/lib/markita/markdown/markup.rb +23 -0
  23. data/lib/markita/markdown/script.rb +28 -0
  24. data/lib/markita/markdown/split.rb +38 -0
  25. data/lib/markita/markdown/table.rb +52 -0
  26. data/lib/markita/markdown.rb +51 -498
  27. data/lib/markita/plug/about.rb +28 -17
  28. data/lib/markita/plug/favicon.rb +14 -10
  29. data/lib/markita/plug/highlight.rb +18 -12
  30. data/lib/markita/plug/login.rb +35 -28
  31. data/lib/markita/plug/navigation.rb +4 -1
  32. data/lib/markita/plug/plugs.rb +7 -1
  33. data/lib/markita/plug/readme.rb +8 -4
  34. data/lib/markita/preprocess.rb +52 -23
  35. data/lib/markita/refinement.rb +21 -0
  36. data/lib/markita/requires.rb +29 -0
  37. data/lib/markita.rb +15 -24
  38. metadata +52 -116
@@ -1,521 +1,74 @@
1
- module Markita
2
- class Markdown
3
- ROUGE = Rouge::Formatters::HTML.new
4
- PARSERS = []
5
-
6
- def initialize(title)
7
- @title = title
8
- @line=@html=@file=@opt=nil
9
- @metadata = {}
10
- end
11
-
12
- def start
13
- @html << HTML.header(@title)
14
- @line = HTML.navigation
15
- end
16
-
17
- def finish
18
- if (title=@metadata['Title'])
19
- @html << %(<script> document.title = "#{title}" </script>\n)
20
- end
21
- @html << HTML.footer
22
- @line = nil
23
- end
24
-
25
- def default
26
- @html << @line
27
- @line = @file.gets
28
- end
29
-
30
- def init(fh)
31
- @file,@html,@opt = Preprocess.new(fh),'',{}
32
- end
33
-
34
- def parse(fh)
35
- init(fh)
36
- start
37
- PARSERS.detect{method(_1).call} or default while @line
38
- finish
39
- end
40
-
41
- def markdown(string)
42
- parse StringIO.new string
43
- @html
44
- end
45
-
46
- def filepath(filepath)
47
- File.open(filepath, 'r'){|fh| parse fh}
48
- @html
49
- end
50
-
51
- Ux = /_([^_]+)_/
52
- U = ->(m){"<u>#{m[1]}</u>"}
53
-
54
- Sx = /~([^~]+)~/
55
- S = ->(m){"<s>#{m[1]}</s>"}
56
-
57
- Ix = /"([^"]+)"/
58
- I = ->(m){"<i>#{m[1]}</i>"}
59
-
60
- Bx = /\*([^*]+)\*/
61
- B = ->(m){"<b>#{m[1]}</b>"}
62
-
63
- CODEx = /`([^`]+)`/
64
- CODE = ->(m){"<code>#{m[1].gsub('<','&lt;')}</code>"}
65
-
66
- Ax = /\[([^\[\]]+)\]\(([^()]+)\)/
67
- def anchor(m)
68
- href = ((_=m[2]).match?(/^\d+$/) and @metadata[_] or _)
69
- text = Markdown.tag(m[1], EMOJIx, EMOJI)
70
- %(<a href="#{href}">#{text}</a>)
71
- end
72
-
73
- URLx = %r{(https?://[\w./&+?%-]+)}
74
- URL = ->(m){%(<a href="#{m[1]}">#{m[1]}</a>)}
75
-
76
- EMOJIx = /:(\w+):/
77
- EMOJI = ->(m){(_=EMOJIS[m[1]])? "&#x#{_};" : m[0]}
78
-
79
- FOOTNOTEx = /\[\^(\d+)\](:)?/
80
- FOOTNOTE = lambda do |m|
81
- if m[2]
82
- %(<a id="fn:#{m[1]}" href="#fnref:#{m[1]}">#{m[1]}:</a>)
83
- else
84
- %(<a id="fnref:#{m[1]}" href="#fn:#{m[1]}"><sup>#{m[1]}</sup></a>)
85
- end
86
- end
87
-
88
- def self.tag(entry, regx, m2string, &block)
89
- if (m=regx.match entry)
90
- string = ''
91
- while m
92
- pre_match = (block ? block.call(m.pre_match) : m.pre_match)
93
- string << pre_match + m2string[m]
94
- post_match = m.post_match
95
- m = regx.match(post_match)
96
- end
97
- string << (block ? block.call(post_match) : post_match)
98
- return string
99
- end
100
- block ? block.call(entry) : entry
101
- end
102
-
103
- def inline(entry)
104
- string = Markdown.tag(entry, CODEx, CODE) do |entry|
105
- Markdown.tag(entry, Ax, method(:anchor)) do |entry|
106
- Markdown.tag(entry, URLx, URL) do |entry|
107
- entry = Markdown.tag(entry, EMOJIx, EMOJI)
108
- entry = Markdown.tag(entry, Bx, B)
109
- entry = Markdown.tag(entry, Ix, I)
110
- entry = Markdown.tag(entry, Sx, S)
111
- entry = Markdown.tag(entry, Ux, U)
112
- Markdown.tag(entry, FOOTNOTEx, FOOTNOTE)
113
- end
114
- end
115
- end
116
- string.sub(/ $/,'<br>')
117
- end
118
-
119
- # Empty
120
- EMPTY = /^$/
121
- PARSERS << :empty
122
- def empty
123
- EMPTY.match?(@line) or return false
124
- @line = @file.gets
125
- true
126
- end
127
-
128
- # Ordered list
129
- ORDERED = /^( {0,3})\d+\. (\S.*)$/
130
- PARSERS << :ordered
131
- def ordered(md=nil)
132
- md ||= ORDERED.match(@line) or return false
133
- level = md[1].length
134
- @html << "<ol#{@opt[:attributes]}>\n"
135
- @opt.delete(:attributes)
136
- while md && level==md[1].length
137
- @html << " <li>#{inline(md[2])}</li>\n"
138
- next unless (md=(@line=@file.gets)&.match ORDERED) && level<md[1].length
139
- ordered(md)
140
- md = @line&.match(ORDERED)
141
- end
142
- @html << "</ol>\n"
143
- true
144
- end
1
+ # frozen_string_literal: true
145
2
 
146
- # Paragraph
147
- PARAGRAPHS = /^[\[(*`'"~_]?:?\w/
148
- PARSERS << :paragraphs
149
- def paragraphs
150
- md = PARAGRAPHS.match(@line) or return false
151
- @html << "<p#{@opt[:attributes]}>\n"
152
- @opt.delete(:attributes)
153
- while md
154
- @html << inline(@line)
155
- while (@line=@file.gets)&.start_with?('<')
156
- @html << @line # Exceptional HTML injection into the paragraph
157
- end
158
- md = @line&.match PARAGRAPHS
159
- end
160
- @html << "</p>\n"
161
- true
162
- end
3
+ # Markita top level namespace
4
+ module Markita
5
+ # The markdown parser.
6
+ # :reek:ClassVariable :reek:TooManyInstanceVariables
7
+ # rubocop:disable Style/ClassVars
8
+ class Markdown
9
+ ROUGE = Rouge::Formatters::HTML.new
163
10
 
164
- # Unordered list
165
- UNORDERED = /^( {0,3})[*] (\S.*)$/
166
- PARSERS << :unordered
167
- def unordered(md=nil)
168
- md ||= UNORDERED.match(@line) or return false
169
- level = md[1].length
170
- @html << "<ul#{@opt[:attributes]}>\n"
171
- @opt.delete(:attributes)
172
- while md && level==md[1].length
173
- @html << " <li>#{inline(md[2])}</li>\n"
174
- next unless (md=(@line=@file.gets)&.match UNORDERED) && level<md[1].length
175
- unordered(md)
176
- md = @line&.match(UNORDERED)
177
- end
178
- @html << "</ul>\n"
179
- true
180
- end
11
+ @@parsers = []
181
12
 
182
- # Ballot box
183
- BALLOTS = /^- \[(x| )\] (.*)$/
184
- PARSERS << :ballots
185
- def ballots
186
- md = BALLOTS.match(@line) or return false
187
- @html << "<ul#{@opt[:attributes]}>\n"
188
- @opt.delete(:attributes)
189
- while md
190
- x,t = md[1],md[2]
191
- li = x=='x' ?
192
- %q(<li style="list-style-type: '&#9745; '">) :
193
- %q(<li style="list-style-type: '&#9744; '">)
194
- @html << " #{li}#{inline(t)}</li>\n"
195
- md = (@line=@file.gets)&.match BALLOTS
13
+ def initialize(title)
14
+ @title = title
15
+ @line = @html = @line_getter = nil
16
+ @metadata = {}
17
+ @attributes = []
196
18
  end
197
- @html << "</ul>\n"
198
- true
199
- end
200
19
 
201
- # Definition list
202
- DEFINITIONS = /^[+] (.*)$/
203
- PARSERS << :definitions
204
- def definitions
205
- md = DEFINITIONS.match(@line) or return false
206
- @html << "<dl#{@opt[:attributes]}>\n"
207
- @opt.delete(:attributes)
208
- while md
209
- case md[1]
210
- when /(.*): (.*)$/
211
- @html << "<dt>#{inline $1.strip}</dt>\n"
212
- @html << "<dd>#{inline $2.strip}</dd>\n"
213
- when /(.*):$/
214
- @html << "<dt>#{inline $1.strip}</dt>\n"
215
- else
216
- @html << "<dd>#{inline md[1].strip}</dd>\n"
20
+ def finish
21
+ if (title = @metadata['Title'])
22
+ @html << %(<script> document.title = "#{title}" </script>\n)
217
23
  end
218
- md = (@line=@file.gets)&.match DEFINITIONS
24
+ @html << Html.footer
25
+ @line = nil
219
26
  end
220
- @html << "</dl>\n"
221
- true
222
- end
223
27
 
224
- # Headers
225
- HEADERS = /^(\#{1,6}) (.*)$/
226
- PARSERS << :headers
227
- def headers
228
- md = HEADERS.match(@line) or return false
229
- i,header = md[1].length,md[2]
230
- id = header.gsub(/\([^()]*\)/,'').scan(/\w+/).join('+')
231
- @html << %(<a id="#{id}">\n)
232
- @html << " <h#{i}#{@opt[:attributes]}>#{inline(header)}</h#{i}>\n"
233
- @html << "</a>\n"
234
- @opt.delete(:attributes)
235
- @line = @file.gets
236
- true
237
- end
238
-
239
- # Block-quote
240
- BLOCKQS = /^( {0,3})> (.*)$/
241
- PARSERS << :blockqs
242
- def blockqs(md=nil)
243
- md ||= BLOCKQS.match(@line) or return false
244
- level = md[1].length
245
- @html << "<blockquote#{@opt[:attributes]}>\n"
246
- @opt.delete(:attributes)
247
- while md && level==md[1].length
248
- @html << inline(md[2])
249
- @html << "\n"
250
- next unless (md=(@line=@file.gets)&.match BLOCKQS) && level<md[1].length
251
- blockqs(md)
252
- md = @line&.match(BLOCKQS)
28
+ # init(fh: String || File) -> void
29
+ def init(line_getter)
30
+ @line_getter = Preprocess.new(line_getter)
31
+ @html = String.new
253
32
  end
254
- @html << "</blockquote>\n"
255
- true
256
- end
257
33
 
258
- # Code
259
- CODES = /^[`~]{3}\s*(\w+)?$/
260
- PARSERS << :codes
261
- def codes
262
- md = CODES.match(@line) or return false
263
- lang = Rouge::Lexer.find md[1]
264
- klass = lang ? ' class="highlight"' : nil
265
- @html << "<pre#{klass}#{@opt[:attributes]}><code>\n"
266
- @opt.delete(:attributes)
267
- code = ''
268
- code << @line while (@line=@file.gets) && !CODES.match?(@line)
269
- @html << (lang ? ROUGE.format(lang.new.lex(code)) : code)
270
- @html << "</code></pre>\n"
271
- @line = @file.gets if @line # then it's code close and thus need next @line.
272
- true
273
- end
274
-
275
- # Script
276
- SCRIPT = /^<script/
277
- PARSERS << :script
278
- def script
279
- SCRIPT.match(@line) or return false
280
- @html << @line
281
- while (@line=@file.gets)
282
- @html << @line
283
- break if %r{^</script>}.match?(@line)
34
+ def start
35
+ @html << Html.header(@title)
36
+ @line = Html.navigation
284
37
  end
285
- @line = @file.gets if @line
286
- true
287
- end
288
38
 
289
- # Preform
290
- PREFORMS = /^ {4}(.*)$/
291
- PARSERS << :preforms
292
- def preforms
293
- md = PREFORMS.match(@line) or return false
294
- @html << "<pre#{@opt[:attributes]}>\n"
295
- @opt.delete(:attributes)
296
- while md
297
- @html << md[1]
298
- @html << "\n"
299
- md = (@line=@file.gets)&.match PREFORMS
39
+ def parse(line_getter)
40
+ init(line_getter)
41
+ start
42
+ parsers_detect or default while @line
43
+ finish
300
44
  end
301
- @html << "</pre>\n"
302
- true
303
- end
304
45
 
305
- # Meta-data
306
- METADATAS = /^(\w+): (.*)$/
307
- def metadata
308
- md = METADATAS.match(@line) or return false
309
- while md
310
- @metadata[md[1]] = md[2]
311
- md = (@line=@file.gets)&.match METADATAS
46
+ def filepath(filepath)
47
+ File.open(filepath, 'r') { parse it }
48
+ @html
312
49
  end
313
- true
314
- end
315
50
 
316
- # Horizontal rule or Meta-data
317
- HRS = /^---+$/
318
- PARSERS << :hrs
319
- def hrs
320
- HRS.match? @line or return false
321
- @line = @file.gets
322
- if metadata
323
- # Optional closing HRS
324
- @line = @file.gets if @line&.match? HRS
325
- else
326
- # Display HR
327
- @html << "<hr#{@opt[:attributes]}>\n"
328
- @opt.delete(:attributes)
51
+ def markdown(string)
52
+ parse StringIO.new string
53
+ @html
329
54
  end
330
- true
331
- end
332
55
 
333
- # Table
334
- TABLES = /^\|.+\|$/
335
- PARSERS << :tables
336
- def tables
337
- TABLES.match? @line or return false
338
- @html << "<table#{@opt[:attributes]}>\n"
339
- @opt.delete(:attributes)
340
- @html << '<thead><tr><th>'
341
- @html << @line[1...-1].split('|').map{inline(_1.strip)}.join('</th><th>')
342
- @html << "</th></tr></thead>\n"
343
- align = []
344
- while (@line=@file.gets)&.match? TABLES
345
- @html << '<tr>'
346
- @line[1...-1].split('|').each_with_index do |cell, i|
347
- case cell
348
- when /^\s*:-+:\s*$/
349
- align[i] = ' align="center"'
350
- @html << '<td><hr></td>'
351
- when /^\s*-+:\s*$/
352
- align[i] = ' align="right"'
353
- @html << '<td><hr></td>'
354
- when /^\s*:-+\s*$/
355
- align[i] = ' align="left"'
356
- @html << '<td><hr></td>'
357
- else
358
- @html << "<td#{align[i]}>#{inline(cell.strip)}</td>"
359
- end
360
- end
361
- @html << "</tr>\n"
362
- end
363
- @html << "</table>\n"
364
- true
365
- end
366
-
367
- # Splits
368
- SPLITS = /^:?\|:?$/
369
- PARSERS << :splits
370
- def splits
371
- SPLITS.match? @line or return false
372
- case @line.chomp
373
- when '|:'
374
- @html << %(<table><tr><td#{@opt[:attributes]}>\n)
375
- when '|'
376
- @html << %(</td><td#{@opt[:attributes]}>\n)
377
- when ':|:'
378
- @html << %(</td></tr><tr><td#{@opt[:attributes]}>\n)
379
- when ':|'
380
- @html << %(</td></tr></table>\n)
381
- end
382
- @opt.delete(:attributes)
383
- @line = @file.gets
384
- true
385
- end
386
-
387
- # Image
388
- IMAGES = /^!\[([^\[\]]+)\]\(([^()]+)\)$/
389
- PARSERS << :images
390
- def images
391
- md = IMAGES.match(@line) or return false
392
- alt,src,href=md[1],*md[2].strip.split(/\s+/,2)
393
- style = ' '
394
- case alt
395
- when /^:.*:$/
396
- style =
397
- %( style="display: block; margin-left: auto; margin-right: auto;" )
398
- when /:$/
399
- style = %( style="float:left;" )
400
- when /^:/
401
- style = %( style="float:right;" )
402
- end
403
- if /(\d+)x(\d+)/.match alt
404
- style << %(width="#{$1}" height="#{$2}" )
405
- end
406
- @html << %(<a href="#{href}">\n) if href
407
- @html <<
408
- %(<img src="#{src}"#{style}alt="#{alt.strip}"#{@opt[:attributes]}>\n)
409
- @html << %(</a>\n) if href
410
- @opt.delete(:attributes)
411
- @line = @file.gets
412
- true
413
- end
414
-
415
- # Forms
416
- FIELD = '(\w+:)?\[(\*)?(\w+)(=("[^"]+")(,"[^"]+")*)?\]'
417
- FIELDS = Regexp.new FIELD
418
- FORMS = Regexp.new "^!( #{FIELD})+"
419
- PARSERS << :forms
420
- def forms
421
- md = FORMS.match(@line) or return false
422
- fields,nl,submit = 0,false,nil
423
- action = (_=/\(([^()]*)\)!?$/.match(@line))? %( action="#{_[1]}") : nil
424
- method = @line.match?(/!$/) ? ' method="post"' : nil
425
- @html << %(<form#{action}#{method}#{@opt[:attributes]}>\n)
426
- @opt.delete(:attributes)
427
- while md
428
- @html << " <br>\n" if nl
429
- @line.scan(FIELDS).each do |field, pwd, name, value|
430
- field &&= field[0...-1]
431
- value &&= value[2...-1]
432
- if field
433
- type = pwd ? 'password' : 'text'
434
- if value
435
- if (values = value.split('","')).length > 1
436
- @html << %(#{field}:<select name="#{name}">\n)
437
- values.each do |value|
438
- fields += 1
439
- @html << %( <option value="#{value}">#{value}</option>\n)
440
- end
441
- @html << "</select>\n"
442
- else
443
- fields += 1
444
- @html << %( #{field}:<input type="#{type}" name="#{name}")
445
- @html << %( value="#{value}">\n)
446
- end
447
- else
448
- fields += 1
449
- @html << %( #{field}:<input type="#{type}" name="#{name}">\n)
450
- end
451
- elsif name=='submit'
452
- submit = value
453
- else
454
- @html << %( <input type="hidden" name="#{name}" value="#{value}">\n)
455
- end
456
- end
457
- md=(@line=@file.gets)&.match(FORMS) and nl=true
458
- end
459
- if submit || fields!=1
460
- submit ||= 'Submit'
461
- @html << " <br>\n" if nl
462
- @html << %( <input type="submit" value="#{submit}">\n)
463
- end
464
- @html << %(</form>\n)
465
- true
466
- end
467
-
468
- # Embed text
469
- EMBED_TEXTS = /^!> (#{PAGE_KEY}\.\w+)$/
470
- PARSERS << :embed_texts
471
- def embed_texts
472
- md = EMBED_TEXTS.match(@line) or return false
473
- if File.exist?(filename=File.join(ROOT, md[1]))
474
- extension,lang = filename.split('.').last,nil
475
- unless extension=='html'
476
- lang = Rouge::Lexer.find(extension) unless extension=='txt'
477
- klass = lang ? ' class="highlight"' : nil
478
- @html << "<pre#{klass}#{@opt[:attributes]}>"
479
- @opt.delete(:attributes)
480
- @html << '<code>' if lang
481
- @html << "\n"
482
- end
483
- code = File.read(filename)
484
- @html << (lang ? ROUGE.format(lang.new.lex(code)) : code)
485
- unless extension=='html'
486
- @html << '</code>' if lang
487
- @html << '</pre>'
488
- @html << "\n"
489
- end
490
- else
491
- @html << @line
492
- end
493
- @line = @file.gets
494
- true
495
- end
56
+ def parsers_detect = @@parsers.detect { method(it).call }
496
57
 
497
- # Footnotes
498
- FOOTNOTES = /^\[\^\d+\]:/
499
- PARSERS << :footnotes
500
- def footnotes
501
- md = FOOTNOTES.match(@line) or return false
502
- @html << "<small>\n"
503
- while md
504
- @html << inline(@line.chomp)+"<br>\n"
505
- md = (@line=@file.gets)&.match FOOTNOTES
58
+ # Defaults to paragraph
59
+ # :reek:DuplicateMethodCall :reek:TooManyStatements
60
+ def default
61
+ # Let html take the original @html String and set @html to String.new('')
62
+ html = @html
63
+ @html = String.new
64
+ html << "<p#{@attributes.shift}>\n"
65
+ html << inline(@line)
66
+ html << inline(@line) while line_gets && !parsers_detect
67
+ html << "</p>\n#{@html}"
68
+ @html = html # Give back the original String to @html
506
69
  end
507
- @html << "</small>\n"
508
- true
509
- end
510
70
 
511
- # Attributes
512
- ATTRIBUTES = /^\{:( .*)\}/
513
- PARSERS << :attributes
514
- def attributes
515
- md = ATTRIBUTES.match(@line) or return false
516
- @opt[:attributes] = md[1]
517
- @line = md.post_match
518
- true
71
+ def line_gets = @line = @line_getter.gets
519
72
  end
520
- end
73
+ # rubocop:enable Style/ClassVars
521
74
  end
@@ -1,33 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Markita namespace
1
4
  module Markita
2
- class Base
3
- module About
4
- def self.page
5
- text = <<~TEXT
5
+ # Base class of the Sinatra Markita application
6
+ class Base
7
+ # About namespace to support the /about.html route
8
+ module About
9
+ ABOUT_TEXT = <<~TEXT.freeze
6
10
  # [Markita](https://github.com/carlosjhr64/markita)
7
11
 
8
12
  * VERSION: #{VERSION}
9
- * ROOT: #{ROOT.sub(%r{^/home/\w+/},'~/')}
13
+ * ROOT: #{ROOT.sub(%r{^/home/\w+/}, '~/')}
10
14
  * ARGV: #{ARGV.join(' ')}
11
15
  * START_TIME: #{START_TIME}
12
16
 
13
17
  ## Plug.html routes:
14
18
 
15
19
  TEXT
16
- Base.routes['GET'].each do |route|
17
- path = route[0].to_s
18
- next unless %r{^/\w+\.html$}.match? path
19
- basename = File.basename(path, '.*')
20
- text << "* [#{basename}](#{path})\n"
20
+
21
+ def self.plugs
22
+ Base.routes['GET'].each do |route|
23
+ path = route[0].to_s
24
+ next unless %r{^/\w+\.html$}.match? path
25
+
26
+ yield path, File.basename(path, '.*')
27
+ end
21
28
  end
22
- if defined? Favicon && Favicon::ICO
23
- text << "\n![Favicon](/favicon.ico)\n"
29
+
30
+ def self.page
31
+ text = ABOUT_TEXT.dup
32
+ plugs { |path, basename| text << "* [#{basename}](#{path})\n" }
33
+ if defined? Favicon && Favicon::ICO
34
+ text << "\n![Favicon](/favicon.ico)\n"
35
+ end
36
+ text
24
37
  end
25
- text
26
38
  end
27
- end
28
39
 
29
- get '/about.html' do
30
- Markdown.new('About').markdown About.page
40
+ get '/about.html' do
41
+ Markdown.new('About').markdown About.page
42
+ end
31
43
  end
32
44
  end
33
- end
@@ -1,15 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Markita namespace
1
4
  module Markita
2
- class Base
3
- HEADER_LINKS <<
4
- %( <link rel="icon" type="image/x-icon" href="/favicon.ico">\n)
5
+ Html.header_links <<
6
+ %(<link rel="icon" type="image/x-icon" href="/favicon.ico">\n)
5
7
 
6
- module Favicon
7
- ICO = File.read PATH['favicon.ico']
8
- end
8
+ # Base class of the Sinatra Markita application
9
+ class Base
10
+ module Favicon
11
+ ICO = File.read PATH['favicon.ico']
12
+ end
9
13
 
10
- get '/favicon.ico' do
11
- headers 'Content-Type' => 'image/x-icon'
12
- Favicon::ICO
14
+ get '/favicon.ico' do
15
+ headers 'Content-Type' => 'image/x-icon'
16
+ Favicon::ICO
17
+ end
13
18
  end
14
19
  end
15
- end