document_file 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +29 -19
- data/lib/document_file/collection.rb +16 -0
- data/lib/document_file/version.rb +1 -1
- data/lib/document_file.rb +15 -4
- data/test/document_file_collection_test.rb +29 -6
- data/test/document_file_test.rb +85 -21
- metadata +5 -5
data/README.textile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
h1. Document File
|
2
2
|
|
3
|
-
Document file is an object mapper for plain text documents. The documents look like the ones used in "jekyll":http://github.com/mojombo/jekyll. They consist of a preambel written in YAML (also called YAML front matter), and some content in the format you prefer, e.g. Textile.
|
3
|
+
Document file is an object mapper for plain text documents. The documents look like the ones used in "jekyll":http://github.com/mojombo/jekyll, "toto":http://github.com/cloudhead/toto or "Serious":http://github.com/colszowka/serious. They consist of a preambel written in YAML (also called YAML front matter), and some content in the format you prefer, e.g. Textile. This enables you to write documents in your favorite editor and access the content and metadata in your Ruby scripts.
|
4
4
|
|
5
5
|
|
6
6
|
h2. Example
|
@@ -16,19 +16,20 @@ Documents look somehow like this. The part between the @---@s is the YAML front
|
|
16
16
|
|
17
17
|
<pre><code>---
|
18
18
|
id: 1
|
19
|
-
title:
|
20
|
-
tags: [
|
19
|
+
title: Ruby is great
|
20
|
+
tags: [programming, software]
|
21
21
|
number_of_foos: 42
|
22
22
|
status: published
|
23
23
|
---
|
24
24
|
|
25
|
-
I like
|
25
|
+
I like Ruby.
|
26
26
|
</code></pre>
|
27
27
|
|
28
28
|
|
29
|
-
In order to access the documents in the folder, you have to create a document class that
|
29
|
+
In order to access the documents in the folder, you have to create a document class that includes @DocumentFile@. Inside the class definition, you must set the @documents_dir@ class variable in order to tell Document File where to look for files. In our little example, we will do the following and assume the above file has been saved as @./documents/2010-09-13-ruby-stuff.textile@:
|
30
30
|
|
31
|
-
<pre><code>
|
31
|
+
<pre><code>require 'document_file'
|
32
|
+
class MyDocument
|
32
33
|
include DocumentFile
|
33
34
|
self.documents_dir = './documents'
|
34
35
|
end
|
@@ -39,38 +40,47 @@ h2. Available functionality
|
|
39
40
|
|
40
41
|
h3. Dynamic finders
|
41
42
|
|
42
|
-
<pre><code>doc = MyDocument.find_by_title("
|
43
|
-
doc = MyDocument.find_by_number_of_foos(42)
|
44
|
-
doc = MyDocument.find_by_file_name("
|
43
|
+
<pre><code>doc = MyDocument.find_by_title("Ruby is great") # => returns the document
|
44
|
+
doc = MyDocument.find_by_number_of_foos(42) # => returns the document
|
45
|
+
doc = MyDocument.find_by_file_name("2010-09-13-ruby-stuff") # => returns the document
|
45
46
|
|
46
47
|
docs = MyDocument.find_all_by_status("published") # => [doc_1, doc_2, ...]
|
47
|
-
docs = MyDocument.find_all_by_tag("
|
48
|
+
docs = MyDocument.find_all_by_tag("programming") # => [doc_1, doc_2, ...]
|
48
49
|
</code></pre>
|
49
50
|
|
50
51
|
|
51
52
|
h3. Listing documents by Array attributes
|
52
53
|
|
53
54
|
<pre><code>docs = MyDocument.by_tags
|
54
|
-
# => Returns {"
|
55
|
+
# => Returns {"programming" => [doc_1, doc_2, ...], "software" => [doc_1, doc_3, ...], ...}
|
55
56
|
</code></pre>
|
56
57
|
|
57
58
|
|
59
|
+
h3. Listing documents by the date attribute
|
60
|
+
|
61
|
+
Document file tries to parse the filename of your documents to create a date attribute. In order to use the automatic parsing, the filenames have to start with a date string, e.g. @2010-09-13-ruby-stuff.textile@. If you don't want to set the date in the filename, you can still do it in the YAML front matter with e.g. @date: 2010-09-10@.
|
62
|
+
|
63
|
+
<pre><code>docs = MyDocument.find_all_by_date(2010) # => returns all documents from 2010
|
64
|
+
docs = MyDocument.find_all_by_date(2010, 9) # => returns all documents from Sep., 2010
|
65
|
+
docs = MyDocument.find_all_by_date(2010, 9, 13) # => returns all documents from Sep. 13th, 2010
|
66
|
+
</code></pre>
|
67
|
+
|
58
68
|
h3. Chaining
|
59
69
|
|
60
70
|
<pre><code>docs = MyDocument.find_all_by_status("published").by_tags
|
61
|
-
# => Returns {"
|
62
|
-
docs = MyDocument.find_all_by_status("published").find_all_by_tag("
|
71
|
+
# => Returns {"programming" => [doc_1, doc_2, ...], ...}
|
72
|
+
docs = MyDocument.find_all_by_status("published").find_all_by_tag("programming")
|
63
73
|
# => Returns [doc_1, doc_2, ...]
|
64
74
|
</code></pre>
|
65
75
|
|
66
76
|
|
67
77
|
h3. Accessing the attributes of single documents
|
68
78
|
|
69
|
-
<pre><code>doc.title # => "
|
70
|
-
doc.tags # => ["
|
71
|
-
doc.content # => "I like
|
72
|
-
doc.
|
73
|
-
doc.file_name_with_extension # => "
|
79
|
+
<pre><code>doc.title # => "Ruby is great"
|
80
|
+
doc.tags # => ["programming", "software"]
|
81
|
+
doc.content # => "I like Ruby."
|
82
|
+
doc.file_name # => "2010-08-12-my-post"
|
83
|
+
doc.file_name_with_extension # => "2010-08-12-my-post.textile"
|
74
84
|
doc.file_extension # => ".textile"
|
75
85
|
</code></pre>
|
76
86
|
|
@@ -91,4 +101,4 @@ If any of the files change, you must manually reload them:
|
|
91
101
|
h2. Author
|
92
102
|
|
93
103
|
Written by "Ralph von der Heyden":http://rvdh.de. Don't hesitate to contact me if you have any further questions.
|
94
|
-
Follow me on "Twitter":http://twitter.com/ralph
|
104
|
+
Follow me on "Twitter":http://twitter.com/ralph!
|
@@ -14,6 +14,7 @@ module DocumentFile
|
|
14
14
|
collection.each do |document|
|
15
15
|
self.ensure_document(document)
|
16
16
|
attributes_hash = document.data.merge({'file_name' => document.file_name})
|
17
|
+
attributes_hash.delete 'date'
|
17
18
|
collection.define_dynamic_finders attributes_hash
|
18
19
|
end
|
19
20
|
collection
|
@@ -27,6 +28,21 @@ module DocumentFile
|
|
27
28
|
raise ArgumentError unless document.class.include? DocumentFile
|
28
29
|
end
|
29
30
|
|
31
|
+
def find_all_by_date(*args)
|
32
|
+
return if args.size == 0
|
33
|
+
|
34
|
+
date_parts = %w(year month day)
|
35
|
+
docs = self
|
36
|
+
args.size.times do |i|
|
37
|
+
docs = docs.select { |doc| doc.date.send(date_parts[i]) == args[i] }
|
38
|
+
end
|
39
|
+
self.class.new docs
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_by_date(*args)
|
43
|
+
find_all_by_date(*args).first
|
44
|
+
end
|
45
|
+
|
30
46
|
def define_dynamic_finders(attributes_hash)
|
31
47
|
attributes_hash.each do |attribute, value|
|
32
48
|
define_find_all_by attribute, value
|
data/lib/document_file.rb
CHANGED
@@ -15,7 +15,11 @@ module DocumentFile
|
|
15
15
|
attr_reader :content, :file_path, :data
|
16
16
|
|
17
17
|
def initialize(new_file_path)
|
18
|
-
@file_path = new_file_path
|
18
|
+
@file_path = if File.exist? new_file_path
|
19
|
+
new_file_path
|
20
|
+
else
|
21
|
+
[self.documents_dir, new_file_path].join('/')
|
22
|
+
end
|
19
23
|
read_yaml
|
20
24
|
end
|
21
25
|
|
@@ -40,12 +44,19 @@ private
|
|
40
44
|
@data = YAML.load($1)
|
41
45
|
end
|
42
46
|
@data ||= {}
|
47
|
+
if !@data.has_key? 'date'
|
48
|
+
begin
|
49
|
+
match = File.basename(@file_path).match(/(\d{4})-(\d{1,2})-(\d{1,2}).*/)
|
50
|
+
@data['date'] = Date.new(match[1].to_i, match[2].to_i, match[3].to_i)
|
51
|
+
rescue NoMethodError => err
|
52
|
+
end
|
53
|
+
end
|
43
54
|
define_dynamic_methods
|
44
55
|
end
|
45
56
|
|
46
57
|
def define_dynamic_methods
|
47
|
-
@data.each do |
|
48
|
-
attribute_reader = "def #{
|
58
|
+
@data.each do |attribute, value|
|
59
|
+
attribute_reader = "def #{attribute}; @data['#{attribute}']; end"
|
49
60
|
self.class.module_eval attribute_reader
|
50
61
|
end
|
51
62
|
end
|
@@ -61,7 +72,7 @@ private
|
|
61
72
|
def reload!
|
62
73
|
if File.directory?(documents_dir)
|
63
74
|
file_paths = Dir.glob("#{documents_dir}/*.*")
|
64
|
-
@@documents = Collection.new file_paths.map { |
|
75
|
+
@@documents = Collection.new file_paths.map { |fp| self.new fp }
|
65
76
|
else
|
66
77
|
[]
|
67
78
|
end
|
@@ -4,9 +4,7 @@ describe DocumentFile::Collection do
|
|
4
4
|
describe 'when adding documents to the collection' do
|
5
5
|
before do
|
6
6
|
@collection = DocumentFile::Collection.new
|
7
|
-
@document = MyDocument.new(
|
8
|
-
TEST_DIR + '/documents/2010-08-08-test-document-file.textile'
|
9
|
-
)
|
7
|
+
@document = MyDocument.new('2010-08-08-test-document-file.textile')
|
10
8
|
end
|
11
9
|
|
12
10
|
it 'should not accept non-documents' do
|
@@ -62,11 +60,36 @@ describe DocumentFile::Collection do
|
|
62
60
|
end
|
63
61
|
|
64
62
|
it 'should accept documents' do
|
65
|
-
document = MyDocument.new
|
66
|
-
TEST_DIR + '/documents/2010-08-08-test-document-file.textile'
|
67
|
-
)
|
63
|
+
document = MyDocument.new '2010-08-08-test-document-file.textile'
|
68
64
|
collection = DocumentFile::Collection.new [document]
|
69
65
|
assert document, collection.first
|
70
66
|
end
|
71
67
|
end
|
68
|
+
|
69
|
+
describe 'when finding documents by date' do
|
70
|
+
it 'should return a collection' do
|
71
|
+
documents = MyDocument.find_all_by_date 2010
|
72
|
+
assert_equal documents.class, DocumentFile::Collection
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should return all documents with the year specified' do
|
76
|
+
documents = MyDocument.find_all_by_date 2010
|
77
|
+
assert_equal 2, documents.size
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should return all documents with the year and month specified' do
|
81
|
+
documents = MyDocument.find_all_by_date 2010, 8
|
82
|
+
assert_equal 2, documents.size
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should return all documents with the year, month and day specified' do
|
86
|
+
documents = MyDocument.find_all_by_date 2010, 8, 8
|
87
|
+
assert_equal 1, documents.size
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should return the first match' do
|
91
|
+
document = MyDocument.find_by_date 2010, 8
|
92
|
+
assert_equal 1, document.id
|
93
|
+
end
|
94
|
+
end
|
72
95
|
end
|
data/test/document_file_test.rb
CHANGED
@@ -17,9 +17,7 @@ describe MyDocument do
|
|
17
17
|
|
18
18
|
describe 'when initializing a MyDocument' do
|
19
19
|
before do
|
20
|
-
@document_file = MyDocument.new(
|
21
|
-
TEST_DIR + '/documents/2010-08-08-test-document-file.textile'
|
22
|
-
)
|
20
|
+
@document_file = MyDocument.new('2010-08-08-test-document-file.textile')
|
23
21
|
end
|
24
22
|
|
25
23
|
it 'should know the documents_dir' do
|
@@ -44,6 +42,68 @@ describe MyDocument do
|
|
44
42
|
assert_equal Fixnum, @document_file.number_of_foos.class
|
45
43
|
assert_equal 42, @document_file.number_of_foos
|
46
44
|
end
|
45
|
+
|
46
|
+
it 'should work with absolute path' do
|
47
|
+
document_file = MyDocument.new(
|
48
|
+
TEST_DIR + '/documents/2010-08-08-test-document-file.textile'
|
49
|
+
)
|
50
|
+
assert_equal MyDocument, document_file.class
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'when initializing the date' do
|
55
|
+
after do
|
56
|
+
remove_document @file_name if @file_name
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should initialize the date from the filename' do
|
60
|
+
document_file = MyDocument.new '2010-08-08-test-document-file.textile'
|
61
|
+
assert_equal Date.new(2010, 8, 8), document_file.date
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should initialize the date from the YAML front matter' do
|
65
|
+
@file_name = 'date-test-1.textile'
|
66
|
+
add_document @file_name, <<-eos
|
67
|
+
---
|
68
|
+
id: 5
|
69
|
+
title: Date test 1
|
70
|
+
date: 2010-09-10
|
71
|
+
---
|
72
|
+
|
73
|
+
I like the dates.
|
74
|
+
eos
|
75
|
+
document_file = MyDocument.new @file_name
|
76
|
+
assert_equal Date.new(2010, 9, 10), document_file.date
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should prefer the date from the YAML front matter' do
|
80
|
+
@file_name = '2010-08-15-date-test-1.textile'
|
81
|
+
add_document @file_name, <<-eos
|
82
|
+
---
|
83
|
+
id: 5
|
84
|
+
title: Date test 2
|
85
|
+
date: 2010-08-20
|
86
|
+
---
|
87
|
+
|
88
|
+
I like the dates.
|
89
|
+
eos
|
90
|
+
document_file = MyDocument.new @file_name
|
91
|
+
assert_equal Date.new(2010, 8, 20), document_file.date
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should not set a date if neither filename nor YAML date is set' do
|
95
|
+
@file_name = 'date-test-1.textile'
|
96
|
+
add_document @file_name, <<-eos
|
97
|
+
---
|
98
|
+
id: 5
|
99
|
+
title: Date test 3
|
100
|
+
---
|
101
|
+
|
102
|
+
I like the dates.
|
103
|
+
eos
|
104
|
+
document_file = MyDocument.new @file_name
|
105
|
+
assert_nil document_file.date
|
106
|
+
end
|
47
107
|
end
|
48
108
|
|
49
109
|
describe 'when listing document_files by an Array attribute' do
|
@@ -130,30 +190,31 @@ describe MyDocument do
|
|
130
190
|
|
131
191
|
describe 'when getting the file name or file path' do
|
132
192
|
before do
|
133
|
-
@
|
193
|
+
@file_name = '2010-08-08-test-document-file.textile'
|
134
194
|
end
|
135
195
|
|
136
196
|
it 'should show the right file name' do
|
137
|
-
document_file = MyDocument.new @
|
197
|
+
document_file = MyDocument.new @file_name
|
138
198
|
file_name = '2010-08-08-test-document-file'
|
139
199
|
assert_equal file_name, document_file.file_name
|
140
200
|
end
|
141
201
|
|
142
202
|
it 'should show the right file name with extension' do
|
143
|
-
document_file = MyDocument.new @
|
203
|
+
document_file = MyDocument.new @file_name
|
144
204
|
file_name = '2010-08-08-test-document-file.textile'
|
145
205
|
assert_equal file_name, document_file.file_name_with_extension
|
146
206
|
end
|
147
207
|
|
148
208
|
it 'should show the right extension' do
|
149
|
-
document_file = MyDocument.new @
|
209
|
+
document_file = MyDocument.new @file_name
|
150
210
|
extension = '.textile'
|
151
211
|
assert_equal extension, document_file.file_extension
|
152
212
|
end
|
153
213
|
|
154
214
|
it 'should show the right file path' do
|
155
|
-
document_file = MyDocument.new @
|
156
|
-
|
215
|
+
document_file = MyDocument.new @file_name
|
216
|
+
expected_path = [MyDocument.documents_dir, @file_name].join('/')
|
217
|
+
assert_equal expected_path, document_file.file_path
|
157
218
|
end
|
158
219
|
end
|
159
220
|
|
@@ -177,6 +238,7 @@ describe MyDocument do
|
|
177
238
|
@document_files_before = MyDocument.all
|
178
239
|
@tmp_dir = "#{@default_dir}-#{Time.now.to_i}-#{rand(999999)}-test"
|
179
240
|
FileUtils.cp_r @default_dir, @tmp_dir
|
241
|
+
MyDocument.documents_dir = @tmp_dir
|
180
242
|
end
|
181
243
|
|
182
244
|
after do
|
@@ -184,7 +246,7 @@ describe MyDocument do
|
|
184
246
|
end
|
185
247
|
|
186
248
|
it 'should get updated document_files' do
|
187
|
-
|
249
|
+
add_document '2010-08-08-test-document-file.textile', <<-eos
|
188
250
|
---
|
189
251
|
id: 1
|
190
252
|
title: The shuzzle!
|
@@ -194,9 +256,6 @@ number_of_foos: 48
|
|
194
256
|
|
195
257
|
I like the foos.
|
196
258
|
eos
|
197
|
-
document_file_file_name = "#{@tmp_dir}/2010-08-08-test-document-file.textile"
|
198
|
-
File.open(document_file_file_name, 'w') {|f| f.write(updated_document_file) }
|
199
|
-
MyDocument.documents_dir = @tmp_dir
|
200
259
|
MyDocument.reload!
|
201
260
|
document_files_after = MyDocument.all
|
202
261
|
|
@@ -208,7 +267,7 @@ eos
|
|
208
267
|
end
|
209
268
|
|
210
269
|
it 'should get new document_files' do
|
211
|
-
|
270
|
+
add_document '2010-08-15-new-test-document_file.textile', <<-eos
|
212
271
|
---
|
213
272
|
id: 3
|
214
273
|
title: The shuzzle!
|
@@ -218,9 +277,6 @@ number_of_foos: 48
|
|
218
277
|
|
219
278
|
I like the cows.
|
220
279
|
eos
|
221
|
-
document_file_file_name = "#{@tmp_dir}/2010-08-15-new-test-document_file.textile"
|
222
|
-
File.open(document_file_file_name, 'w') {|f| f.write(new_document_file) }
|
223
|
-
MyDocument.documents_dir = @tmp_dir
|
224
280
|
MyDocument.reload!
|
225
281
|
document_files_after = MyDocument.all
|
226
282
|
|
@@ -236,13 +292,21 @@ eos
|
|
236
292
|
end
|
237
293
|
|
238
294
|
it 'should not show deleted document_files' do
|
239
|
-
|
240
|
-
FileUtils.rm document_file_file_name
|
241
|
-
MyDocument.documents_dir = @tmp_dir
|
295
|
+
remove_document '2010-08-08-test-document-file.textile' # has id 1
|
242
296
|
MyDocument.reload!
|
243
297
|
document_files_after = MyDocument.all
|
244
|
-
|
298
|
+
refute document_files_after.map(&:id).include? 1
|
245
299
|
end
|
246
300
|
end
|
301
|
+
|
302
|
+
def add_document(file_name, content)
|
303
|
+
complete_file_name = [MyDocument.documents_dir, file_name].join('/')
|
304
|
+
File.open(complete_file_name, 'w') {|f| f.write(content) }
|
305
|
+
end
|
306
|
+
|
307
|
+
def remove_document(file_name)
|
308
|
+
complete_file_name = [MyDocument.documents_dir, file_name].join('/')
|
309
|
+
FileUtils.rm complete_file_name if File.exist? complete_file_name
|
310
|
+
end
|
247
311
|
end
|
248
312
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 6
|
9
|
+
version: 0.0.6
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ralph von der Heyden
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-09-
|
17
|
+
date: 2010-09-08 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 3.0.0
|
33
33
|
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
|
-
description: "
|
35
|
+
description: " Document file is an object mapper for plain text documents. The documents look like the ones used in jekyll (http://github.com/mojombo/jekyll). They consist of a preambel written in YAML (also called YAML front matter), and some content in the format you prefer, e.g. Textile. This enables you to write documents in your favorite editor and access the content and metadata of these in your Ruby scripts.\n"
|
36
36
|
email: ralph@rvdh.de
|
37
37
|
executables: []
|
38
38
|
|
@@ -82,6 +82,6 @@ rubyforge_project:
|
|
82
82
|
rubygems_version: 1.3.7
|
83
83
|
signing_key:
|
84
84
|
specification_version: 3
|
85
|
-
summary:
|
85
|
+
summary: Document file is an object mapper for plain text documents.
|
86
86
|
test_files: []
|
87
87
|
|