History

Store docs' metadata in meta.json files

To avoid relying on the filesystem for modified times.

Thibaut Courouble committed 8 years ago

Commit 0725a691 parent ed12d864 files · +48 −60Browse files

Unified · Split

4 files
  1. lib/docs/core/doc.rb +14 −0
  2. lib/docs/core/manifest.rb +3 −21
  3. test/lib/docs/core/doc_test.rb +21 −0
  4. test/lib/docs/core/manifest_test.rb +10 −39
lib/docs/core/doc.rb+14−0
@@ -2,6 +2,7 @@ module Docs · 1 unmodified line
2 class Doc2 class Doc
3 INDEX_FILENAME = 'index.json'3 INDEX_FILENAME = 'index.json'
4 DB_FILENAME = 'db.json'4 DB_FILENAME = 'db.json'
5 META_FILENAME = 'meta.json'
5 6
6 class << self7 class << self
7 include Instrumentable8 include Instrumentable
@@ -73,6 +74,10 @@ module Docs · 65 unmodified lines
73 File.join path, DB_FILENAME74 File.join path, DB_FILENAME
74 end75 end
75 76
77 def meta_path
78 File.join path, META_FILENAME
79 end
80
76 def as_json81 def as_json
77 json = { name: name, slug: slug, type: type }82 json = { name: name, slug: slug, type: type }
78 json[:links] = links if links.present?83 json[:links] = links if links.present?
@@ -107,6 +112,7 @@ module Docs · 28 unmodified lines
107 if index.present?112 if index.present?
108 store_index(store, INDEX_FILENAME, index)113 store_index(store, INDEX_FILENAME, index)
109 store_index(store, DB_FILENAME, pages)114 store_index(store, DB_FILENAME, pages)
115 store_meta(store)
110 true116 true
111 else117 else
112 false118 false
@@ -131,8 +137,16 @@ module Docs · 18 unmodified lines
131 instrument "#{filename.remove('.json')}.doc", before: old_json, after: new_json137 instrument "#{filename.remove('.json')}.doc", before: old_json, after: new_json
132 store.write(filename, new_json)138 store.write(filename, new_json)
133 end139 end
140
141 def store_meta(store)
142 json = as_json
143 json[:mtime] = Time.now.to_i
144 json[:db_size] = store.size(DB_FILENAME)
145 store.write(META_FILENAME, json.to_json)
146 end
134 end147 end
135 148
149
136 def initialize150 def initialize
137 raise NotImplementedError, "#{self.class} is an abstract class and cannot be instantiated." if self.class.abstract151 raise NotImplementedError, "#{self.class} is an abstract class and cannot be instantiated." if self.class.abstract
138 end152 end
lib/docs/core/manifest.rb+3−21
@@ -14,32 +14,14 @@ module Docs · 13 unmodified lines
14 end14 end
15 15
16 def as_json16 def as_json
17 indexed_docs.map do |doc|17 @docs.each_with_object [] do |doc, result|
18 json = doc.as_json18 next unless @store.exist?(doc.meta_path)
19 json[:mtime] = doc_mtime(doc)19 result << JSON.parse(@store.read(doc.meta_path))
20 json[:db_size] = doc_db_size(doc)
21 json
22 end20 end
23 end21 end
24 22
25 def to_json23 def to_json
26 JSON.generate(as_json)24 JSON.generate(as_json)
27 end25 end
28
29 private
30
31 def indexed_docs
32 @docs.select do |doc|
33 @store.exist?(doc.index_path) && @store.exist?(doc.db_path)
34 end
35 end
36
37 def doc_mtime(doc)
38 [@store.mtime(doc.index_path).to_i, @store.mtime(doc.db_path).to_i].max
39 end
40
41 def doc_db_size(doc)
42 @store.size(doc.db_path)
43 end
44 end26 end
45end27end
test/lib/docs/core/doc_test.rb+21−0
@@ -131,6 +131,13 @@ class DocsDocTest < MiniTest::Spec · 130 unmodified lines
131 end131 end
132 end132 end
133 133
134 describe ".meta_path" do
135 it "returns .path + ::META_FILENAME" do
136 stub(doc).path { 'path' }
137 assert_equal File.join('path', Docs::Doc::META_FILENAME), doc.meta_path
138 end
139 end
140
134 describe ".new" do141 describe ".new" do
135 it "raises an error when .abstract is true" do142 it "raises an error when .abstract is true" do
136 doc.abstract = true143 doc.abstract = true
@@ -265,12 +272,14 @@ class DocsDocTest < MiniTest::Spec · 128 unmodified lines
265 mock(store).write(page[:store_path], page[:output])272 mock(store).write(page[:store_path], page[:output])
266 mock(store).write('index.json', anything)273 mock(store).write('index.json', anything)
267 mock(store).write('db.json', anything)274 mock(store).write('db.json', anything)
275 mock(store).write('meta.json', anything)
268 doc.store_pages(store)276 doc.store_pages(store)
269 end277 end
270 278
271 it "stores an index that contains all the pages' entries" do279 it "stores an index that contains all the pages' entries" do
272 stub(store).write(page[:store_path], page[:output])280 stub(store).write(page[:store_path], page[:output])
273 stub(store).write('db.json', anything)281 stub(store).write('db.json', anything)
282 stub(store).write('meta.json', anything)
274 mock(store).write('index.json', anything) do |path, json|283 mock(store).write('index.json', anything) do |path, json|
275 json = JSON.parse(json)284 json = JSON.parse(json)
276 assert_equal pages.length, json['entries'].length285 assert_equal pages.length, json['entries'].length
@@ -282,6 +291,7 @@ class DocsDocTest < MiniTest::Spec · 5 unmodified lines
282 it "stores a db that contains all the pages, indexed by path" do291 it "stores a db that contains all the pages, indexed by path" do
283 stub(store).write(page[:store_path], page[:output])292 stub(store).write(page[:store_path], page[:output])
284 stub(store).write('index.json', anything)293 stub(store).write('index.json', anything)
294 stub(store).write('meta.json', anything)
285 mock(store).write('db.json', anything) do |path, json|295 mock(store).write('db.json', anything) do |path, json|
286 json = JSON.parse(json)296 json = JSON.parse(json)
287 assert_equal page[:output], json[page[:path]]297 assert_equal page[:output], json[page[:path]]
@@ -289,6 +299,17 @@ class DocsDocTest < MiniTest::Spec · 1 unmodified line
289 doc.store_pages(store)299 doc.store_pages(store)
290 end300 end
291 301
302 it "stores a meta file that contains the doc's metadata" do
303 stub(store).write(page[:store_path], page[:output])
304 stub(store).write('index.json', anything)
305 stub(store).write('db.json', anything)
306 mock(store).write('meta.json', anything) do |path, json|
307 json = JSON.parse(json)
308 assert_equal %w(name slug type mtime db_size).sort, json.keys.sort
309 end
310 doc.store_pages(store)
311 end
312
292 it "replaces the .path directory before storing the files" do313 it "replaces the .path directory before storing the files" do
293 stub(doc).path { 'path' }314 stub(doc).path { 'path' }
294 stub(store).write { assert false }315 stub(store).write { assert false }
test/lib/docs/core/manifest_test.rb+10−39
@@ -41,17 +41,12 @@ class ManifestTest < MiniTest::Spec · 40 unmodified lines
41 end41 end
42 42
43 describe "#as_json" do43 describe "#as_json" do
44 let :index_path do44 let :meta_path do
45 'index_path'45 'meta_path'
46 end
47
48 let :db_path do
49 'db_path'
50 end46 end
51 47
52 before do48 before do
53 stub(doc).index_path { index_path }49 stub(doc).meta_path { meta_path }
54 stub(doc).db_path { db_path }
55 end50 end
56 51
57 it "returns an array" do52 it "returns an array" do
@@ -59,46 +54,22 @@ class ManifestTest < MiniTest::Spec · 1 unmodified line
59 assert_instance_of Array, manifest.as_json54 assert_instance_of Array, manifest.as_json
60 end55 end
61 56
62 context "when the doc has an index and a db" do57 context "when the doc has a meta file" do
63 before do58 before do
64 stub(store).exist?(index_path) { true }59 stub(store).exist?(meta_path) { true }
65 stub(store).exist?(db_path) { true }60 stub(store).read(meta_path) { '{"name":"Test"}' }
66 end61 end
67 62
68 it "includes the doc's JSON representation" do63 it "includes the doc's meta representation" do
69 json = manifest.as_json64 json = manifest.as_json
70 assert_equal 1, json.length65 assert_equal 1, json.length
71 assert_empty doc.as_json.keys - json.first.keys66 assert_equal 'Test', json[0]['name']
72 end
73
74 it "adds an :mtime attribute with the greatest of the index and db files' mtime" do
75 mtime_index = Time.now - 1
76 mtime_db = Time.now - 2
77 stub(store).mtime(index_path) { mtime_index }
78 stub(store).mtime(db_path) { mtime_db }
79 assert_equal mtime_index.to_i, manifest.as_json.first[:mtime]
80 mtime_index, mtime_db = mtime_db, mtime_index
81 assert_equal mtime_db.to_i, manifest.as_json.first[:mtime]
82 end
83
84 it "adds a :db_size attribute" do
85 stub(store).size(db_path) { 42 }
86 assert_equal 42, manifest.as_json.first[:db_size]
87 end
88 end
89
90 context "when the doc doesn't have an index" do
91 it "doesn't include the doc" do
92 stub(store).exist?(db_path) { true }
93 stub(store).exist?(index_path) { false }
94 assert_empty manifest.as_json
95 end67 end
96 end68 end
97 69
98 context "when the doc doesn't have a db" do70 context "when the doc doesn't have a meta file" do
99 it "doesn't include the doc" do71 it "doesn't include the doc" do
100 stub(store).exist?(index_path) { true }72 stub(store).exist?(meta_path) { false }
101 stub(store).exist?(db_path) { false }
102 assert_empty manifest.as_json73 assert_empty manifest.as_json
103 end74 end
104 end75 end