kitabu 2.0.2 → 3.0.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.
Files changed (97) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +4 -0
  3. data/.github/FUNDING.yml +4 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  5. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
  8. data/.github/dependabot.yml +15 -0
  9. data/.github/workflows/ruby-tests.yml +61 -0
  10. data/.gitignore +1 -0
  11. data/.rubocop.yml +17 -0
  12. data/CHANGELOG.md +34 -1
  13. data/CODE_OF_CONDUCT.md +74 -0
  14. data/CONTRIBUTING.md +79 -0
  15. data/Gemfile +2 -0
  16. data/LICENSE.md +20 -0
  17. data/README.md +121 -85
  18. data/Rakefile +7 -0
  19. data/bin/kitabu +4 -0
  20. data/kitabu.gemspec +20 -14
  21. data/lib/kitabu/cli.rb +54 -39
  22. data/lib/kitabu/dependency.rb +11 -5
  23. data/lib/kitabu/errors.rb +2 -0
  24. data/lib/kitabu/exporter/base.rb +13 -11
  25. data/lib/kitabu/exporter/css.rb +6 -14
  26. data/lib/kitabu/exporter/epub.rb +24 -18
  27. data/lib/kitabu/exporter/html.rb +33 -20
  28. data/lib/kitabu/exporter/mobi.rb +7 -1
  29. data/lib/kitabu/exporter/pdf.rb +9 -3
  30. data/lib/kitabu/exporter.rb +15 -16
  31. data/lib/kitabu/extensions/rouge.rb +7 -1
  32. data/lib/kitabu/extensions/string.rb +5 -3
  33. data/lib/kitabu/footnotes/base.rb +2 -0
  34. data/lib/kitabu/footnotes/html.rb +19 -12
  35. data/lib/kitabu/footnotes/pdf.rb +17 -11
  36. data/lib/kitabu/generator.rb +16 -8
  37. data/lib/kitabu/helpers.rb +12 -9
  38. data/lib/kitabu/markdown.rb +12 -10
  39. data/lib/kitabu/source_list.rb +15 -12
  40. data/lib/kitabu/stats.rb +3 -1
  41. data/lib/kitabu/syntax/highlight.rb +4 -11
  42. data/lib/kitabu/toc/epub.rb +5 -2
  43. data/lib/kitabu/toc/html/stream.rb +33 -0
  44. data/lib/kitabu/toc/html.rb +19 -9
  45. data/lib/kitabu/version.rb +4 -2
  46. data/lib/kitabu.rb +11 -12
  47. data/spec/kitabu/cli/export_spec.rb +6 -4
  48. data/spec/kitabu/cli/new_spec.rb +6 -4
  49. data/spec/kitabu/cli/permalinks_spec.rb +4 -2
  50. data/spec/kitabu/cli/stats_spec.rb +19 -15
  51. data/spec/kitabu/cli/version_spec.rb +3 -1
  52. data/spec/kitabu/exporter/css_spec.rb +3 -1
  53. data/spec/kitabu/exporter/epub_spec.rb +2 -0
  54. data/spec/kitabu/exporter/html_spec.rb +17 -4
  55. data/spec/kitabu/exporter/mobi_spec.rb +5 -5
  56. data/spec/kitabu/exporter/pdf_spec.rb +8 -4
  57. data/spec/kitabu/extensions/string_spec.rb +14 -9
  58. data/spec/kitabu/footnotes/html_spec.rb +38 -28
  59. data/spec/kitabu/generator_spec.rb +3 -1
  60. data/spec/kitabu/markdown_spec.rb +15 -3
  61. data/spec/kitabu/source_list_spec.rb +8 -2
  62. data/spec/kitabu/stats_spec.rb +10 -6
  63. data/spec/kitabu/toc/html_spec.rb +55 -35
  64. data/spec/spec_helper.rb +23 -8
  65. data/spec/support/exit_with_code.rb +7 -5
  66. data/spec/support/have_tag.rb +44 -32
  67. data/spec/support/helper.rb +5 -3
  68. data/spec/support/mybook/code/code.rb +2 -0
  69. data/spec/support/mybook/config/helper.rb +2 -0
  70. data/spec/support/mybook/fonts/OpenSans-CondBold.ttf +0 -0
  71. data/spec/support/shared.rb +12 -6
  72. data/templates/Gemfile +5 -3
  73. data/templates/Guardfile +3 -1
  74. data/templates/helper.rb +8 -6
  75. data/templates/templates/styles/epub.css +1 -0
  76. data/templates/templates/styles/files/normalize.css +351 -0
  77. data/templates/templates/styles/{html.scss → html.css} +28 -26
  78. data/templates/templates/styles/{pdf.scss → pdf.css} +49 -47
  79. data/templates/templates/styles/print.css +2 -0
  80. data/templates/text/01_Getting_Started.md +27 -9
  81. data/templates/text/02_Creating_Chapters.md +9 -3
  82. data/templates/text/{03_Syntax_Highlighting.erb → 03_Syntax_Highlighting.md.erb} +12 -7
  83. data/templates/text/04_Dynamic_Content.md.erb +48 -0
  84. data/templates/text/05_Exporting_Files.md +17 -8
  85. metadata +42 -50
  86. data/.gitmodules +0 -3
  87. data/.travis.yml +0 -18
  88. data/Gemfile.lock +0 -108
  89. data/lib/kitabu/exporter/txt.rb +0 -18
  90. data/lib/kitabu/stream.rb +0 -27
  91. data/lib/kitabu/toc.rb +0 -6
  92. data/spec/kitabu/exporter/txt_spec.rb +0 -14
  93. data/templates/ebook.png +0 -0
  94. data/templates/templates/styles/epub.scss +0 -1
  95. data/templates/templates/styles/files/_normalize.scss +0 -427
  96. data/templates/templates/styles/print.scss +0 -2
  97. data/templates/text/04_Dynamic_Content.erb +0 -64
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  class Exporter
3
5
  class Epub < Base
