softcover 0.8.9 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/softcover/book_manifest.rb +17 -5
  3. data/lib/softcover/builder.rb +29 -1
  4. data/lib/softcover/builders/epub.rb +5 -11
  5. data/lib/softcover/builders/html.rb +5 -3
  6. data/lib/softcover/builders/mobi.rb +6 -13
  7. data/lib/softcover/builders/pdf.rb +23 -4
  8. data/lib/softcover/builders/preview.rb +1 -3
  9. data/lib/softcover/cli.rb +24 -3
  10. data/lib/softcover/commands/build.rb +29 -6
  11. data/lib/softcover/commands/check.rb +103 -0
  12. data/lib/softcover/commands/deployment.rb +0 -7
  13. data/lib/softcover/commands/epub_validator.rb +2 -8
  14. data/lib/softcover/sanitizer.rb +5 -1
  15. data/lib/softcover/template/.softcover-build +6 -0
  16. data/lib/softcover/template/chapters/a_chapter.md +10 -11
  17. data/lib/softcover/template/chapters/a_chapter.tex +13 -21
  18. data/lib/softcover/template/chapters/another_chapter.md +3 -1
  19. data/lib/softcover/template/config/lang.yml +14 -0
  20. data/lib/softcover/template/config/preamble.tex +8 -0
  21. data/lib/softcover/template/epub/OEBPS/styles/custom_epub.css +7 -0
  22. data/lib/softcover/template/images/cover-web.png +0 -0
  23. data/lib/softcover/template/images/cover.pdf +0 -0
  24. data/lib/softcover/template/images/cover.png +0 -0
  25. data/lib/softcover/template/latex_styles/custom_pdf.sty +6 -4
  26. data/lib/softcover/template/latex_styles/language_customization.sty +11 -0
  27. data/lib/softcover/template/latex_styles/softcover.sty +10 -7
  28. data/lib/softcover/utils.rb +65 -6
  29. data/lib/softcover/version.rb +1 -1
  30. data/lib/softcover.rb +1 -0
  31. data/softcover.gemspec +10 -10
  32. data/spec/builders/mobi_spec.rb +5 -3
  33. data/spec/builders/pdf_spec.rb +19 -0
  34. data/spec/cli_spec.rb +27 -0
  35. data/spec/commands/build_spec.rb +9 -0
  36. data/spec/commands/check_spec.rb +57 -0
  37. metadata +49 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e236dc06258cb83e779007f53868d7e11a1fe12
4
- data.tar.gz: 4e9cf4fd4ee6a1a03beb796004522e4cb20dce10
3
+ metadata.gz: 5cde257d853b87404d19decb7190ed774b6f68c2
4
+ data.tar.gz: 4a22997a284fa6f364c61aeee24344942a485a94
5
5
  SHA512:
6
- metadata.gz: 1c0f5758cbbd305ea9b0f76a7939be1d39cbba9729d8cd5626a33c844c92415e59839d81d2442ee14d649c5e2a0b102e1dee4321fff671a9eb55b459627387ab
7
- data.tar.gz: 03f7a45f12d7905abdf0f78ace0330eece59d948dcaaeb1841ab72a0018cfd390c0f8010d6cbe59775584ee34656558e432cadc086d3c7a91d186fd15c5f0e7e
6
+ metadata.gz: 2b5aacf11aa98f5bf6683574c138a51bb9e3b39c205001f628d5a10a82831eca40c8505561e559d7c4292f7b60cb362d95fb1d81f2e1e3495ee73b7bb4e697ae
7
+ data.tar.gz: 2d56e4ec07a2eb1c4e70bdd6cfc3349d989b813fb0d950d8e6a6cb7a87876d89dbdefc0feada9ce5b37282ca3da99cbc7753b80dacd11b4daf12dddec73e650b
@@ -35,9 +35,15 @@ class Softcover::BookManifest < OpenStruct
35
35
 
36
36
  # Returns a chapter heading for use in the navigation menu.
37
37
  def menu_heading
