Store docs' metadata in meta.json files

To avoid relying on the filesystem for modified times.
This commit is contained in:
Thibaut Courouble 2018-03-25 14:52:16 -04:00
parent ed12d86e56
commit 0725a69af5
4 changed files with 48 additions and 60 deletions

View file

@ -2,6 +2,7 @@ module Docs
class Doc
INDEX_FILENAME = 'index.json'
DB_FILENAME = 'db.json'
META_FILENAME = 'meta.json'
class << self
include Instrumentable
@ -73,6 +74,10 @@ module Docs
File.join path, DB_FILENAME
end
def meta_path
File.join path, META_FILENAME
end
def as_json
json = { name: name, slug: slug, type: type }
json[:links] = links if links.present?
@ -107,6 +112,7 @@ module Docs
if index.present?
store_index(store, INDEX_FILENAME, index)
store_index(store, DB_FILENAME, pages)
store_meta(store)
true
else
false
@ -131,8 +137,16 @@ module Docs
instrument "#{filename.remove('.json')}.doc", before: old_json, after: new_json
store.write(filename, new_json)
end
def store_meta(store)
json = as_json
json[:mtime] = Time.now.to_i
json[:db_size] = store.size(DB_FILENAME)
store.write(META_FILENAME, json.to_json)
end
end
def initialize
raise NotImplementedError, "#{self.class} is an abstract class and cannot be instantiated." if self.class.abstract
end

View file

@ -14,32 +14,14 @@ module Docs
end
def as_json
indexed_docs.map do |doc|
json = doc.as_json
json[:mtime] = doc_mtime(doc)
json[:db_size] = doc_db_size(doc)
json
@docs.each_with_object [] do |doc, result|
next unless @store.exist?(doc.meta_path)
result << JSON.parse(@store.read(doc.meta_path))
end
end
def to_json
JSON.generate(as_json)
end
private
def indexed_docs
@docs.select do |doc|
@store.exist?(doc.index_path) && @store.exist?(doc.db_path)
end
end
def doc_mtime(doc)
[@store.mtime(doc.index_path).to_i, @store.mtime(doc.db_path).to_i].max
end
def doc_db_size(doc)
@store.size(doc.db_path)
end
end
end

View file

@ -131,6 +131,13 @@ class DocsDocTest < MiniTest::Spec
end
end
describe ".meta_path" do
it "returns .path + ::META_FILENAME" do
stub(doc).path { 'path' }
assert_equal File.join('path', Docs::Doc::META_FILENAME), doc.meta_path
end
end
describe ".new" do
it "raises an error when .abstract is true" do
doc.abstract = true
@ -265,12 +272,14 @@ class DocsDocTest < MiniTest::Spec
mock(store).write(page[:store_path], page[:output])
mock(store).write('index.json', anything)
mock(store).write('db.json', anything)
mock(store).write('meta.json', anything)
doc.store_pages(store)
end
it "stores an index that contains all the pages' entries" do
stub(store).write(page[:store_path], page[:output])
stub(store).write('db.json', anything)
stub(store).write('meta.json', anything)
mock(store).write('index.json', anything) do |path, json|
json = JSON.parse(json)
assert_equal pages.length, json['entries'].length
@ -282,6 +291,7 @@ class DocsDocTest < MiniTest::Spec
it "stores a db that contains all the pages, indexed by path" do
stub(store).write(page[:store_path], page[:output])
stub(store).write('index.json', anything)
stub(store).write('meta.json', anything)
mock(store).write('db.json', anything) do |path, json|
json = JSON.parse(json)
assert_equal page[:output], json[page[:path]]
@ -289,6 +299,17 @@ class DocsDocTest < MiniTest::Spec
doc.store_pages(store)
end
it "stores a meta file that contains the doc's metadata" do
stub(store).write(page[:store_path], page[:output])
stub(store).write('index.json', anything)
stub(store).write('db.json', anything)
mock(store).write('meta.json', anything) do |path, json|
json = JSON.parse(json)
assert_equal %w(name slug type mtime db_size).sort, json.keys.sort
end
doc.store_pages(store)
end
it "replaces the .path directory before storing the files" do
stub(doc).path { 'path' }
stub(store).write { assert false }

View file

@ -41,17 +41,12 @@ class ManifestTest < MiniTest::Spec
end
describe "#as_json" do
let :index_path do
'index_path'
end
let :db_path do
'db_path'
let :meta_path do
'meta_path'
end
before do
stub(doc).index_path { index_path }
stub(doc).db_path { db_path }
stub(doc).meta_path { meta_path }
end
it "returns an array" do
@ -59,46 +54,22 @@ class ManifestTest < MiniTest::Spec
assert_instance_of Array, manifest.as_json
end
context "when the doc has an index and a db" do
context "when the doc has a meta file" do
before do
stub(store).exist?(index_path) { true }
stub(store).exist?(db_path) { true }
stub(store).exist?(meta_path) { true }
stub(store).read(meta_path) { '{"name":"Test"}' }
end
it "includes the doc's JSON representation" do
it "includes the doc's meta representation" do
json = manifest.as_json
assert_equal 1, json.length
assert_empty doc.as_json.keys - json.first.keys
end
it "adds an :mtime attribute with the greatest of the index and db files' mtime" do
mtime_index = Time.now - 1
mtime_db = Time.now - 2
stub(store).mtime(index_path) { mtime_index }
stub(store).mtime(db_path) { mtime_db }
assert_equal mtime_index.to_i, manifest.as_json.first[:mtime]
mtime_index, mtime_db = mtime_db, mtime_index
assert_equal mtime_db.to_i, manifest.as_json.first[:mtime]
end
it "adds a :db_size attribute" do
stub(store).size(db_path) { 42 }
assert_equal 42, manifest.as_json.first[:db_size]
assert_equal 'Test', json[0]['name']
end
end
context "when the doc doesn't have an index" do
context "when the doc doesn't have a meta file" do
it "doesn't include the doc" do
stub(store).exist?(db_path) { true }
stub(store).exist?(index_path) { false }
assert_empty manifest.as_json
end
end
context "when the doc doesn't have a db" do
it "doesn't include the doc" do
stub(store).exist?(index_path) { true }
stub(store).exist?(db_path) { false }
stub(store).exist?(meta_path) { false }
assert_empty manifest.as_json
end
end