4
6
  def sections
5
- @sections ||= html.css("div.chapter").each_with_index.map do |chapter, index|
6
- OpenStruct.new({
7
- index: index,
8
- filename: "section_#{index}.html",
9
- filepath: tmp_dir.join("section_#{index}.html").to_s,
10
- html: Nokogiri::HTML(chapter.inner_html)
11
- })
12
- end
7
+ @sections ||=
8
+ html.css("div.chapter").each_with_index.map do |chapter, index|
9
+ OpenStruct.new(
10
+ index: index,
11
+ filename: "section_#{index}.html",
12
+ filepath: tmp_dir.join("section_#{index}.html").to_s,
13
+ html: Nokogiri::HTML(chapter.inner_html)
14
+ )
15
+ end
13
16
  end
14
17
 
15
18
  def epub
@@ -34,7 +37,7 @@ module Kitabu
34
37
  epub.save(epub_path)
35
38
 
36
39
  true
37
- rescue Exception => error
40
+ rescue StandardError => error
38
41
  handle_error(error)
39
42
  false
40
43
  end
@@ -54,7 +57,8 @@ module Kitabu
54
57
  epub.publisher config[:publisher]
55
58
  epub.date config[:published_at]
56
59
  epub.uid config[:uid]
57
- epub.identifier config[:identifier][:id], scheme: config[:identifier][:type]
60
+ epub.identifier config[:identifier][:id],
61
+ scheme: config[:identifier][:type]
58
62
  epub.cover_page cover_image if cover_image && File.exist?(cover_image)
59
63
  end
60
64
 
@@ -70,13 +74,11 @@ module Kitabu
70
74
  # First we need to get all ids, which are used as
71
75
  # the anchor target.
72
76
  #
73
- links = sections.inject({}) do |buffer, section|
77
+ links = sections.each_with_object({}) do |section, buffer|
74
78
  section.html.css("[id]").each do |element|
75
- anchor = "##{element["id"]}"
79
+ anchor = "##{element['id']}"
76
80
  buffer[anchor] = "#{section.filename}#{anchor}"
77
81
  end
78
-
79
- buffer
80
82
  end
81
83
 
82
84
  # Then we can normalize all links and
@@ -102,14 +104,16 @@ module Kitabu
102
104
  # Save file to disk.