38
- raw_html = Polytexnic::Pipeline.new(title).to_html
38
+ raw_html = Polytexnic::Pipeline.new(title,
39
+ language_labels: language_labels).
40
+ to_html
39
41
  html = Nokogiri::HTML(raw_html).at_css('p').inner_html
40
- chapter_number.zero? ? html : "Chapter #{chapter_number}: #{html}"
42
+ if chapter_number.zero?
43
+ html
44
+ else
45
+ "#{chapter_label(chapter_number)}: #{html}"
46
+ end
41
47
  end
42
48
 
43
49
  def to_hash
@@ -103,7 +109,7 @@ class Softcover::BookManifest < OpenStruct
103
109
  if base_contents.match(/frontmatter/)
104
110
  @frontmatter = true
105
111
  chapters.push Chapter.new(slug: 'frontmatter',
106
- title: 'Frontmatter',
112
+ title: language_labels["frontmatter"],
107
113
  sections: nil,
108
114
  chapter_number: 0)
109
115
  end
@@ -139,7 +145,11 @@ class Softcover::BookManifest < OpenStruct
139
145
  template_dir = File.join(File.dirname(__FILE__), 'template')
140
146
  files = [File.join(Softcover::Directories::CONFIG, 'marketing.yml'),
141
147
  path('images/cover-web.png'),
142
- path('latex_styles/custom_pdf.sty')]
148
+ path('latex_styles/custom_pdf.sty'),
149
+ path('config/preamble.tex'),
150
+ path('config/lang.yml'),
151
+ path('epub/OEBPS/styles/custom_epub.css')
152
+ ]
143
153
  files.each do |file|
144
154
  unless File.exist?(file)
145
155
  puts "Copying missing file '#{file}' from template"
@@ -346,7 +356,9 @@ class Softcover::BookManifest < OpenStruct
346
356
  chapter_file_paths do |chapter_path|
347
357
  next if chapter_path =~ /frontmatter/
348
358
  unless File.exist?(chapter_path)
349
- raise "Chapter file in manifest not found in #{chapter_path}"
359
+ $stderr.puts "ERROR -- document not built"
360
+ $stderr.puts "Chapter file '#{chapter_path}'' not found"
361
+ exit 1
350
362
  end
351
363
  end
352
364
  end
@@ -10,6 +10,7 @@ module Softcover
10
10
  @built_files = []
11
11
  ensure_style_file_locations
12
12
  write_polytexnic_commands_file
13
+ write_language_customization_file
13
14
  end
14
15
 
15
16
  def build!(options={})
@@ -51,8 +52,35 @@ module Softcover
51
52
 
52
53
  # Writes out the PolyTeXnic commands from polytexnic.
53
54
  def write_polytexnic_commands_file
54
- styles_dir = File.join(Dir.pwd, Softcover::Directories::STYLES)
55
55
  Polytexnic.write_polytexnic_style_file(styles_dir)
56
56
  end
