diff --git a/assets/javascripts/app/app.coffee b/assets/javascripts/app/app.coffee
index 00c17495..22845ccf 100644
--- a/assets/javascripts/app/app.coffee
+++ b/assets/javascripts/app/app.coffee
@@ -75,6 +75,7 @@
docs = @settings.getDocs()
for doc in @DOCS
(if docs.indexOf(doc.slug) >= 0 then @docs else @disabledDocs).add(doc)
+ @migrateDocs()
@docs.sort()
@disabledDocs.sort()
@docs.load @start.bind(@), @onBootError.bind(@), readCache: true, writeCache: true
@@ -99,6 +100,15 @@
@entries.add doc.entries.all()
return
+ migrateDocs: ->
+ for slug in @settings.getDocs() when not @docs.findBy('slug', slug)
+ needsSaving = true
+ if doc = @disabledDocs.findBy('slug_without_version', slug)
+ @disabledDocs.remove(doc)
+ @docs.add(doc)
+
+ @saveDocs() if needsSaving
+
enableDoc: (doc, _onSuccess, onError) ->
return if @docs.contains(doc)
onSuccess = =>
@@ -106,14 +116,17 @@
@docs.add(doc)
@docs.sort()
@initDoc(doc)
- @settings.setDocs(doc.slug for doc in @docs.all())
+ @saveDocs()
_onSuccess()
- @appCache?.updateInBackground()
return
doc.load onSuccess, onError, writeCache: true
return
+ saveDocs: ->
+ @settings.setDocs(doc.slug for doc in @docs.all())
+ @appCache?.updateInBackground()
+
welcomeBack: ->
visitCount = @settings.get('count')
@settings.set 'count', ++visitCount
diff --git a/assets/javascripts/app/router.coffee b/assets/javascripts/app/router.coffee
index d86b9881..aa1fc6b7 100644
--- a/assets/javascripts/app/router.coffee
+++ b/assets/javascripts/app/router.coffee
@@ -39,7 +39,7 @@ class app.Router
return
doc: (context, next) ->
- if doc = app.docs.findBy('slug', context.params.doc) or app.disabledDocs.findBy('slug', context.params.doc)
+ if doc = app.docs.findBySlug(context.params.doc) or app.disabledDocs.findBySlug(context.params.doc)
context.doc = doc
context.entry = doc.toEntry()
@triggerRoute 'entry'
@@ -48,7 +48,7 @@ class app.Router
return
type: (context, next) ->
- doc = app.docs.findBy 'slug', context.params.doc
+ doc = app.docs.findBySlug(context.params.doc)
if type = doc?.types.findBy 'slug', context.params.type
context.doc = doc
@@ -59,7 +59,7 @@ class app.Router
return
entry: (context, next) ->
- doc = app.docs.findBy 'slug', context.params.doc
+ doc = app.docs.findBySlug(context.params.doc)
if entry = doc?.findEntryByPathAndHash(context.params.path, context.hash)
context.doc = doc
diff --git a/assets/javascripts/collections/docs.coffee b/assets/javascripts/collections/docs.coffee
index 30001566..c4b2e368 100644
--- a/assets/javascripts/collections/docs.coffee
+++ b/assets/javascripts/collections/docs.coffee
@@ -1,6 +1,9 @@
class app.collections.Docs extends app.Collection
@model: 'Doc'
+ findBySlug: (slug) ->
+ @findBy('slug', slug) or @findBy('slug_without_version', slug)
+
sort: ->
@models.sort (a, b) ->
a = a.name.toLowerCase()
diff --git a/assets/javascripts/models/doc.coffee b/assets/javascripts/models/doc.coffee
index c805d3a2..b7b78b54 100644
--- a/assets/javascripts/models/doc.coffee
+++ b/assets/javascripts/models/doc.coffee
@@ -4,6 +4,8 @@ class app.models.Doc extends app.Model
constructor: ->
super
@reset @
+ [@slug_without_version, @version] = @slug.split('~v')
+ @icon = @slug_without_version
@text = @toEntry().text
reset: (data) ->
diff --git a/assets/javascripts/templates/pages/offline_tmpl.coffee b/assets/javascripts/templates/pages/offline_tmpl.coffee
index 54a6bfa7..bf79a7f7 100644
--- a/assets/javascripts/templates/pages/offline_tmpl.coffee
+++ b/assets/javascripts/templates/pages/offline_tmpl.coffee
@@ -51,10 +51,11 @@ canICloseTheTab = ->
app.templates.offlineDoc = (doc, status) ->
outdated = doc.isOutdated(status)
+ version = if doc.version then " (#{doc.version})" else ''
html = """
- #{doc.name} |
+ #{doc.name}#{version} |
#{Math.ceil(doc.db_size / 100000) / 10} MB |
"""
diff --git a/assets/javascripts/templates/path_tmpl.coffee b/assets/javascripts/templates/path_tmpl.coffee
index 43996ee0..cf4bc873 100644
--- a/assets/javascripts/templates/path_tmpl.coffee
+++ b/assets/javascripts/templates/path_tmpl.coffee
@@ -1,5 +1,5 @@
app.templates.path = (doc, type, entry) ->
- html = """#{doc.name}"""
+ html = """#{doc.name}"""
html += """#{type.name}""" if type
html += """#{$.escape entry.name}""" if entry
html
diff --git a/assets/javascripts/templates/sidebar_tmpl.coffee b/assets/javascripts/templates/sidebar_tmpl.coffee
index 41c7038e..0b2390c4 100644
--- a/assets/javascripts/templates/sidebar_tmpl.coffee
+++ b/assets/javascripts/templates/sidebar_tmpl.coffee
@@ -1,7 +1,7 @@
templates = app.templates
templates.sidebarDoc = (doc, options = {}) ->
- link = """"""
if options.disabled
@@ -22,7 +22,7 @@ templates.sidebarResult = (entry) ->
"""Enable"""
else
""""""
- """#{addon}#{$.escape entry.name}"""
+ """#{addon}#{$.escape entry.name}"""
templates.sidebarNoResults = ->
html = """ No results.
"""
@@ -35,11 +35,13 @@ templates.sidebarPageLink = (count) ->
"""Show more\u2026 (#{count})"""
templates.sidebarLabel = (doc, options = {}) ->
- label = """"
+ label += ">#{doc.name}"
+ label += " (#{doc.version})" if doc.version
+ label + ""
templates.sidebarDisabledList = (options) ->
"""#{templates.render 'sidebarDoc', options.docs, disabled: true}
"""
diff --git a/lib/app.rb b/lib/app.rb
index a618a243..d85fa49d 100644
--- a/lib/app.rb
+++ b/lib/app.rb
@@ -115,6 +115,23 @@ class App < Sinatra::Application
end
end
+ def find_doc(slug)
+ settings.docs[slug] || begin
+ slug = "#{slug}~v"
+ settings.docs.each do |_slug, _doc|
+ return _doc if _slug.start_with?(slug)
+ end
+ nil
+ end
+ end
+
+ def user_has_docs?(slug)
+ docs.include?(slug) || begin
+ slug = "#{slug}~v"
+ docs.any? { |_slug| _slug.start_with?(slug) }
+ end
+ end
+
def doc_index_urls
docs.each_with_object [] do |slug, result|
if doc = settings.docs[slug]
@@ -247,14 +264,14 @@ class App < Sinatra::Application
settings.news_feed
end
- get %r{\A/(\w+)(\-[\w\-]+)?(/.*)?\z} do |doc, type, rest|
- return 404 unless @doc = settings.docs[doc]
+ get %r{\A/([\w~\.]+)(\-[\w\-]+)?(/.*)?\z} do |doc, type, rest|
+ return 404 unless @doc = find_doc(doc)
if rest.nil?
redirect "/#{doc}#{type}/#{query_string_for_redirection}"
elsif rest.length > 1 && rest.end_with?('/')
redirect "/#{doc}#{type}#{rest[0...-1]}#{query_string_for_redirection}"
- elsif docs.include?(doc) && supports_js_redirection?
+ elsif user_has_docs?(doc) && supports_js_redirection?
redirect_via_js(request.path)
else
erb :other
diff --git a/lib/docs.rb b/lib/docs.rb
index b31dcf7e..046d75a8 100644
--- a/lib/docs.rb
+++ b/lib/docs.rb
@@ -31,31 +31,44 @@ module Docs
Dir["#{root_path}/docs/scrapers/**/*.rb"].
map { |file| File.basename(file, '.rb') }.
sort!.
- map(&method(:find)).
+ map { |name| const_get(name.camelize) }.
reject(&:abstract)
end
- def self.find(name)
+ def self.all_versions
+ all.flat_map(&:versions)
+ end
+
+ def self.find(name, version)
const = name.camelize
- const_get(const)
+ doc = const_get(const)
+
+ if version.present?
+ doc = doc.versions.find { |klass| klass.version == version }
+ raise DocNotFound.new(%(could not find version "#{version}" for doc "#{name}"), name) unless doc
+ else
+ doc = doc.versions.first
+ end
+
+ doc
rescue NameError => error
if error.name.to_s == const
- raise DocNotFound.new("failed to locate doc class '#{name}'", name)
+ raise DocNotFound.new(%(could not find doc "#{name}"), name)
else
raise error
end
end
- def self.generate_page(name, page_id)
- find(name).store_page(store, page_id)
+ def self.generate_page(name, version, page_id)
+ find(name, version).store_page(store, page_id)
end
- def self.generate(name)
- find(name).store_pages(store)
+ def self.generate(name, version)
+ find(name, version).store_pages(store)
end
def self.generate_manifest
- Manifest.new(store, all).store
+ Manifest.new(store, all_versions).store
end
def self.store
diff --git a/lib/docs/core/doc.rb b/lib/docs/core/doc.rb
index 23203756..69eb67a0 100644
--- a/lib/docs/core/doc.rb
+++ b/lib/docs/core/doc.rb
@@ -12,12 +12,39 @@ module Docs
subclass.type = type
end
+ def version(version = nil, &block)
+ return @version if version.nil?
+
+ klass = Class.new(self)
+ klass.class_exec(&block)
+ klass.name = name
+ klass.slug = slug
+ klass.version = version
+ klass.links = links
+ @versions ||= []
+ @versions << klass
+ klass
+ end
+
+ def version=(value)
+ @version = value.to_s
+ end
+
+ def versions
+ @versions.presence || [self]
+ end
+
+ def version?
+ version.present?
+ end
+
def name
@name || super.try(:demodulize)
end
def slug
- @slug || name.try(:downcase)
+ slug = @slug || name.try(:downcase)
+ version? ? "#{slug}~v#{version}" : slug
end
def path
diff --git a/lib/docs/filters/python2/entries.rb b/lib/docs/filters/python/entries_v2.rb
similarity index 97%
rename from lib/docs/filters/python2/entries.rb
rename to lib/docs/filters/python/entries_v2.rb
index 453f4d19..c5f7bfc1 100644
--- a/lib/docs/filters/python2/entries.rb
+++ b/lib/docs/filters/python/entries_v2.rb
@@ -1,6 +1,6 @@
module Docs
- class Python2
- class EntriesFilter < Docs::EntriesFilter
+ class Python
+ class EntriesV2Filter < Docs::EntriesFilter
REPLACE_TYPES = {
'compiler package' => 'Compiler',
'Cryptographic' => 'Cryptography',
diff --git a/lib/docs/filters/python/entries.rb b/lib/docs/filters/python/entries_v3.rb
similarity index 98%
rename from lib/docs/filters/python/entries.rb
rename to lib/docs/filters/python/entries_v3.rb
index 2f7d6e1f..2addea16 100644
--- a/lib/docs/filters/python/entries.rb
+++ b/lib/docs/filters/python/entries_v3.rb
@@ -1,6 +1,6 @@
module Docs
class Python
- class EntriesFilter < Docs::EntriesFilter
+ class EntriesV3Filter < Docs::EntriesFilter
REPLACE_TYPES = {
'Cryptographic' => 'Cryptography',
'Custom Interpreters' => 'Interpreters',
diff --git a/lib/docs/scrapers/python.rb b/lib/docs/scrapers/python.rb
index 877f4161..51e1586a 100644
--- a/lib/docs/scrapers/python.rb
+++ b/lib/docs/scrapers/python.rb
@@ -1,13 +1,8 @@
module Docs
class Python < FileScraper
- self.release = '3.5.1'
self.type = 'sphinx'
- self.dir = '/Users/Thibaut/DevDocs/Docs/Python' # downloaded from docs.python.org/3/download.html
- self.base_url = 'http://docs.python.org/3/'
self.root_path = 'library/index.html'
- html_filters.push 'python/entries', 'python/clean_html'
-
options[:only_patterns] = [/\Alibrary\//]
options[:skip] = %w(
@@ -23,5 +18,21 @@ module Docs
© 1990–2015 Python Software Foundation
Licensed under the PSF License.
HTML
+
+ version '3.5' do
+ self.release = '3.5.1'
+ self.dir = '/Users/Thibaut/DevDocs/Docs/Python35' # docs.python.org/3.5/download.html
+ self.base_url = 'https://docs.python.org/3.5/'
+
+ html_filters.push 'python/entries_v3', 'python/clean_html'
+ end
+
+ version '2.7' do
+ self.release = '2.7.10'
+ self.dir = '/Users/Thibaut/DevDocs/Docs/Python27' # docs.python.org/2.7/download.html
+ self.base_url = 'https://docs.python.org/2.7/'
+
+ html_filters.push 'python/entries_v2', 'python/clean_html'
+ end
end
end
diff --git a/lib/docs/scrapers/python2.rb b/lib/docs/scrapers/python2.rb
deleted file mode 100644
index d36452e9..00000000
--- a/lib/docs/scrapers/python2.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-module Docs
- class Python2 < FileScraper
- self.name = 'Python 2'
- self.slug = 'python2'
- self.release = '2.7.10'
- self.type = 'sphinx'
- self.dir = '/Users/Thibaut/DevDocs/Docs/Python2' # downloaded from docs.python.org/2.7/download.html
- self.base_url = 'http://docs.python.org/2.7/'
- self.root_path = 'library/index.html'
-
- html_filters.push 'python2/entries', 'python/clean_html'
-
- options[:only_patterns] = [/\Alibrary\//]
-
- options[:skip] = %w(
- library/2to3.html
- library/formatter.html
- library/index.html
- library/intro.html
- library/undoc.html
- library/unittest.mock-examples.html
- library/sunau.html)
-
- options[:attribution] = <<-HTML
- © 1990–2015 Python Software Foundation
- Licensed under the PSF License.
- HTML
- end
-end
diff --git a/lib/tasks/docs.thor b/lib/tasks/docs.thor
index 8a8beb0d..4445b256 100644
--- a/lib/tasks/docs.thor
+++ b/lib/tasks/docs.thor
@@ -16,11 +16,13 @@ class DocsCLI < Thor
max_length = 0
Docs.all.
map { |doc| [doc.to_s.demodulize.underscore, doc] }.
- each { |pair| max_length = pair.first.length if pair.first.length > max_length }.
- each { |pair| puts "#{pair.first.rjust max_length + 1}: #{pair.second.base_url.remove %r{\Ahttps?://}}" }
+ to_h.
+ each { |name, doc| max_length = name.length if name.length > max_length }.
+ each { |name, doc| puts "#{name.rjust max_length + 1}: #{doc.versions.map { |v| v.release || '-' }.join(', ')}" }
end
- desc 'page [path] [--verbose] [--debug]', 'Generate a page (no indexing)'
+ desc 'page [path] [--version] [--verbose] [--debug]', 'Generate a page (no indexing)'
+ option :version, type: :string
option :verbose, type: :boolean
option :debug, type: :boolean
def page(name, path = '')
@@ -34,16 +36,17 @@ class DocsCLI < Thor
Docs.install_report :filter, :request
end
- if Docs.generate_page(name, path)
+ if Docs.generate_page(name, options[:version], path)
puts 'Done'
else
puts "Failed!#{' (try running with --debug for more information)' unless options[:debug]}"
end
- rescue Docs::DocNotFound
- invalid_doc(name)
+ rescue Docs::DocNotFound => error
+ handle_doc_not_found_error(error)
end
- desc 'generate [--verbose] [--debug] [--force] [--package]', 'Generate a documentation'
+ desc 'generate [--version] [--verbose] [--debug] [--force] [--package]', 'Generate a documentation'
+ option :version, type: :string
option :verbose, type: :boolean
option :debug, type: :boolean
option :force, type: :boolean
@@ -66,18 +69,18 @@ class DocsCLI < Thor
return unless yes? 'Proceed? (y/n)'
end
- if Docs.generate(name)
+ if Docs.generate(name, options[:version])
generate_manifest
if options[:package]
require 'unix_utils'
- package_doc(Docs.find(name))
+ package_doc(Docs.find(name, options[:version]))
end
puts 'Done'
else
puts "Failed!#{' (try running with --debug for more information)' unless options[:debug]}"
end
- rescue Docs::DocNotFound
- invalid_doc(name)
+ rescue Docs::DocNotFound => error
+ handle_doc_not_found_error(error)
end
desc 'manifest', 'Create the manifest'
@@ -86,7 +89,7 @@ class DocsCLI < Thor
puts 'Done'
end
- desc 'download ( ... | --all)', 'Download documentations'
+ desc 'download ( ... | --all)', 'Download documentations'
option :all, type: :boolean
def download(*names)
require 'unix_utils'
@@ -96,10 +99,10 @@ class DocsCLI < Thor
generate_manifest
puts 'Done'
rescue Docs::DocNotFound => error
- invalid_doc(error.name)
+ handle_doc_not_found_error(error)
end
- desc 'package ( ... | --all)', 'Package documentations'
+ desc 'package ( ... | --all)', 'Package documentations'
option :all, type: :boolean
def package(*names)
require 'unix_utils'
@@ -108,7 +111,7 @@ class DocsCLI < Thor
docs.each(&method(:package_doc))
puts 'Done'
rescue Docs::DocNotFound => error
- invalid_doc(error.name)
+ handle_doc_not_found_error(error)
end
desc 'clean', 'Delete documentation packages'
@@ -121,7 +124,8 @@ class DocsCLI < Thor
def find_docs(names)
names.map do |name|
- Docs.find(name)
+ name, version = name.split('@')
+ Docs.find(name, version)
end
end
@@ -133,9 +137,9 @@ class DocsCLI < Thor
end
end
- def invalid_doc(name)
- puts %(ERROR: invalid doc "#{name}".)
- puts 'Run "thor docs:list" to see the list of docs.'
+ def handle_doc_not_found_error(error)
+ puts %(ERROR: #{error}.)
+ puts 'Run "thor docs:list" to see the list of docs and versions.'
end
def download_docs(docs)
diff --git a/test/app_test.rb b/test/app_test.rb
index 94512900..db7d7ba1 100644
--- a/test/app_test.rb
+++ b/test/app_test.rb
@@ -80,11 +80,18 @@ class AppTest < MiniTest::Spec
end
it "works with cookie" do
- set_cookie('docs=css/html')
+ set_cookie('docs=css/html~v5')
get '/manifest.appcache'
assert last_response.ok?
- assert_includes last_response.body, '/css/index.json'
- assert_includes last_response.body, '/html/index.json'
+ assert_includes last_response.body, '/css/index.json?1420139788'
+ assert_includes last_response.body, '/html~v5/index.json?1420139791'
+ end
+
+ it "ignores invalid docs in the cookie" do
+ set_cookie('docs=foo')
+ get '/manifest.appcache'
+ assert last_response.ok?
+ refute_includes last_response.body, 'foo'
end
it "has the word 'default' when no 'dark' cookie is set" do
@@ -120,13 +127,26 @@ class AppTest < MiniTest::Spec
describe "/[doc]" do
it "renders when the doc exists and isn't enabled" do
- set_cookie('docs=css')
- get '/html/', {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
+ set_cookie('docs=html~v5')
+ get '/html~v4/', {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
assert last_response.ok?
end
it "redirects via JS cookie when the doc exists and is enabled" do
- set_cookie('docs=html')
+ set_cookie('docs=html~v5')
+ get '/html~v5/', {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
+ assert last_response.redirect?
+ assert_equal 'http://example.org/', last_response['Location']
+ assert last_response['Set-Cookie'].start_with?("initial_path=%2Fhtml%7Ev5%2F; path=/; expires=")
+ end
+
+ it "renders when the doc exists, has no version in the path, and isn't enabled" do
+ get '/html/', {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
+ assert last_response.ok?
+ end
+
+ it "redirects via JS cookie when the doc exists, has no version in the path, and a version is enabled" do
+ set_cookie('docs=html~v5')
get '/html/', {}, 'HTTP_USER_AGENT' => MODERN_BROWSER
assert last_response.redirect?
assert_equal 'http://example.org/', last_response['Location']
@@ -140,7 +160,7 @@ class AppTest < MiniTest::Spec
end
it "returns 404 when the doc doesn't exist" do
- get '/foo/'
+ get '/html~v6/'
assert last_response.not_found?
end
@@ -157,42 +177,49 @@ class AppTest < MiniTest::Spec
describe "/[doc]-[type]" do
it "works when the doc exists" do
+ get '/html~v4-foo-bar_42/'
+ assert last_response.ok?
+ assert_includes last_response.body, 'app.DOC = {"name":"HTML","slug":"html~v4"'
+ end
+
+ it "works when the doc has no version in the path and a version exists" do
get '/html-foo-bar_42/'
assert last_response.ok?
+ assert_includes last_response.body, 'app.DOC = {"name":"HTML","slug":"html~v5"'
end
it "returns 404 when the type is blank" do
- get '/html-/'
+ get '/css-/'
assert last_response.not_found?
end
it "returns 404 when the type is not alpha-numeric" do
- get '/html-foo:bar/'
+ get '/css-foo:bar/'
assert last_response.not_found?
end
it "returns 404 when the doc doesn't exist" do
- get '/foo-bar/'
+ get '/html~v6-bar/'
assert last_response.not_found?
end
it "redirects with trailing slash" do
- get '/html-foo'
+ get '/css-foo'
assert last_response.redirect?
- assert_equal 'http://example.org/html-foo/', last_response['Location']
+ assert_equal 'http://example.org/css-foo/', last_response['Location']
- get '/html-foo', bar: 'baz'
+ get '/css-foo', bar: 'baz'
assert last_response.redirect?
- assert_equal 'http://example.org/html-foo/?bar=baz', last_response['Location']
+ assert_equal 'http://example.org/css-foo/?bar=baz', last_response['Location']
end
end
describe "/[doc+type]/[path]" do
it "works when the doc exists" do
- get '/html/foo'
+ get '/css/foo'
assert last_response.ok?
- get '/html-bar/foo'
+ get '/css-bar/foo'
assert last_response.ok?
end
@@ -202,13 +229,13 @@ class AppTest < MiniTest::Spec
end
it "redirects without trailing slash" do
- get '/html/foo/'
+ get '/css/foo/'
assert last_response.redirect?
- assert_equal 'http://example.org/html/foo', last_response['Location']
+ assert_equal 'http://example.org/css/foo', last_response['Location']
- get '/html/foo/', bar: 'baz'
+ get '/css/foo/', bar: 'baz'
assert last_response.redirect?
- assert_equal 'http://example.org/html/foo?bar=baz', last_response['Location']
+ assert_equal 'http://example.org/css/foo?bar=baz', last_response['Location']
end
end
diff --git a/test/files/docs.json b/test/files/docs.json
index c010fc0b..c70c2056 100644
--- a/test/files/docs.json
+++ b/test/files/docs.json
@@ -1 +1 @@
-[{"name":"CSS","slug":"css","type":"mdn","release":null,"mtime":1420139788,"db_size":3460507},{"name":"DOM","slug":"dom","type":"mdn","release":null,"mtime":1420139789,"db_size":11399128},{"name":"DOM Events","slug":"dom_events","type":"mdn","release":null,"mtime":1420139790,"db_size":889020},{"name":"HTML","slug":"html","type":"mdn","release":null,"mtime":1420139790,"db_size":1835646},{"name":"HTTP","slug":"http","type":"rfc","release":null,"mtime":1420139790,"db_size":183083},{"name":"JavaScript","slug":"javascript","type":"mdn","release":null,"mtime":1420139791,"db_size":4125477}]
+[{"name":"CSS","slug":"css","type":"mdn","release":null,"mtime":1420139788,"db_size":3460507},{"name":"DOM","slug":"dom","type":"mdn","release":null,"mtime":1420139789,"db_size":11399128},{"name":"DOM Events","slug":"dom_events","type":"mdn","release":null,"mtime":1420139790,"db_size":889020},{"name":"HTML","slug":"html~v5","type":"mdn","version":"5","mtime":1420139791,"db_size":1835647},{"name":"HTML","slug":"html~v4","type":"mdn","version":"4","mtime":1420139790,"db_size":1835646},{"name":"HTTP","slug":"http","type":"rfc","release":null,"mtime":1420139790,"db_size":183083},{"name":"JavaScript","slug":"javascript","type":"mdn","release":null,"mtime":1420139791,"db_size":4125477}]
diff --git a/test/lib/docs/core/doc_test.rb b/test/lib/docs/core/doc_test.rb
index 3e595486..5430a975 100644
--- a/test/lib/docs/core/doc_test.rb
+++ b/test/lib/docs/core/doc_test.rb
@@ -44,6 +44,17 @@ class DocsDocTest < MiniTest::Spec
it "returns 'doc' when the class is Docs::Doc" do
assert_equal 'doc', Docs::Doc.slug
end
+
+ it "returns 'doc~v42' when the class is Docs::Doc and its #version is '42'" do
+ stub(Docs::Doc).version { '42' }
+ assert_equal 'doc~v42', Docs::Doc.slug
+ end
+
+ it "returns 'foo~v42' when #slug has been set to 'foo' and #version to '42'" do
+ doc.slug = 'foo'
+ doc.version = '42'
+ assert_equal 'foo~v42', doc.slug
+ end
end
describe ".slug=" do
@@ -53,6 +64,13 @@ class DocsDocTest < MiniTest::Spec
end
end
+ describe ".version=" do
+ it "stores .version as a string" do
+ doc.version = 4815162342
+ assert_equal '4815162342', doc.version
+ end
+ end
+
describe ".release=" do
it "stores .release" do
doc.release = '1'
@@ -297,4 +315,37 @@ class DocsDocTest < MiniTest::Spec
end
end
end
+
+ describe ".versions" do
+ it "returns [self] if no versions have been created" do
+ assert_equal [doc], doc.versions
+ end
+ end
+
+ describe ".version" do
+ context "with no args" do
+ it "returns @version by default" do
+ doc.version = 'v'
+ assert_equal 'v', doc.version
+ end
+ end
+
+ context "with args" do
+ it "creates a version subclass" do
+ version = doc.version('4') { self.release = '8'}
+
+ assert_equal [version], doc.versions
+
+ assert_nil doc.version
+ assert_nil doc.release
+ refute doc.version?
+
+ assert version.version?
+ assert_equal '4', version.version
+ assert_equal '8', version.release
+ assert_equal 'name', version.name
+ assert_equal 'type', version.type
+ end
+ end
+ end
end
diff --git a/views/app.erb b/views/app.erb
index 29e4cab7..adc1b2af 100644
--- a/views/app.erb
+++ b/views/app.erb
@@ -21,7 +21,7 @@