103
105
  #
104
106
  File.open(section.filepath, "w") do |file|
105
- body = section.html.css("body").to_xhtml.gsub(%r[<body>(.*?)</body>]m, "\\1")
107
+ body = section.html.css("body").to_xhtml.gsub(
108
+ %r{<body>(.*?)</body>}m, "\\1"
109
+ )
106
110
  file << render_chapter(body)
107
111
  end
108
112
  end
109
113
  end
110
114
 
111
115
  def render_chapter(content)
112
- locals = config.merge(:content => content)
116
+ locals = config.merge(content: content)
113
117
  render_template(template_path, locals)
114
118
  end
115
119
 
@@ -122,14 +126,16 @@ module Kitabu
122
126
  end
123
127
 
124
128
  def cover_image
125
- path = Dir[root_dir.join("templates/epub/cover.{jpg,png,gif}").to_s].first
129
+ path =
130
+ Dir[root_dir.join("templates/epub/cover.{jpg,png,gif}").to_s].first
131
+
126
132
  return path if path && File.exist?(path)
127
133
  end
128
134
 
129
135
  def navigation
130
136
  sections.map do |section|
131
137
  {
132
- label: section.html.css("h2:first-of-type").text,
138
+ label: section.html.css(":first-child").text,
133
139
  content: section.filename
134
140
  }
135
141
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  class Exporter
3
5
  class HTML < Base
@@ -13,6 +15,7 @@ module Kitabu
13
15
  #
14
16
  def export
15
17
  copy_images!
18
+ copy_fonts!
16
19
  export_stylesheets!
17
20
 
18
21
  File.open(root_dir.join("output/#{name}.html"), "w") do |file|
@@ -20,7 +23,7 @@ module Kitabu
20
23
  end
21
24
 
22
25
  true
23
- rescue Exception => error
26
+ rescue StandardError => error
24
27
  handle_error(error)
25
28
  false
26
29
  end
@@ -32,28 +35,29 @@ module Kitabu
32
35
  # Return all chapters wrapped in a <tt>div.chapter</tt> tag.
33
36
  #
34
37
  def content
35
- String.new.tap do |content|
38
+ buffer = [].tap do |content|
36
39
  source_list.each_chapter do |files|