57
+
58
+ def write_language_customization_file
59
+ filename = File.join(styles_dir, 'language_customization.sty')
60
+ contents = listing_customization
61
+ File.write(filename, contents)
62
+ end
63
+
64
+ def styles_dir
65
+ File.join(Dir.pwd, Softcover::Directories::STYLES)
66
+ end
67
+
68
+
69
+ def listing_customization
70
+ listing = language_labels["listing"].downcase
71
+ box = language_labels["aside"]
72
+ <<-EOS
73
+ % Aside box label
74
+ \\renewcommand{\\boxlabel}{#{box}}
75
+
76
+ % Codelisting captions
77
+ \\usepackage[hypcap=false]{caption}
78
+ \\DeclareCaptionFormat{#{listing}}{\\hspace{-0.2em}\\colorbox[gray]{.85}{\\hspace{0.1em}\\parbox{0.997\\textwidth}{#1#2#3}}\\vspace{-1.3\\baselineskip}}
79
+ \\captionsetup[#{listing}]{format=#{listing},labelfont=bf,skip=16pt,font={rm,normalsize}}
80
+ \\DeclareCaptionType{#{listing}}
81
+ \\newcommand{\\codecaption}[1]{\\captionof{#{listing}}{#1}}
82
+ EOS
83
+ end
84
+
57
85
  end
58
86
  end
@@ -177,20 +177,12 @@ module Softcover
177
177
 
178
178
  # Returns the PhantomJS executable (if available).
179
179
  def phantomjs
180
- filename = `which phantomjs`.chomp
181
- message = "Install PhantomJS (http://phantomjs.org/)"
182
- @phantomjs ||= executable(filename, message)
180
+ @phantomjs ||= executable(dependency_filename(:phantomjs))
183
181
  end
184
182
 
185
183
  # Returns the Inkscape executable (if available).
186
184
  def inkscape
187
- filename = `which inkscape`.chomp
188
- if filename.empty?
189
- filename = '/Applications/Inkscape.app/Contents/Resources/bin/' +
190
- 'inkscape'
191
- end
192
- message = "Install Inkscape (http://inkscape.org/)"
193
- @inkscape ||= executable(filename, message)
185
+ @inkscape ||= executable(dependency_filename(:inkscape))
194
186
  end
195
187
 
196
188
  # Strip attributes that are invalid in EPUB documents.
@@ -342,6 +334,7 @@ module Softcover
342
334
  <item id="softcover.css" href="styles/softcover.css" media-type="text/css"/>
343
335
  <item id="epub.css" href="styles/epub.css" media-type="text/css"/>
344
336
  <item id="custom.css" href="styles/custom.css" media-type="text/css"/>
337
+ <item id="custom_epub.css" href="styles/custom_epub.css" media-type="text/css"/>
345
338
  <item id="cover" href="cover.html" media-type="application/xhtml+xml"/>
346
339
  #{man_ch.join("\n")}
347
340
  #{images.join("\n")}
@@ -401,7 +394,7 @@ module Softcover
401
394
  end
402
395
 
403
396
  def chapter_name(n)
404
- n == 0 ? "Frontmatter" : "Chapter #{n}"
397
+ n == 0 ? language_labels["frontmatter"] : chapter_label(n)
405
398
  end
406
399
 
407
400
  # Returns the nav HTML content.
@@ -440,6 +433,7 @@ module Softcover
440
433
  <link rel="stylesheet" href="styles/softcover.css" type="text/css" />
441
434
  <link rel="stylesheet" href="styles/epub.css" type="text/css" />
442
435
  <link rel="stylesheet" href="styles/custom.css" type="text/css"/>
436
+ <link rel="stylesheet" href="styles/custom_epub.css" type="text/css"/>
443
437
  <link rel="stylesheet" type="application/vnd.adobe-page-template+xml" href="styles/page-template.xpgt" />
444
438
  </head>
445
439
 
@@ -99,7 +99,8 @@ module Softcover
99
99
  File.write(chapter.cache_filename, digest(markdown))
100
100
  p = Polytexnic::Pipeline.new(markdown,
101
101
  source: :markdown,
102
- custom_commands: Softcover.custom_styles)
102
+ custom_commands: Softcover.custom_styles,
103
+ language_labels: language_labels)
103
104
  p.polytex
104
105
  end
105
106
 
@@ -112,8 +113,9 @@ module Softcover
112
113
  polytex.gsub!(/(^\s*\\include{(.*?)})/) do
113
114
  File.read($2 + '.tex') + "\n"
114
115
  end
115
- cc = Softcover.custom_styles
116
- Polytexnic::Pipeline.new(polytex, custom_commands: cc).to_html
116
+ Polytexnic::Pipeline.new(polytex,
117
+ custom_commands: Softcover.custom_styles,
118
+ language_labels: language_labels).to_html
117
119
  end
118
120
 
119
121
  # Writes the full HTML file for the book.
@@ -12,7 +12,7 @@ module Softcover
12
12
  else
13
13
  system(command)
14
14
  end
15
- unless options[:kindlegen]
15
+ if options[:calibre]
16
16
  FileUtils.mv("ebooks/#{filename}.azw3", "ebooks/#{filename}.mobi")
17
17
  puts "MOBI saved to ebooks/#{filename}.mobi" unless silent
18
18
  end
@@ -25,28 +25,21 @@ module Softcover
25
25
 
26
26
  # Returns the command for making a MOBI, based on the options.
27
27
  def mobi_command(filename, options={})
28
- if options[:kindlegen]
29
- "#{kindlegen} ebooks/#{filename}.epub"
30
- else
28
+ if options[:calibre]
31
29
  "#{calibre} ebooks/#{filename}.epub ebooks/#{filename}.azw3"
30
+ else
31
+ "#{kindlegen} ebooks/#{filename}.epub"
32
32
  end
33
33
  end
34
34
 
35
35
  private
36
36
 
37
37
  def calibre
38
- filename = `which ebook-convert`.chomp
39
- url = 'http://calibre-ebook.com/'
40
- message = "Install Calibre (#{url}) and enable command line tools"
41
- message += " (http://manual.calibre-ebook.com/cli/cli-index.html)"
42
- @calibre ||= executable(filename, message)
38
+ @calibre ||= executable(dependency_filename(:calibre))
43
39
  end
44
40
 
45
41
  def kindlegen
46
- filename = `which kindlegen`.chomp
47
- url = 'http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211'
48
- message = "Install kindlegen (#{url})"
49
- @kindlegen ||= executable(filename, message)
42
+ @kindlegen ||= executable(dependency_filename(:kindlegen))
50
43
  end
51
44
  end
52
45
  end
@@ -5,6 +5,7 @@ module Softcover
5
5
  include Softcover::Utils
6
6
 
7
7
  def build!(options={})
8
+ make_png_from_gif
8
9
  if manifest.markdown?
9
10
  # Build the HTML to produce PolyTeX as a side-effect,
10
11
  # then update the manifest to reduce PDF generation
@@ -29,7 +30,9 @@ module Softcover
29
30
  polytex_filenames = manifest.pdf_chapter_filenames << book_filename
30
31
  polytex_filenames.each do |filename|
31
32
  polytex = File.read(filename)
32
- latex = Polytexnic::Pipeline.new(polytex).to_latex
33
+ latex = Polytexnic::Pipeline.new(polytex,
34
+ language_labels: language_labels).
35
+ to_latex
33
36
  if filename == book_filename
34
37
  latex.gsub!(/\\include{(.*?)}/) do
35
38
  "\\include{#{Softcover::Utils.tmpify(manifest, $1)}.tmp}"
@@ -67,9 +70,25 @@ module Softcover
67
70
  # The `xelatex` program is roughly equivalent to the more standard
68
71
  # `pdflatex`, but has better support for Unicode.
69
72
  def xelatex
70
- filename = `which xelatex`.chomp
71
- message = "Install LaTeX (http://latex-project.org/ftp.html)"
72
- @xelatex ||= executable(filename, message)
73
+ @xelatex ||= executable(dependency_filename(:latex))
74
+ end
75
+
76
+ # Make a PNG for each GIF in the images/ directory.
77
+ def make_png_from_gif
78
+ gif_pattern = File.join('images', '**', '*.gif')
79
+ gif_files = Dir.glob(gif_pattern).reject { |f| File.directory?(f) }
80
+ gif_files.each do |gif|
81
+ dir = File.dirname(gif)
82
+ ext = File.extname(gif)
83
+ img = File.basename(gif, ext)
84
+ png = File.join(dir, "#{img}.png")
85
+ system "#{convert} #{gif} #{png}"
86
+ end
87
+ end
88
+
89
+ # Returns the executable to ImageMagick's `convert` program.
90
+ def convert
91
+ @convert ||= executable(dependency_filename(:convert))
73
92
  end
74
93
 
75
94
  # Returns the command to build the PDF (once).
@@ -25,9 +25,7 @@ module Softcover
25
25
  end
26
26
 
27
27
  def ghostscript
28
- filename = `which gs`.chomp
29
- message = "Install GhostScript (should come with LaTeX)"
30
- @ghostscript ||= executable(filename, message)
28
+ @ghostscript ||= executable(dependency_filename(:ghostscript))
31
29
  end
32
30
  end
33
31
  end
data/lib/softcover/cli.rb CHANGED
@@ -42,9 +42,9 @@ module Softcover
42
42
  desc: "Find overfull hboxes",
43
43
  type: :boolean
44
44
  elsif format == 'mobi'
45
- method_option :kindlegen, aliases: '-k',
46
- desc: "Use kindlegen to build the MOBI",
47
- type: :boolean
45
+ method_option :calibre, aliases: '-c',
46
+ desc: "Use Calibre to build the MOBI",
47
+ type: :boolean
48
48
  end
49
49
  method_option :quiet, aliases: '-q',
50
50
  desc: "Quiet output", type: :boolean
@@ -67,6 +67,27 @@ module Softcover
67
67
  Softcover::Commands::Build.preview(options)
68
68
  end
69
69
 
70
+ # ===============================================
71
+ # Clean
72
+ # ===============================================
73
+ desc "clean", "Clean unneeded files"
74
+ def clean
75
+ rm(Dir.glob('*.aux'))
76
+ rm(Dir.glob('*.toc'))
77
+ rm(Dir.glob('*.out'))
78
+ rm(Dir.glob('*.tmp.*'))
79
+ rm(Dir.glob(path('tmp/*')))
80
+ rm('.highlight_cache')
81
+ end
82
+
83
+ # ===============================================
84
+ # Check
85
+ # ===============================================
86
+ desc "check", "Check dependencies"
87
+ def check
88
+ Softcover::Commands::Check.check_dependencies!
89
+ end
90
+
70
91
  # ===============================================
71
92
  # Server
72
93
  # ===============================================
@@ -2,6 +2,7 @@ module Softcover
2
2
  module Commands
3
3
  module Build
4
4
  include Softcover::Output
5
+ include Softcover::Utils
5
6
  extend self
6
7
 
7
8
  # Builds the book for the given format.
@@ -17,13 +18,17 @@ module Softcover
17
18
  # Builds the book for all formats.
18
19
  def all_formats(options={})
19
20
  building_message('all formats', options)
20
- Softcover::BUILD_ALL_FORMATS.each do |format|
21
- if format == 'mobi'
22
- building_message('EPUB & MOBI', options)
23
- else
24
- building_message(format.upcase, options)
21
+ if custom?
22
+ build_custom_formats!
23
+ else
24
+ Softcover::BUILD_ALL_FORMATS.each do |format|
25
+ if format == 'mobi'
26
+ building_message('EPUB & MOBI', options)
27
+ else
28
+ building_message(format.upcase, options)
29
+ end
30
+ builder_for(format).build!(options)
25
31
  end
26
- builder_for(format).build!(options)
27
32
  end
28
33
  end
29
34
 
@@ -38,6 +43,24 @@ module Softcover
38
43
  "Softcover::Builders::#{format.titleize}".constantize.new
39
44
  end
40
45
 
46
+ def custom?
47
+ File.exist?(build_config) && !custom_commands.empty?
48
+ end
49
+
50
+ def build_custom_formats!
51
+ execute custom_commands
52
+ end
53
+
54
+ # Returns custom commands (if any).
55
+ def custom_commands
56
+ commands(File.readlines(build_config).map(&:strip))
57
+ end
58
+
59
+ # Returns the filename for configuring `softcover build`.
60
+ def build_config
61
+ '.softcover-build'
62
+ end
63
+
41
64
  private
42
65
 
43
66
  # Shows a message when building a particular format.
@@ -0,0 +1,103 @@
1
+ module Softcover
2
+ module Commands
3
+ module Check
4
+ extend self
5
+ extend Softcover::Utils
6
+
7
+ def check_dependencies!
8
+ puts "Checking Softcover dependencies..."
9
+ simulate_work(1)
10
+ missing_dependencies = []
11
+ dependencies.each do |label, name|
12
+ printf "%-30s", "Checking for #{name}..."
13
+ simulate_work(0.15)
14
+ if present?(label)
15
+ puts "Found"
16
+ else
17
+ missing_dependencies << label
18
+ puts "Missing"
19
+ end
20
+ simulate_work(0.1)
21
+ end
22
+ simulate_work(0.25)
23
+ if missing_dependencies.empty?
24
+ puts "All dependencies satisfied."
25
+ else
26
+ puts "Missing dependencies:"
27
+ missing_dependencies.each do |dependency|
28
+ puts " • " + missing_dependency_message(dependency)
29
+ end
30
+ end
31
+ end
32
+
33
+ def dependencies
34
+ [[:latex, 'LaTeX'],
35
+ [:ghostscript, 'GhostScript'],
36
+ [:convert, 'ImageMagick'],
37
+ [:node, 'Node.js'],
38
+ [:phantomjs, 'PhantomJS'],
39
+ [:inkscape, 'Inkscape'],
40
+ [:calibre, 'Calibre'],
41
+ [:kindlegen, 'KindleGen'],
42
+ [:java, 'Java'],
43
+ [:epubcheck, 'EpubCheck'],
44
+ ]
45
+ end
46
+
47
+ def dependency_labels
48
+ dependencies.map(&:first)
49
+ end
50
+
51
+ def dependency_names
52
+ dependencies.map { |e| e[1] }
53
+ end
54
+
55
+ def missing_dependency_message(label)
56
+ case label
57
+ when :latex
58
+ message = "LaTeX (http://latex-project.org/ftp.html)\n"
59
+ message += " ∟ Huge download—start it now!"
60
+ when :convert
61
+ "ImageMagick (http://www.imagemagick.org/script/binary-releases.php)"
62
+ when :node
63
+ "NodeJS (http://nodejs.org/)"
64
+ when :phantomjs
65
+ "PhantomJS (http://phantomjs.org/)"
66
+ when :kindlegen
67
+ url = 'http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211'
68
+ "KindleGen (#{url})"
69
+ when :calibre
70
+ url = 'http://calibre-ebook.com/'
71
+ message = "Calibre (#{url})\n"
72
+ message += " ∟ Enable Calibre command-line tools"
73
+ message += " (http://manual.calibre-ebook.com/cli/cli-index.html)"
74
+ when :java
75
+ url = 'http://www.java.com/en/download/help/index_installing.xml'
76
+ "Java (#{url})"
77
+ when :ghostscript
78
+ "GhostScript (should come with LaTeX)"
79
+ when :epubcheck
80
+ url = 'https://github.com/IDPF/epubcheck/releases/'
81
+ url += 'download/v3.0/epubcheck-3.0.zip'
82
+ message = "EpubCheck 3.0 (#{url})\n"
83
+ message += " ∟ Unzip EpubCheck into your home directory"
84
+ when :inkscape
85
+ message = "Inkscape (http://inkscape.org/)"
86
+ else
87
+ raise "Unknown label #{label}"
88
+ end
89
+ end
90
+
91
+ def present?(label)
92
+ File.exist?(dependency_filename(label))
93
+ end
94
+
95
+ # Simulate working for given time.
96
+ # `softcover check` is more satisfying if it looks like it's doing work.
97
+ def simulate_work(time)
98
+ sleep time unless Softcover::test?
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -30,13 +30,6 @@ module Softcover
30
30
  def deploy_config
31
31
  '.softcover-deploy'
32
32
  end
33
-
34
- # Returns the commands from the given lines.
35
- # We skip comments and blank lines.
36
- def commands(lines)
37
- skip = /(^\s*#|^\s*$)/
38
- lines.reject { |line| line =~ skip }.join("\n")
39
- end
40
33
  end
41
34
  end
42
35
  end
@@ -14,17 +14,11 @@ module Softcover
14
14
  private
15
15
 
16
16
  def java
17
- filename = `which java`.chomp
18
- url = 'http://www.java.com/en/download/help/index_installing.xml'
19
- message = "Install Java (#{url})"
20
- @java ||= executable(filename, message)
17
+ @java ||= executable(dependency_filename(:java))
21
18
  end
22
19
 
23
20
  def epubcheck
24
- filename = File.join(Dir.home, 'epubcheck-3.0', 'epubcheck-3.0.jar')
25
- url = 'https://github.com/IDPF/epubcheck/releases/download/v3.0/epubcheck-3.0.zip'
26
- message = "Download EpubCheck 3.0 (#{url}) and unzip it in your home directory"
27
- @epubcheck ||= executable(filename, message).inspect
21
+ @epubcheck ||= executable(dependency_filename(:epubcheck)).inspect
28
22
  end
29
23
  end
30
24
  end
@@ -29,7 +29,11 @@ module Softcover
29
29
  'img' => %w{id class src alt},
30
30
  'em' => %w{id class},
31
31
  'code' => %w{id class},
32
- 'strong' => %w{id class}
32
+ 'strong' => %w{id class},
33
+ 'table' => %w{id class},
34
+ 'tbody' => %w{id class},
35
+ 'tr' => %w{id class},
36
+ 'td' => %w{id class}
33
37
  },
34
38
  protocols: {
35
39
  'a' => {'href' => [:relative, 'http', 'https', 'mailto']},
@@ -0,0 +1,6 @@
1
+ # Edit this file to customize your build steps with custom command options
2
+ # or additional commands.
3
+ #
4
+ # softcover build:pdf
5
+ # softcover build:mobi
6
+ # softcover build:preview
@@ -75,6 +75,12 @@ Softcover supports the inclusion of images, like this:
75
75
 
76
76
  ![Some dude.](images/2011_michael_hartl.png)
77
77
 
78
+ Using \LaTeX\ labels, you can also include a caption (as in Figure~\ref{fig:captioned_image}) or just a figure number (as in Figure~\ref{fig:figure_number}).
79
+
80
+ ![Some dude.\label{fig:captioned_image}](images/2011_michael_hartl.png)
81
+
82
+ ![\label{fig:figure_number}](images/2011_michael_hartl.png)
83
+
78
84
  ### Tables
79
85
 
80
86
  Softcover supports raw tables via a simple table syntax:
@@ -88,6 +94,7 @@ Softcover supports raw tables via a simple table syntax:
88
94
  | `PATCH` | /users/1 | `update` | update user with id `1` |
89
95
  | `DELETE` | /users/1 | `destroy` | delete user with id `1` |
90
96
 
97
+ See [*The Softcover Book*](http://manual.softcover.io/book/softcover_markdown#sec-embedded_tabular_and_tables) to learn how to make more complicated tables.
91
98
 
92
99
  ## Command-line interface
93
100
 
@@ -102,17 +109,9 @@ Commands:
102
109
  softcover build:mobi # Build MOBI
103
110
  softcover build:pdf # Build PDF
104
111
  softcover build:preview # Build book preview in all formats
105
- softcover config # View local config
106
- softcover config:add key=value # Add to your local config vars
107
- softcover epub:validate, epub:check # Validate EPUB with epubcheck
108
- softcover help [COMMAND] # Describe available commands...
109
- softcover login # Log into Softcover account
110
- softcover logout # Log out of Softcover account
111
- softcover new <name> # Generate new book directory structure.
112
- softcover open # Open book on Softcover website (OS X)
113
- softcover publish # Publish your book on Softcover
114
- softcover publish:screencasts # Publish screencasts
115
- softcover server # Run local server
112
+ .
113
+ .
114
+ .
116
115
  ```
117
116
 
118
117
  \noindent You can run `softcover help <command>` to get additional help on a given command: