diff --git a/Gemfile b/Gemfile
index b628640f9eb..48019c8b622 100644
--- a/Gemfile
+++ b/Gemfile
@@ -51,8 +51,8 @@ group :doc do
gem "sdoc", ">= 2.4.0"
gem "redcarpet", "~> 3.2.3", platforms: :ruby
gem "w3c_validators", "~> 1.3.6"
- gem "kindlerb", "~> 1.2.0"
gem "rouge"
+ gem "rubyzip", "~> 2.0"
end
# Active Support
diff --git a/Gemfile.lock b/Gemfile.lock
index 8d7996f534d..e1269a2e620 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -181,7 +181,7 @@ GEM
crass (1.0.6)
cssbundling-rails (1.1.0)
railties (>= 6.0.0)
- curses (1.4.3)
+ curses (1.4.4)
daemons (1.4.1)
dalli (3.2.0)
dante (0.2.0)
@@ -303,9 +303,6 @@ GEM
railties (>= 6.0.0)
json (2.6.1)
jwt (2.3.0)
- kindlerb (1.2.0)
- mustache
- nokogiri
libxml-ruby (3.2.1)
listen (3.7.0)
rb-fsevent (~> 0.10, >= 0.10.3)
@@ -336,7 +333,6 @@ GEM
msgpack (1.4.2)
multi_json (1.15.0)
multipart-post (2.1.1)
- mustache (1.1.1)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
mysql2 (0.5.4)
@@ -583,7 +579,6 @@ DEPENDENCIES
importmap-rails
jsbundling-rails
json (>= 2.0.0)
- kindlerb (~> 1.2.0)
libxml-ruby
listen (~> 3.3)
minitest (>= 5.15.0)
@@ -614,6 +609,7 @@ DEPENDENCIES
rubocop-packaging
rubocop-performance
rubocop-rails
+ rubyzip (~> 2.0)
sdoc (>= 2.4.0)
selenium-webdriver (>= 4.0.0)
sequel
@@ -637,4 +633,4 @@ DEPENDENCIES
websocket-client-simple!
BUNDLED WITH
- 2.3.14
+ 2.3.17
diff --git a/guides/Rakefile b/guides/Rakefile
index 694976fe847..834b4ba8762 100644
--- a/guides/Rakefile
+++ b/guides/Rakefile
@@ -10,16 +10,16 @@ namespace :guides do
ruby "-Eutf-8:utf-8", "rails_guides.rb"
end
- desc "Generate .mobi file. The kindlegen executable must be in your PATH. You can get it for free from http://www.amazon.com/gp/feature.html?docId=1000765211"
+ desc "Generate .mobi file"
task :kindle do
- require "kindlerb"
- unless Kindlerb.kindlegen_available?
- abort "Please run `setupkindlerb` to install kindlegen"
- end
- unless /convert/.match?(`convert`)
- abort "Please install ImageMagick"
- end
- ENV["KINDLE"] = "1"
+ require "active_support/deprecation"
+ ActiveSupport::Deprecation.warn("The guides:generate:kindle rake task is deprecated and will be removed in 7.2. Run rake guides:generate:epub instead")
+ Rake::Task["guides:generate:epub"].invoke
+ end
+
+ desc "Generate .epub file"
+ task :epub do
+ ENV["EPUB"] = "1"
Rake::Task["guides:generate:html"].invoke
end
end
@@ -68,7 +68,7 @@ Some arguments may be passed via environment variables:
Examples:
$ rake guides:generate ALL=1 RAILS_VERSION=v5.1.0
$ rake guides:generate ONLY=migrations
- $ rake guides:generate:kindle
+ $ rake guides:generate:epub
$ rake guides:generate GUIDES_LANGUAGE=es
HELP
end
diff --git a/guides/assets/stylesheets/kindle.css b/guides/assets/stylesheets/epub.css
similarity index 80%
rename from guides/assets/stylesheets/kindle.css
rename to guides/assets/stylesheets/epub.css
index b26cd1786a3..aca2a1c12ae 100644
--- a/guides/assets/stylesheets/kindle.css
+++ b/guides/assets/stylesheets/epub.css
@@ -8,4 +8,9 @@ p, H1, H2, H3, H4, H5, H6, H7, H8, table { margin-top: 1em;}
}
#toc .document {
text-indent: 2em;
+}
+
+img {
+ display: block;
+ max-width: 100%;
}
\ No newline at end of file
diff --git a/guides/rails_guides.rb b/guides/rails_guides.rb
index a72acdbd061..937375401aa 100644
--- a/guides/rails_guides.rb
+++ b/guides/rails_guides.rb
@@ -24,7 +24,7 @@ RailsGuides::Generator.new(
version: version,
all: env_flag["ALL"],
only: env_value["ONLY"],
- kindle: env_flag["KINDLE"],
+ epub: env_flag["EPUB"],
language: env_value["GUIDES_LANGUAGE"],
direction: env_value["DIRECTION"]
).generate
diff --git a/guides/rails_guides/epub.rb b/guides/rails_guides/epub.rb
new file mode 100644
index 00000000000..149d69fa770
--- /dev/null
+++ b/guides/rails_guides/epub.rb
@@ -0,0 +1,94 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require "nokogiri"
+require "fileutils"
+require "yaml"
+require "date"
+
+require "rails_guides/epub_packer"
+
+module Epub # :nodoc:
+ extend self
+
+ def generate(output_dir, epub_outfile)
+ fix_file_names(output_dir)
+ generate_meta_files(output_dir)
+ generate_epub(output_dir, epub_outfile)
+ end
+
+ private
+ def open_toc_doc(toc)
+ Nokogiri::XML(toc).xpath("//ncx:content", "ncx" => "http://www.daisy.org/z3986/2005/ncx/")
+ end
+
+ def generate_meta_files(output_dir)
+ output_dir = File.absolute_path(File.join(output_dir, ".."))
+ Dir.chdir output_dir do
+ puts "=> Using output dir: #{output_dir}"
+ puts "=> Generating meta files"
+ FileUtils.mkdir_p("META-INF")
+ File.write("META-INF/container.xml", <<~CONTENT)
+
+
+
+
+
+
+ CONTENT
+ end
+ end
+
+ def generate_epub(output_dir, epub_outfile)
+ output_dir = File.absolute_path(File.join(output_dir, ".."))
+ Dir.chdir output_dir do
+ puts "=> Generating EPUB"
+ EpubPacker.pack("./", epub_outfile)
+ puts "=> Done Generating EPUB"
+ end
+ end
+
+ def is_name_invalid(name)
+ (/[0-9]/ === name.chars.first)
+ end
+
+ def fix_file_names(output_dir)
+ book_dir = File.absolute_path(output_dir)
+ Dir.chdir book_dir do
+ puts "=> Using book dir: #{book_dir}"
+ puts "=> Fixing filenames in Table of Contents"
+ # opf file: item->id and itemref->idref attributes does not support values starting with a number
+ toc = File.read("toc.ncx")
+ toc_html = File.read("toc.html")
+ opf = File.read("rails_guides.opf")
+
+ doc = open_toc_doc(toc)
+ doc.each do |c|
+ name = c[:src]
+
+ if is_name_invalid(name)
+ FileUtils.mv(name, "rails_#{name}")
+ toc.gsub!(name, "rails_#{name}")
+ toc_html.gsub!(name, "rails_#{name}")
+ opf.gsub!(name, "rails_#{name}")
+ end
+ end
+ File.write("toc.ncx", toc)
+ File.write("toc.html", toc_html)
+ File.write("rails_guides.opf", opf)
+ end
+ end
+
+ def add_head_section(doc, title)
+ head = Nokogiri::XML::Node.new "head", doc
+ title_node = Nokogiri::XML::Node.new "title", doc
+ title_node.content = title
+ title_node.parent = head
+ css = Nokogiri::XML::Node.new "link", doc
+ css["rel"] = "stylesheet"
+ css["type"] = "text/css"
+ css["href"] = "#{Dir.pwd}/stylesheets/epub.css"
+ css.parent = head
+ doc.at("body").before head
+ end
+end
diff --git a/guides/rails_guides/epub_packer.rb b/guides/rails_guides/epub_packer.rb
new file mode 100644
index 00000000000..d4ac611ed7c
--- /dev/null
+++ b/guides/rails_guides/epub_packer.rb
@@ -0,0 +1,59 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require "nokogiri"
+require "fileutils"
+require "yaml"
+require "date"
+require "zip"
+
+module EpubPacker # :nodoc:
+ extend self
+
+ def pack(output_dir, epub_file_name)
+ @output_dir = output_dir
+
+ FileUtils.rm_f(epub_file_name)
+
+ Zip::OutputStream.open(epub_file_name) {
+ |epub|
+ create_epub(epub, epub_file_name)
+ }
+
+ entries = Dir.entries(output_dir) - %w[. ..]
+
+ entries.reject! { |item| File.extname(item) == ".epub" }
+
+ Zip::File.open(epub_file_name, create: true) do |epub|
+ write_entries(entries, "", epub)
+ end
+ end
+
+ def create_epub(epub, epub_file_name)
+ epub.put_next_entry("mimetype", nil, nil, Zip::Entry::STORED, Zlib::NO_COMPRESSION)
+ epub.write "application/epub+zip"
+ end
+
+ def write_entries(entries, path, zipfile)
+ entries.each do |e|
+ zipfile_path = path == "" ? e : File.join(path, e)
+ disk_file_path = File.join(@output_dir, zipfile_path)
+
+ if File.directory? disk_file_path
+ recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
+ else
+ put_into_archive(disk_file_path, zipfile, zipfile_path)
+ end
+ end
+ end
+
+ def recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
+ zipfile.mkdir zipfile_path
+ subdir = Dir.entries(disk_file_path) - %w[. ..]
+ write_entries subdir, zipfile_path, zipfile
+ end
+
+ def put_into_archive(disk_file_path, zipfile, zipfile_path)
+ zipfile.add(zipfile_path, disk_file_path)
+ end
+end
diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb
index 6f7535d56fd..5f2a9386d38 100644
--- a/guides/rails_guides/generator.rb
+++ b/guides/rails_guides/generator.rb
@@ -2,6 +2,8 @@
require "set"
require "fileutils"
+require "nokogiri"
+require "securerandom"
require "active_support/core_ext/string/output_safety"
require "active_support/core_ext/object/blank"
@@ -10,23 +12,23 @@ require "action_view"
require "rails_guides/markdown"
require "rails_guides/helpers"
+require "rails_guides/epub"
module RailsGuides
class Generator
GUIDES_RE = /\.(?:erb|md)\z/
- def initialize(edge:, version:, all:, only:, kindle:, language:, direction: nil)
+ def initialize(edge:, version:, all:, only:, epub:, language:, direction: nil)
@edge = edge
@version = version
@all = all
@only = only
- @kindle = kindle
+ @epub = epub
@language = language
@direction = direction || "ltr"
- if @kindle
- check_for_kindlegen
- register_kindle_mime_types
+ if @epub
+ register_special_mime_types
end
initialize_dirs
@@ -37,32 +39,24 @@ module RailsGuides
def generate
generate_guides
copy_assets
- generate_mobi if @kindle
+ generate_epub if @epub
end
private
- def register_kindle_mime_types
+ def register_special_mime_types
Mime::Type.register_alias("application/xml", :opf, %w(opf))
Mime::Type.register_alias("application/xml", :ncx, %w(ncx))
end
- def check_for_kindlegen
- if `which kindlegen`.blank?
- raise "Can't create a kindle version without `kindlegen`."
- end
+ def generate_epub
+ Epub.generate(@output_dir, epub_filename)
+ puts "Epub generated at: output/epub/#{epub_filename}"
end
- def generate_mobi
- require "rails_guides/kindle"
- out = "#{@output_dir}/kindlegen.out"
- Kindle.generate(@output_dir, mobi, out)
- puts "(kindlegen log at #{out})."
- end
-
- def mobi
- mobi = +"ruby_on_rails_guides_#{@version || @edge[0, 7]}"
- mobi << ".#{@language}" if @language
- mobi << ".mobi"
+ def epub_filename
+ epub_filename = +"ruby_on_rails_guides_#{@version || @edge[0, 7]}"
+ epub_filename << ".#{@language}" if @language
+ epub_filename << ".epub"
end
def initialize_dirs
@@ -72,7 +66,7 @@ module RailsGuides
@source_dir += "/#{@language}" if @language
@output_dir = "#{@guides_dir}/output"
- @output_dir += "/kindle" if @kindle
+ @output_dir += "/epub/OEBPS" if @epub
@output_dir += "/#{@language}" if @language
end
@@ -95,10 +89,9 @@ module RailsGuides
def guides_to_generate
guides = Dir.entries(@source_dir).grep(GUIDES_RE)
- if @kindle
- Dir.entries("#{@source_dir}/kindle").grep(GUIDES_RE).map do |entry|
- next if entry == "KINDLE.md"
- guides << "kindle/#{entry}"
+ if @epub
+ Dir.entries("#{@source_dir}/epub").grep(GUIDES_RE).map do |entry|
+ guides << "epub/#{entry}"
end
end
@@ -108,7 +101,7 @@ module RailsGuides
def select_only(guides)
prefixes = @only.split(",").map(&:strip)
guides.select do |guide|
- guide.start_with?("kindle", *prefixes)
+ guide.start_with?("epub", *prefixes)
end
end
@@ -137,15 +130,16 @@ module RailsGuides
def generate_guide(guide, output_file)
output_path = output_path_for(output_file)
puts "Generating #{guide} as #{output_file}"
- layout = @kindle ? "kindle/layout" : "layout"
+ layout = @epub ? "epub/layout" : "layout"
view = ActionView::Base.with_empty_template_cache.with_view_paths(
[@source_dir],
edge: @edge,
version: @version,
- mobi: "kindle/#{mobi}",
+ epub: "epub/#{epub_filename}",
language: @language,
direction: @direction,
+ uuid: SecureRandom.uuid
)
view.extend(Helpers)
@@ -161,7 +155,8 @@ module RailsGuides
view: view,
layout: layout,
edge: @edge,
- version: @version
+ version: @version,
+ epub: @epub
).render(body)
warn_about_broken_links(result)
diff --git a/guides/rails_guides/helpers.rb b/guides/rails_guides/helpers.rb
index 5ab1388c29e..25a36723e8e 100644
--- a/guides/rails_guides/helpers.rb
+++ b/guides/rails_guides/helpers.rb
@@ -28,6 +28,15 @@ module RailsGuides
documents.reject { |document| document["work_in_progress"] }
end
+ def all_images
+ base_path = File.expand_path("../assets", __dir__)
+ images_path = File.join(base_path, "images/**/*")
+ @all_images = Dir.glob(images_path).reject { |f| File.directory?(f) }.map { |item|
+ item.delete_prefix "#{base_path}/"
+ }
+ @all_images
+ end
+
def docs_for_menu(position = nil)
if position.nil?
documents_by_section
diff --git a/guides/rails_guides/kindle.rb b/guides/rails_guides/kindle.rb
deleted file mode 100644
index dea2e775a41..00000000000
--- a/guides/rails_guides/kindle.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require "kindlerb"
-require "nokogiri"
-require "fileutils"
-require "yaml"
-require "date"
-
-module Kindle
- extend self
-
- def generate(output_dir, mobi_outfile, logfile)
- output_dir = File.absolute_path(output_dir)
- Dir.chdir output_dir do
- puts "=> Using output dir: #{output_dir}"
- puts "=> Arranging html pages in document order"
- toc = File.read("toc.ncx")
- doc = Nokogiri::XML(toc).xpath("//ncx:content", "ncx" => "http://www.daisy.org/z3986/2005/ncx/")
- html_pages = doc.filter_map { |c| c[:src] }.uniq
-
- generate_front_matter(html_pages)
-
- generate_sections(html_pages)
-
- generate_document_metadata(mobi_outfile)
-
- puts "Creating MOBI document with kindlegen. This may take a while."
- if Kindlerb.run(output_dir)
- puts "MOBI document generated at #{File.expand_path(mobi_outfile, output_dir)}"
- end
- end
- end
-
- def generate_front_matter(html_pages)
- frontmatter = []
- html_pages.delete_if { |x|
- if /(toc|welcome|copyright).html/.match?(x)
- frontmatter << x unless /toc/.match?(x)
- true
- end
- }
- html = frontmatter.map { |x|
- Nokogiri::HTML(File.open(x)).at("body").inner_html
- }.join("\n")
-
- fdoc = Nokogiri::HTML(html)
- fdoc.search("h3").each do |h3|
- h3.name = "h4"
- end
- fdoc.search("h2").each do |h2|
- h2.name = "h3"
- h2["id"] = h2.inner_text.gsub(/\s/, "-")
- end
- add_head_section fdoc, "Front Matter"
- File.open("frontmatter.html", "w") { |f| f.puts fdoc.to_html }
- html_pages.unshift "frontmatter.html"
- end
-
- def generate_sections(html_pages)
- FileUtils.rm_rf("sections/")
- html_pages.each_with_index do |page, section_idx|
- FileUtils.mkdir_p("sections/%03d" % section_idx)
- doc = Nokogiri::HTML(File.open(page))
- title = doc.at("title").inner_text.gsub("Ruby on Rails Guides: ", "")
- title = page.capitalize.gsub(".html", "") if title.strip == ""
- File.open("sections/%03d/_section.txt" % section_idx, "w") { |f| f.puts title }
- doc.xpath("//h3[@id]").each_with_index do |h3, item_idx|
- subsection = h3.inner_text
- content = h3.xpath("./following-sibling::*").take_while { |x| x.name != "h3" }.map(&:to_html)
- item = Nokogiri::HTML(h3.to_html + content.join("\n"))
- item_path = "sections/%03d/%03d.html" % [section_idx, item_idx]
- add_head_section(item, subsection)
- item.search("img").each do |img|
- img["src"] = "#{Dir.pwd}/#{img['src']}"
- end
- item.xpath("//li/p").each { |p| p.swap(p.children); p.remove }
- File.open(item_path, "w") { |f| f.puts item.to_html }
- end
- end
- end
-
- def generate_document_metadata(mobi_outfile)
- puts "=> Generating _document.yml"
- x = Nokogiri::XML(File.open("rails_guides.opf")).remove_namespaces!
- cover_jpg = "#{Dir.pwd}/images/rails_guides_kindle_cover.jpg"
- cover_gif = cover_jpg.sub(/jpg$/, "gif")
- puts `convert #{cover_jpg} #{cover_gif}`
- document = {
- "doc_uuid" => x.at("package")["unique-identifier"],
- "title" => x.at("title").inner_text.gsub(/\(.*$/, " v2"),
- "publisher" => x.at("publisher").inner_text,
- "author" => x.at("creator").inner_text,
- "subject" => x.at("subject").inner_text,
- "date" => x.at("date").inner_text,
- "cover" => cover_gif,
- "masthead" => nil,
- "mobi_outfile" => mobi_outfile
- }
- puts document.to_yaml
- File.open("_document.yml", "w") { |f| f.puts document.to_yaml }
- end
-
- def add_head_section(doc, title)
- head = Nokogiri::XML::Node.new "head", doc
- title_node = Nokogiri::XML::Node.new "title", doc
- title_node.content = title
- title_node.parent = head
- css = Nokogiri::XML::Node.new "link", doc
- css["rel"] = "stylesheet"
- css["type"] = "text/css"
- css["href"] = "#{Dir.pwd}/stylesheets/kindle.css"
- css.parent = head
- doc.at("body").before head
- end
-end
diff --git a/guides/rails_guides/markdown.rb b/guides/rails_guides/markdown.rb
index c0e456bf5f0..552cd552a77 100644
--- a/guides/rails_guides/markdown.rb
+++ b/guides/rails_guides/markdown.rb
@@ -3,11 +3,12 @@
require "redcarpet"
require "nokogiri"
require "rails_guides/markdown/renderer"
+require "rails_guides/markdown/epub_renderer"
require "rails-html-sanitizer"
module RailsGuides
class Markdown
- def initialize(view:, layout:, edge:, version:)
+ def initialize(view:, layout:, edge:, version:, epub:)
@view = view
@layout = layout
@edge = edge
@@ -15,6 +16,7 @@ module RailsGuides
@index_counter = Hash.new(0)
@raw_header = ""
@node_ids = {}
+ @epub = epub
end
def render(body)
@@ -59,7 +61,8 @@ module RailsGuides
end
def engine
- @engine ||= Redcarpet::Markdown.new(Renderer,
+ renderer = @epub ? EpubRenderer : Renderer
+ @engine ||= Redcarpet::Markdown.new(renderer,
no_intra_emphasis: true,
fenced_code_blocks: true,
autolink: true,
@@ -91,7 +94,7 @@ module RailsGuides
def generate_structure
@headings_for_index = []
if @body.present?
- @body = Nokogiri::HTML.fragment(@body).tap do |doc|
+ document = Nokogiri::HTML.fragment(@body).tap do |doc|
hierarchy = []
doc.children.each do |node|
@@ -117,7 +120,8 @@ module RailsGuides
doc.css("h3, h4, h5, h6").each do |node|
node.inner_html = "#{node.inner_html} "
end
- end.to_html
+ end
+ @body = @epub ? document.to_xhtml : document.to_html
end
end
diff --git a/guides/rails_guides/markdown/epub_renderer.rb b/guides/rails_guides/markdown/epub_renderer.rb
new file mode 100644
index 00000000000..5ddae73c891
--- /dev/null
+++ b/guides/rails_guides/markdown/epub_renderer.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+require "rouge"
+
+# Add more common shell commands
+Rouge::Lexers::Shell::BUILTINS << "|bin/rails|brew|bundle|gem|git|node|rails|rake|ruby|sqlite3|yarn"
+
+module RailsGuides
+ class Markdown
+ class EpubRenderer < Redcarpet::Render::XHTML # :nodoc:
+ cattr_accessor :edge, :version
+
+ def linebreak
+ " "
+ end
+
+ def link(url, title, content)
+ if %r{https?://api\.rubyonrails\.org}.match?(url)
+ %(#{content} )
+ elsif title
+ %(#{content} )
+ else
+ %(#{content} )
+ end
+ end
+
+ def header(text, header_level)
+ # Always increase the heading level by 1, so we can use h1, h2 heading in the document
+ header_level += 1
+
+ header_with_id = text.scan(/(.*){#(.*)}/)
+ unless header_with_id.empty?
+ %()
+ else
+ %(#{text} )
+ end
+ end
+
+ def paragraph(text)
+ if text =~ %r{^NOTE:\s+Defined\s+in\s+(.*?)
\.?$}
+ %(
)
+ elsif /^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:]/.match?(text)
+ convert_notes(text)
+ elsif text.include?("DO NOT READ THIS FILE ON GITHUB")
+ elsif text =~ /^\[(\d+)\]:<\/sup> (.+)$/
+ linkback = %(#{$1} )
+ %()
+ else
+ text = convert_footnotes(text)
+ "#{text}
"
+ end
+ end
+
+ private
+ def convert_footnotes(text)
+ text.gsub(/\[(\d+)\]<\/sup>/i) do
+ %()
+ end
+ end
+
+ def convert_notes(body)
+ # The following regexp detects special labels followed by a
+ # paragraph, perhaps at the end of the document.
+ #
+ # It is important that we do not eat more than one newline
+ # because formatting may be wrong otherwise. For example,
+ # if a bulleted list follows, the first item is not rendered
+ # as a list item, but as a paragraph starting with a plain
+ # asterisk.
+ body.gsub(/^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:](.*?)(\n(?=\n)|\Z)/m) do
+ css_class = \
+ case $1
+ when "CAUTION", "IMPORTANT"
+ "warning"
+ when "TIP"
+ "info"
+ else
+ $1.downcase
+ end
+ %()
+ end
+ end
+
+ def github_file_url(file_path)
+ tree = version || edge
+
+ root = file_path[%r{(\w+)/}, 1]
+ path = \
+ case root
+ when "abstract_controller", "action_controller", "action_dispatch"
+ "actionpack/lib/#{file_path}"
+ when /\A(action|active)_/
+ "#{root.sub("_", "")}/lib/#{file_path}"
+ else
+ file_path
+ end
+
+ "https://github.com/rails/rails/tree/#{tree}/#{path}"
+ end
+
+ def api_link(url)
+ if %r{https?://api\.rubyonrails\.org/v\d+\.}.match?(url)
+ url
+ elsif edge
+ url.sub("api", "edgeapi")
+ else
+ url.sub(/(?<=\.org)/, "/#{version}")
+ end
+ end
+ end
+ end
+end
diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb
index b1667b25a8d..bd0c721c767 100644
--- a/guides/rails_guides/markdown/renderer.rb
+++ b/guides/rails_guides/markdown/renderer.rb
@@ -7,7 +7,7 @@ Rouge::Lexers::Shell::BUILTINS << "|bin/rails|brew|bundle|gem|git|node|rails|rak
module RailsGuides
class Markdown
- class Renderer < Redcarpet::Render::HTML
+ class Renderer < Redcarpet::Render::HTML # :nodoc:
cattr_accessor :edge, :version
def block_code(code, language)
diff --git a/guides/source/kindle/copyright.html.erb b/guides/source/epub/copyright.html.erb
similarity index 100%
rename from guides/source/kindle/copyright.html.erb
rename to guides/source/epub/copyright.html.erb
diff --git a/guides/source/kindle/layout.html.erb b/guides/source/epub/layout.html.erb
similarity index 62%
rename from guides/source/kindle/layout.html.erb
rename to guides/source/epub/layout.html.erb
index fd8746776b0..9d96a656002 100644
--- a/guides/source/kindle/layout.html.erb
+++ b/guides/source/epub/layout.html.erb
@@ -1,14 +1,9 @@
-
-
-
+
+
-
-
+
+
<%= yield(:page_title) || 'Ruby on Rails Guides' %>
-
-
-
diff --git a/guides/source/epub/rails_guides.opf.erb b/guides/source/epub/rails_guides.opf.erb
new file mode 100644
index 00000000000..d552725cf61
--- /dev/null
+++ b/guides/source/epub/rails_guides.opf.erb
@@ -0,0 +1,48 @@
+
+
+
+ <%= @uuid %>
+ Ruby on Rails Guides (<%= @version || "main@#{@edge[0, 7]}" %>)
+ en
+ Ruby on Rails
+ Ruby on Rails
+ Reference
+ <%= Time.now.strftime('%Y-%m-%dT%H:%M:%SZ') %>
+ These guides are designed to make you immediately productive with Rails, and to help you understand how all of the pieces fit together.
+
+
+
+
+
+ <% documents_flat.each do |document| %>
+
+ <% end %>
+
+ <% %w{toc.html welcome.html copyright.html}.each do |url| %>
+
+ <% end %>
+
+
+
+
+
+
+
+ <% all_images.each do |image| %>
+
+ <% end %>
+
+
+
+
+
+
+ <% documents_flat.each do |document| %>
+
+ <% end %>
+
+
+
+
+
+
diff --git a/guides/source/epub/toc.html.erb b/guides/source/epub/toc.html.erb
new file mode 100644
index 00000000000..7cafe00b675
--- /dev/null
+++ b/guides/source/epub/toc.html.erb
@@ -0,0 +1,24 @@
+<% content_for :page_title do %>
+Ruby on Rails Guides
+<% end %>
+
+Table of Contents
+
+
+
+ <% documents_by_section.each_with_index do |section, i| %>
+
<%= "#{i + 1}." %> <%= section['name'] %>
+
+ <% section['documents'].each do |document| %>
+
+ <%= document['name'] %>
+ <% if document['work_in_progress']%>(WIP)<% end %>
+
+ <% end %>
+
+ <% end %>
+
+
+
diff --git a/guides/source/kindle/toc.ncx.erb b/guides/source/epub/toc.ncx.erb
similarity index 94%
rename from guides/source/kindle/toc.ncx.erb
rename to guides/source/epub/toc.ncx.erb
index 9b73bc9bea7..1115cd7f07a 100644
--- a/guides/source/kindle/toc.ncx.erb
+++ b/guides/source/epub/toc.ncx.erb
@@ -18,7 +18,7 @@
-
+
Introduction
@@ -30,7 +30,7 @@
-
+
Copyright & License
diff --git a/guides/source/kindle/welcome.html.erb b/guides/source/epub/welcome.html.erb
similarity index 100%
rename from guides/source/kindle/welcome.html.erb
rename to guides/source/epub/welcome.html.erb
diff --git a/guides/source/index.html.erb b/guides/source/index.html.erb
index 10e388774ce..5ec48061ef3 100644
--- a/guides/source/index.html.erb
+++ b/guides/source/index.html.erb
@@ -10,7 +10,7 @@
<% unless @edge -%>
- Rails Guides are also available for <%= link_to 'Kindle', @mobi %>.
+ Rails Guides are also available for <%= link_to 'Kindle', @epub %>.
<% end -%>
Guides marked with this icon are currently being worked on and will not be available in the Guides Index menu. While still useful, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections.
diff --git a/guides/source/kindle/rails_guides.opf.erb b/guides/source/kindle/rails_guides.opf.erb
deleted file mode 100644
index 06bfac8fc8d..00000000000
--- a/guides/source/kindle/rails_guides.opf.erb
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
- Ruby on Rails Guides (<%= @version || "main@#{@edge[0, 7]}" %>)
-
- en-us
- Ruby on Rails
- Ruby on Rails
- Reference
- <%= Time.now.strftime('%Y-%m-%d') %>
-
- These guides are designed to make you immediately productive with Rails, and to help you understand how all of the pieces fit together.
-
-
-
-
-
-
-
-
- <% documents_flat.each do |document| %>
-
- <% end %>
-
- <% %w{toc.html welcome.html copyright.html}.each do |url| %>
-
- <% end %>
-
-
-
-
-
-
-
-
-
-
- <% documents_flat.each do |document| %>
-
- <% end %>
-
-
-
-
-
-
-
diff --git a/guides/source/kindle/toc.html.erb b/guides/source/kindle/toc.html.erb
deleted file mode 100644
index b77ac2e99d6..00000000000
--- a/guides/source/kindle/toc.html.erb
+++ /dev/null
@@ -1,23 +0,0 @@
-<% content_for :page_title do %>
-Ruby on Rails Guides
-<% end %>
-
-Table of Contents
-
-
-<% documents_by_section.each_with_index do |section, i| %>
-
<%= "#{i + 1}." %> <%= section['name'] %>
-
- <% section['documents'].each do |document| %>
-
- <%= document['name'] %>
- <% if document['work_in_progress']%>(WIP)<% end %>
-
- <% end %>
-
-<% end %>
-
-
-