37
40
  content << %[<div class="chapter">#{render_chapter(files)}</div>]
38
41
  end
39
42
  end
43
+
44
+ buffer.join
40
45
  end
41
46
 
42
- private
43
47
  # Render +file+ considering its extension.
44
48
  #
45
- def render_file(file)
46
- if format(file) == :erb
47
- content = render_template(file, config)
48
- else
49
- content = File.read(file)
50
- end
49
+ private def render_file(file_path)
50
+ content = if file_format(file_path) == :erb
51
+ render_template(file_path, config)
52
+ else
53
+ File.read(file_path)
54
+ end
51
55
 
52
56
  Kitabu::Markdown.render(content)
53
57
  end
54
58
 
55
- def format(file)
56
- if File.extname(file) == '.erb'
59
+ private def file_format(file_path)
60
+ if File.extname(file_path) == ".erb"
57
61
  :erb
58
62
  else
59
63
  :markdown
@@ -62,15 +66,16 @@ module Kitabu
62
66
 
63
67
  # Parse layout file, making available all configuration entries.
64
68
  #
65
- def parse_layout(html)
69
+ private def parse_layout(html)
66
70
  toc = TOC::HTML.generate(html)
67
- content = Footnotes::HTML.process(toc.content).html.css('body').first.inner_html
71
+ content =
72
+ Footnotes::HTML.process(toc.content).html.css("body").first.inner_html
68
73
 
69
- locals = config.merge({
74
+ locals = config.merge(
70
75
  content: content,
71
76
  toc: toc.to_html,
72
77
  changelog: render_changelog
73
- })
78
+ )
74
79
 
75
80
  render_template(root_dir.join("templates/html/layout.erb"), locals)
76
81
  end
@@ -78,30 +83,38 @@ module Kitabu
78
83
  # Render changelog file.
79
84
  # This file can be used to inform any book change.
80
85
  #
81
- def render_changelog
86
+ private def render_changelog
82
87
  changelog = Dir[root_dir.join("text/CHANGELOG.*")].first
83
88
  render_file(changelog) if changelog
84
89
  end
85
90
 
86
91
  # Render all +files+ from a given chapter.
87
92
  #
88
- def render_chapter(files)
89
- String.new.tap do |chapter|
93
+ private def render_chapter(files)
94
+ buffer = [].tap do |chapter|
90
95
  files.each do |file|
91
96
  chapter << render_file(file) << "\n\n"
92
97
  end
93
98
  end
99
+
100
+ buffer.join
94
101
  end
95
102
 
96
103
  # Copy images
97
104
  #
98
- def copy_images!
105
+ private def copy_images!
99
106
  copy_directory("images", "output/images")
100
107
  end
101
108
 
109
+ # Copy font files
110
+ #
111
+ private def copy_fonts!
112
+ copy_directory("fonts", "output/fonts")
113
+ end
114
+
102
115
  # Export all root stylesheets.
103
116
  #
104
- def export_stylesheets!
117
+ private def export_stylesheets!
105
118
  Exporter::CSS.new(root_dir).export
106
119
  end
107
120
  end
@@ -1,11 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  class Exporter
3
5
  class Mobi < Base
4
6
  def export
5
- spawn_command ["kindlegen", epub_file.to_s]
7
+ spawn_command ["ebook-convert", epub_file.to_s, mobi_file.to_s]
6
8
  true
7
9
  end
8
10
 
11
+ def mobi_file
12
+ root_dir.join("output/#{name}.mobi")
13
+ end
14
+
9
15
  def epub_file
10
16
  root_dir.join("output/#{name}.epub")
11
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  class Exporter
3
5
  class PDF < Base
@@ -9,13 +11,17 @@ module Kitabu
9
11
 
10
12
  def apply_footnotes!
11
13
  html = Footnotes::PDF.process(html_file.read).html
12
- create_html_file(html_for_print, html, 'print')
13
- create_html_file(html_for_pdf, html, 'pdf')
14
+ create_html_file(html_for_print, html, "print")
15
+ create_html_file(html_for_pdf, html, "pdf")
14
16
  end
15
17
 
16
18
  def create_html_file(target, html, class_name)
17
19
  html.css("html").first.set_attribute "class", class_name
18
- html.css("link[name=stylesheet]").first.set_attribute "href", "styles/#{class_name}.css"
20
+ html
21
+ .css("link[name=stylesheet]")
22
+ .first
23
+ .set_attribute "href", "styles/#{class_name}.css"
24
+
19
25
  File.open(target, "w") {|f| f << html.to_html }
20
26
  end
21
27
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  class Exporter
3
5
  def self.run(root_dir, options)
@@ -5,8 +7,7 @@ module Kitabu
5
7
  exporter.export!
6
8
  end
7
9
 
8
- attr_accessor :root_dir
9
- attr_accessor :options
10
+ attr_accessor :root_dir, :options
10
11
 
11
12
  def initialize(root_dir, options)
12
13
  @root_dir = root_dir
@@ -26,37 +27,35 @@ module Kitabu
26
27
  export_pdf = [nil, "pdf"].include?(options[:only])
27
28
  export_epub = [nil, "mobi", "epub"].include?(options[:only])
28
29
  export_mobi = [nil, "mobi"].include?(options[:only])
29
- export_txt = [nil, "txt"].include?(options[:only])
30
30
 
31
31
  exported = []
32
32
  exported << HTML.export(root_dir)
33
33
  exported << PDF.export(root_dir) if export_pdf && Dependency.prince?
34
34
  exported << Epub.export(root_dir) if export_epub
35
- exported << Mobi.export(root_dir) if export_mobi && Dependency.kindlegen?
36
- exported << Txt.export(root_dir) if export_txt && Dependency.html2text?
35
+ exported << Mobi.export(root_dir) if export_mobi && Dependency.calibre?
37
36
 
38
37
  if exported.all?
39
38
  color = :green
40
- message = options[:auto] ? "exported!" : "** e-book has been exported"
39
+ message = options[:auto] ? "exported!" : "=> e-book has been exported"
41
40
 
42
41
  if options[:open] && export_pdf
43
42
  filepath = root_dir.join("output/#{File.basename(root_dir)}.pdf")
44
43
 
45
- if RUBY_PLATFORM =~ /darwin/
44
+ case RUBY_PLATFORM
45
+ when /darwin/
46
46
  IO.popen("open -a Preview.app '#{filepath}'").close
47
- elsif RUBY_PLATFORM =~ /linux/
48
- Process.detach(Process.spawn("xdg-open '#{filepath}'", :out => "/dev/null"))
47
+ when /linux/
48
+ Process.detach(Process.spawn("xdg-open '#{filepath}'",
49
+ out: "/dev/null"))
49
50
  end
50
51
  end
51
-
52
- Notifier.notify(
53
- :image => Kitabu::ROOT.join("templates/ebook.png"),
54
- :title => "Kitabu",
55
- :message => "Your \"#{config[:title]}\" e-book has been exported!"
56
- )
57
52
  else
58
53
  color = :red
59
- message = options[:auto] ? "could not be exported!" : "** e-book couldn't be exported"
54
+ message = if options[:auto]
55
+ "could not be exported!"
56
+ else
57
+ "=> e-book couldn't be exported"
58
+ end
60
59
  end
61
60
 
62
61
  ui.say message, color
@@ -1,8 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rouge
2
4
  module Plugins
3
5
  module Redcarpet
4
6
  def rouge_formatter(lexer)
5
- Formatters::HTML.new({css_class: "highlight #{lexer.tag}"}.merge(lexer.options))
7
+ options = lexer.respond_to?(:options) ? lexer.options : {}
8
+
9
+ Formatters::HTMLLegacy.new(
10
+ {css_class: "highlight #{lexer.tag}"}.merge(options)
11
+ )
6
12
  end
7
13
  end
8
14
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  def to_permalink
3
- str = ActiveSupport::Multibyte::Chars.new(self.dup)
4
- str = str.normalize(:kd).gsub(/[^\x00-\x7F]/,'').to_s
5
- str.gsub!(/[^-\w\d]+/xim, "-")
5
+ str = dup.unicode_normalize(:nfkd)
6
+ str = str.gsub(/[^\x00-\x7F]/, "").to_s
7
+ str.gsub!(/[^-\w]+/xim, "-")
6
8
  str.gsub!(/-+/xm, "-")
7
9
  str.gsub!(/^-?(.*?)-?$/, '\1')
8
10
  str.downcase!
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  module Footnotes
3
5
  class Base
@@ -1,25 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  module Footnotes
3
5
  class HTML < Base
4
6
  def process
5
- html.css('.chapter').each(&method(:process_chapter))
7
+ html.css(".chapter").each(&method(:process_chapter))
6
8
  end
7
9
 
8
10
  def process_chapter(chapter)
9
- footnotes = chapter.css('.footnotes').first
11
+ footnotes = chapter.css(".footnotes").first
10
12
  return unless footnotes
11
- list = footnotes.css('ol').first
12
- list.set_attribute 'start', footnote_index
13
13
 
14
- chapter.css('.footnotes li').each do |footnote|
14
+ list = footnotes.css("ol").first
15
+ list.set_attribute "start", footnote_index
16
+
17
+ chapter.css(".footnotes li").each do |footnote|
15
18
  process_footnote(chapter, footnote)
16
19
  increment_footnote_index!
17
20
  end
18
21
  end
19
22
 
20
23
  def process_footnote(chapter, footnote)
21
- current_index = footnote.get_attribute('id').gsub(/[^\d]/m, '')
22
- footnote.set_attribute 'id', "fn#{footnote_index}"
24
+ current_index = footnote.get_attribute("id").gsub(/[^\d]/m, "")
25
+ footnote.set_attribute "id", "fn#{footnote_index}"
23
26
 
24
27
  process_links_to_footnote(chapter, current_index)
25
28
  process_rev_links(chapter, current_index)
@@ -28,23 +31,27 @@ module Kitabu
28
31
 
29
32
  def process_links_to_footnote(chapter, current_index)
30
33
  chapter.css("a[href='#fn#{current_index}']").each do |link|
31
- link.set_attribute 'href', "#fn#{footnote_index}"
34
+ link.set_attribute "href", "#fn#{footnote_index}"
32
35
  end
33
36
  end
34
37
 
35
38
  def process_rev_links(chapter, current_index)
36
39
  chapter.css("a[href='#fnref#{current_index}']").each do |link|
37
- link.set_attribute 'href', "#fnref#{footnote_index}"
40
+ link.set_attribute "href", "#fnref#{footnote_index}"
38
41
  end
39
42
  end
40
43
 
41
44
  def process_ref_elements(chapter, current_index)
42
- chapter.css("sup[id=fnref#{current_index}]").each_with_index do |sup, index|
45
+ selector = "sup[id=fnref#{current_index}]"
46
+
47
+ chapter.css(selector).each_with_index do |sup, index|
43
48
  if index.zero?
44
- sup.set_attribute 'id', "fnref#{footnote_index}"
49
+ sup.set_attribute "id", "fnref#{footnote_index}"
45
50
  else
46
- sup.remove_attribute 'id'
51
+ sup.remove_attribute "id"
47
52
  end
53
+
54
+ sup.css("a").first.content = footnote_index
48
55
  end
49
56
  end
50
57
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  module Footnotes
3
5
  class PDF < Base
@@ -8,35 +10,39 @@ module Kitabu
8
10
 
9
11
  def remove_duplicated_attributes
10
12
  # https://github.com/sparklemotion/nokogiri/issues/339
11
- html.css('html').first.tap do |element|
13
+ html.css("html").first.tap do |element|
12
14
  next unless element
13
- element.delete('xmlns')
14
- element.delete('xml:lang')
15
+
16
+ element.delete("xmlns")
17
+ element.delete("xml:lang")
15
18
  end
16
19
  end
17
20
 
18
21
  def process_chapter(chapter)
19
- chapter.css('.footnotes li').each do |footnote|
22
+ chapter.css(".footnotes li").each do |footnote|
20
23
  process_footnote(chapter, footnote)
21
24
  increment_footnote_index!
22
25
  end
23
26
 
24
- chapter.css('.footnotes').each(&:remove)
27
+ chapter.css(".footnotes").each(&:remove)
25
28
  end
26
29
 
27
30
  def process_footnote(chapter, footnote)
28
31
  # Remove rev links
29
- footnote.css('[rev=footnote]').map(&:remove)
32
+ footnote.css("[rev=footnote]").map(&:remove)
30
33
 
31
34
  # Create an element for storing the footnote description
32
- description = Nokogiri::XML::Node.new('span', Nokogiri::HTML::DocumentFragment.parse(''))
33
- description.set_attribute 'class', 'footnote'
34
- description.inner_html = footnote.css('p').map(&:inner_html).join("\n")
35
+ description = Nokogiri::XML::Node.new(
36
+ "span",
37
+ Nokogiri::HTML::DocumentFragment.parse("")
38
+ )
39
+ description.set_attribute "class", "footnote"
40
+ description.inner_html = footnote.css("p").map(&:inner_html).join("\n")
35
41
 
36
42
  # Find ref based on footnote's id
37
- fn_id = footnote.get_attribute('id')
43
+ fn_id = footnote.get_attribute("id")
38
44
 
39
- refs = chapter.css("a[href='##{fn_id}']").each do |ref|
45
+ chapter.css("a[href='##{fn_id}']").each do |ref|
40
46
  sup = ref.parent
41
47
  sup.after(description)
42
48
  sup.remove
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  # The Kitabu::Generator class will create a new book structure.
3
5
  #
@@ -11,7 +13,7 @@ module Kitabu
11
13
  desc "Generate a new e-Book structure"
12
14
 
13
15
  def self.source_root
14
- File.dirname(__FILE__) + "/../../templates"
16
+ "#{File.dirname(__FILE__)}/../../templates"
15
17
  end
16
18
 
17
19
  def copy_templates
@@ -43,12 +45,15 @@ module Kitabu
43
45
 
44
46
  def create_directories
45
47
  empty_directory "output"
48
+ empty_directory "fonts"
46
49
  end
47
50
 
48
51
  def create_git_files
49
52
  create_file ".gitignore" do
50
53
  "/output"
51
54
  end
55
+
56
+ create_file "fonts/.keep"
52
57
  end
53
58
 
54
59
  def copy_guardfile
@@ -61,13 +66,16 @@ module Kitabu
61
66
  end
62
67
  end
63
68
 
64
- private
65
- # Retrieve user's name using finger.
66
- # Defaults to <tt>John Doe</tt>.
67
- #
68
- def full_name
69
- name = `finger $USER 2> /dev/null | grep Login | colrm 1 46 2> /dev/null`.chomp
70
- name.present? ? name.squish : "John Doe"
69
+ no_commands do
70
+ # Retrieve user's name using finger.
71
+ # Defaults to <tt>John Doe</tt>.
72
+ #
73
+ def full_name
74
+ name =
75
+ `finger $USER 2> /dev/null | grep Login | colrm 1 46 2> /dev/null`
76
+ .chomp
77
+ name.present? ? name.squish : "John Doe"
78
+ end
71
79
  end
72
80
  end
73
81
  end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: false
2
+
1
3
  module Kitabu
2
4
  module Helpers
3
5
  def highlight_theme(name = theme)
4
6
  html = '<style type="text/css">'
5
- html << Rouge::Theme.find(name).render(scope: '.highlight')
6
- html << '</style>'
7
+ html << Rouge::Theme.find(name).render(scope: ".highlight")
8
+ html << "</style>"
7
9
  html
8
10
  end
9
11
 
10
- def image_tag(path, attributes = {})
11
- html = %[<img src="images/#{path}" />]
12
+ def image_tag(path, _attributes = {})
13
+ %[<img src="images/#{path}" />]
12
14
  end
13
15
 
14
16
  def escape_html(content)
@@ -17,19 +19,20 @@ module Kitabu
17
19
 
18
20
  def note(class_name = :info, &block)
19
21
  content = block_content(block)
20
- output << '<div class="note %s">' % escape_html(class_name)
22
+ output << ('<div class="note %s">' % escape_html(class_name)) # rubocop:disable Style/FormatString
21
23
  output << markdown(content)
22
- output << '</div>'
24
+ output << "</div>"
23
25
  end
24
26
 
25
27
  def block_content(block)
26
- output, @_output = @_output.dup, ''
28
+ output = @_output.dup
29
+ @_output = ""
27
30
  content = block.call
28
31
  @_output = output
29
32
  content
30
33
  end
31
34
 
32
- def markdown(content, deindent_content = true)
35
+ def markdown(content, deindent_content: true)
33
36
  content = deindent(content) if deindent_content
34
37
  Markdown.render(content)
35
38
  end
@@ -37,7 +40,7 @@ module Kitabu
37
40
  def deindent(content)
38
41
  content = content.to_s
39
42
  indent = (content.scan(/^[ \t]*(?=\S)/) || []).size
40
- content.gsub(/^[ \t]{#{indent}}/, '')
43
+ content.gsub(/^[ \t]{#{indent}}/, "")
41
44
  end
42
45
 
43
46
  def output
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kitabu
2
4
  module Markdown
3
5
  class Renderer < Redcarpet::Render::HTML
@@ -13,16 +15,16 @@ module Kitabu
13
15
  renderer = Renderer.new(hard_wrap: true, safe_links_only: true)
14
16
 
15
17
  self.processor = Redcarpet::Markdown.new(renderer, {
16
- tables: true,
17
- footnotes: true,
18
- space_after_headers: true,
19
- superscript: true,
20
- highlight: true,
21
- strikethrough: true,
22
- autolink: true,
23
- fenced_code_blocks: true,
24
- no_intra_emphasis: true
25
- })
18
+ tables: true,
19
+ footnotes: true,
20
+ space_after_headers: true,
21
+ superscript: true,
22
+ highlight: true,
23
+ strikethrough: true,
24
+ autolink: true,
25
+ fenced_code_blocks: true,
26
+ no_intra_emphasis: true
27
+ })
26
28
 
27
29
  def self.render(text)
28
30
  processor.render(text)