document_mapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Ralph von der Heyden
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,120 @@
1
+ h1. Document Mapper
2
+
3
+ Document mapper 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
+
5
+
6
+ h2. Step-by-step tutorial
7
+
8
+ Documents look somehow like this. The part between the @---@s is the YAML front matter. After the second @---@, there is one blank line, followed by the content of the file. All items in the YAML front matter and the content are accessible by Document Mapper.
9
+
10
+ <pre><code>---
11
+ id: 1
12
+ title: Ruby is great
13
+ tags: [programming, software]
14
+ number_of_foos: 42
15
+ status: published
16
+ ---
17
+
18
+ I like Ruby.
19
+ </code></pre>
20
+
21
+
22
+ In order to access the values in the front matter, you have to create a class that includes @DocumentMapper@.
23
+
24
+ <pre><code>require 'document_mapper'
25
+ class MyDocument
26
+ include DocumentMapper::Document
27
+ end
28
+ </code></pre>
29
+
30
+
31
+ h3. Initializing single documents
32
+
33
+ <pre><code>doc = MyDocument.from_file('./documents/document-file.textile')
34
+ </code></pre>
35
+
36
+
37
+ h3. Accessing the attributes of single documents
38
+
39
+ <pre><code>doc.title # => "Ruby is great"
40
+ doc.tags # => ["programming", "software"]
41
+ doc.content # => "I like Ruby."
42
+ </code></pre>
43
+
44
+
45
+ h3. Date recognition
46
+
47
+ You can either set the date of a document in the YAML front matter, or you can use the file name, if you want to. A file named @2010-08-07-test-document-file.textile@ will return a date like this:
48
+
49
+ <pre><code>doc.date # => #<Date: 2010-08-08 (4910833/2,0,2299161)>
50
+ doc.date.to_s # => "2010-08-08"
51
+ doc.year # => 2010
52
+ doc.month # => 08
53
+ doc.day # => 07
54
+ </code></pre>
55
+
56
+
57
+ h3. Working with directories
58
+
59
+ As an example let's assume we have a directory called "documents" containing the following files:
60
+
61
+ <pre><code>documents/
62
+ |-foo.textile
63
+ |-bar.textile
64
+ </code></pre>
65
+
66
+
67
+ In order to work with a whole directory of files, we have to use the @directory@ method:
68
+
69
+ <pre><code>require 'document_mapper'
70
+ class MyDocument
71
+ include DocumentMapper::Document
72
+ self.directory = 'documents'
73
+ end
74
+ </code></pre>
75
+
76
+ Now we can receive all available documents or filter like that:
77
+
78
+ <pre><code>MyDocument.all
79
+ MyDocument.first
80
+ MyDocument.last
81
+ MyDocument.limit(2)
82
+ MyDocument.offset(2)
83
+ MyDocument.where(:title => 'Some title').first
84
+ MyDocument.where(:status => 'published').all
85
+ MyDocument.where(:year => 2010).all
86
+ </code></pre>
87
+
88
+ Not all of the documents in the directory need to have all of the attributes. You can add single attributes to single documents, and the queries will only return those documents where the attributes match.
89
+
90
+ The document queries do support more operators than just equality. The following operators are available:
91
+
92
+ <pre><code>MyDocument.where(:year.gt => 2010)
93
+ MyDocument.where(:year.gte => 2010)
94
+ MyDocument.where(:year.in => [2010,2011])
95
+ MyDocument.where(:year.lt => 2010)
96
+ MyDocument.where(:year.lte => 2010)
97
+ </code></pre>
98
+
99
+
100
+ h3. Chaining
101
+
102
+ Chaining works with all available query methods, e.g.:
103
+
104
+ <pre><code>MyDocument.where(:status => 'published').where(:title => 'Some title').limit(2).all
105
+ </code></pre>
106
+
107
+
108
+ h3. Reloading
109
+
110
+ If any of the files change, you must manually reload them:
111
+
112
+ <pre><code>MyDocument.reload
113
+ </code></pre>
114
+
115
+
116
+ h2. Author
117
+
118
+ Written by "Ralph von der Heyden":http://rvdh.de. Don't hesitate to contact me if you have any further questions.
119
+
120
+ Follow me on "Twitter":http://twitter.com/ralph!
@@ -0,0 +1,14 @@
1
+ require 'active_support/core_ext/class'
2
+ require 'active_support/concern'
3
+ require 'yaml'
4
+
5
+ require 'document_mapper/constants'
6
+ require 'document_mapper/errors'
7
+ require 'document_mapper/attribute_methods'
8
+ require 'document_mapper/yaml_parsing'
9
+ require 'document_mapper/document'
10
+ require 'document_mapper/query'
11
+ require 'document_mapper/selector'
12
+ require 'document_mapper/version'
13
+
14
+ require 'document_mapper/core_ext/symbol'
@@ -0,0 +1,25 @@
1
+ module DocumentMapper
2
+ module AttributeMethods
3
+ module Read
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # Undefine id so it can be used as an attribute name
8
+ undef_method(:id) if method_defined?(:id)
9
+ end
10
+
11
+ module ClassMethods
12
+ def define_read_method(attr_name)
13
+ access_code = "attributes['#{attr_name}']"
14
+ generated_attribute_methods.module_eval("def #{attr_name}; #{access_code}; end", __FILE__, __LINE__)
15
+
16
+ %w(year month day).each do |attr_name|
17
+ access_code = "date.#{attr_name} if date"
18
+ generated_attribute_methods.module_eval("def #{attr_name}; #{access_code}; end", __FILE__, __LINE__)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ module DocumentMapper
2
+ REVERSE_OPERATOR_MAPPING = {
3
+ 'equal' => :==,
4
+ 'gt' => :<,
5
+ 'gte' => :<=,
6
+ 'in' => :include?,
7
+ 'lt' => :>,
8
+ 'lte' => :>=
9
+ }
10
+
11
+ VALID_OPERATORS = REVERSE_OPERATOR_MAPPING.keys
12
+ end
@@ -0,0 +1,9 @@
1
+ class Symbol
2
+ DocumentMapper::VALID_OPERATORS.each do |operator|
3
+ class_eval <<-OPERATORS
4
+ def #{operator}
5
+ Selector.new(:attribute => self, :operator => '#{operator}')
6
+ end
7
+ OPERATORS
8
+ end
9
+ end
@@ -0,0 +1,94 @@
1
+ require 'active_model'
2
+
3
+ module DocumentMapper
4
+ module Document
5
+ extend ActiveSupport::Concern
6
+ include ActiveModel::AttributeMethods
7
+ include AttributeMethods::Read
8
+ include YamlParsing
9
+
10
+ attr_accessor :attributes, :content, :directory, :file_path
11
+
12
+ included do
13
+ @@documents = []
14
+ end
15
+
16
+ def ==(other_document)
17
+ return false unless other_document.is_a? Document
18
+ self.file_path == other_document.file_path
19
+ end
20
+
21
+ module ClassMethods
22
+ def reset
23
+ @@documents = []
24
+ end
25
+
26
+ def reload
27
+ self.reset
28
+ self.directory = @@directory
29
+ end
30
+
31
+ def from_file(file_path)
32
+ if !File.exist? file_path
33
+ raise FileNotFoundError
34
+ end
35
+ self.new.tap do |document|
36
+ document.file_path = File.expand_path(file_path)
37
+ document.read_yaml
38
+ @@documents << document
39
+ end
40
+ end
41
+
42
+ def directory=(new_directory)
43
+ raise FileNotFoundError unless File.directory?(new_directory)
44
+ self.reset
45
+ @@directory = Dir.new File.expand_path(new_directory)
46
+ @@directory.each do |file|
47
+ next if ['.', '..'].include? file
48
+ self.from_file [@@directory.path, file].join('/')
49
+ end
50
+ end
51
+
52
+ def select(options = {})
53
+ documents = @@documents.dup
54
+ options[:where].each do |selector, selector_value|
55
+ documents.select! do |document|
56
+ next unless document.respond_to? selector.attribute
57
+ document_value = document.send(selector.attribute)
58
+ operator = REVERSE_OPERATOR_MAPPING[selector.operator]
59
+ selector_value.send operator, document_value
60
+ end
61
+ end
62
+ documents
63
+ end
64
+
65
+ def where(hash)
66
+ Query.new(self).where(hash)
67
+ end
68
+
69
+ def sort(field)
70
+ Query.new(self).sort(field)
71
+ end
72
+
73
+ def offset(number)
74
+ Query.new(self).offset(number)
75
+ end
76
+
77
+ def limit(number)
78
+ Query.new(self).limit(number)
79
+ end
80
+
81
+ def all
82
+ @@documents
83
+ end
84
+
85
+ def first
86
+ @@documents.first
87
+ end
88
+
89
+ def last
90
+ @@documents.last
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,4 @@
1
+ module DocumentMapper
2
+ FileNotFoundError = Class.new StandardError
3
+ OperatorNotSupportedError = Class.new StandardError
4
+ end
@@ -0,0 +1,54 @@
1
+ module DocumentMapper
2
+ class Query
3
+ def initialize(model)
4
+ @model = model
5
+ @where = {}
6
+ end
7
+
8
+ def where(constraints_hash)
9
+ differentiator = ->(key, value){ key.is_a? Selector }
10
+ selector_hash = constraints_hash.select &differentiator
11
+ symbol_hash = constraints_hash.reject &differentiator
12
+ symbol_hash.each do |attribute, value|
13
+ selector = Selector.new(:attribute => attribute, :operator => 'equal')
14
+ selector_hash.update({ selector => value })
15
+ end
16
+ @where.merge! selector_hash
17
+ self
18
+ end
19
+
20
+ def sort(field)
21
+ @sort = field
22
+ self
23
+ end
24
+
25
+ def offset(number)
26
+ @offset = number
27
+ self
28
+ end
29
+
30
+ def limit(number)
31
+ @limit = number
32
+ self
33
+ end
34
+
35
+ def first
36
+ self.all.first
37
+ end
38
+
39
+ def last
40
+ self.all.last
41
+ end
42
+
43
+ def all
44
+ result = @model.select(:where => @where, :sort => @sort)
45
+ if @offset.present?
46
+ result = result.last(result.size - @offset)
47
+ end
48
+ if @limit.present?
49
+ result = result.first(@limit)
50
+ end
51
+ result
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ module DocumentMapper
2
+ class Selector
3
+ attr_reader :attribute, :operator
4
+
5
+ def initialize(opts = {})
6
+ unless VALID_OPERATORS.include? opts[:operator]
7
+ raise OperatorNotSupportedError
8
+ end
9
+ @attribute, @operator = opts[:attribute], opts[:operator]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module DocumentMapper
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,24 @@
1
+ module DocumentMapper
2
+ module YamlParsing
3
+ def read_yaml
4
+ @content = File.read(file_path)
5
+
6
+ if @content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
7
+ @content = @content[($1.size + $2.size)..-1]
8
+ self.attributes = YAML.load($1)
9
+ end
10
+
11
+ self.attributes ||= {}
12
+ if !self.attributes.has_key? 'date'
13
+ begin
14
+ match = File.basename(@file_path).match(/(\d{4})-(\d{1,2})-(\d{1,2}).*/)
15
+ self.attributes['date'] = Date.new(match[1].to_i, match[2].to_i, match[3].to_i)
16
+ rescue NoMethodError => err
17
+ end
18
+ end
19
+
20
+ self.class.define_attribute_methods self.attributes.keys
21
+ self.attributes.keys.each { |attr| self.class.define_read_method attr }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ require File.join(File.expand_path(__FILE__), '..', '..', '..', 'test_base')
2
+ include DocumentMapper
3
+
4
+ describe Symbol do
5
+ it 'should create a selector from a valid operator' do
6
+ selector = :my_attribute.gte
7
+ assert_equal 'gte', selector.operator
8
+ assert_equal :my_attribute, selector.attribute
9
+ end
10
+
11
+ it 'should not raise an error on valid operators' do
12
+ begin
13
+ :my_attribute.equal
14
+ :my_attribute.gt
15
+ :my_attribute.gte
16
+ :my_attribute.in
17
+ :my_attribute.lt
18
+ :my_attribute.lte
19
+ rescue StandardError => e
20
+ assert false, 'Calling operator on symbol raised error'
21
+ end
22
+ end
23
+
24
+ it 'should raise an error on invalid operators' do
25
+ assert_raises NoMethodError do
26
+ :my_attribute.not_supported
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,253 @@
1
+ require File.join(File.expand_path(__FILE__), '..', '..', 'test_base')
2
+ include DocumentMapper
3
+
4
+ describe MyDocument do
5
+ before do
6
+ MyDocument.reset
7
+ end
8
+
9
+ describe 'loading a document from file' do
10
+ before do
11
+ @file_path = sample_file_path_1
12
+ @document = MyDocument.from_file(@file_path)
13
+ end
14
+
15
+ it 'should load the document from a yaml file' do
16
+ assert_equal 1, @document.attributes['id']
17
+ assert_equal 'Some fancy title', @document.attributes['title']
18
+ assert_equal ['ruby'], @document.attributes['tags']
19
+ assert_equal :published, @document.attributes['status']
20
+ end
21
+
22
+ it 'should specify attributes from the YAML header' do
23
+ assert_equal 1, @document.id
24
+ assert_equal 'Some fancy title', @document.title
25
+ assert_equal ['ruby'], @document.tags
26
+ assert_equal :published, @document.status
27
+ assert_equal File.expand_path(@file_path), @document.file_path
28
+ end
29
+
30
+ describe 'specifying the date of the document' do
31
+ it 'should get the date from the filename' do
32
+ assert_equal '2010-08-08', @document.date.to_s
33
+ assert_equal 2010, @document.date.year
34
+ assert_equal 8, @document.date.month
35
+ assert_equal 8, @document.date.day
36
+ end
37
+
38
+ it 'should delegate the day method to date' do
39
+ assert_equal 2010, @document.year
40
+ assert_equal 8, @document.month
41
+ assert_equal 8, @document.day
42
+ end
43
+
44
+ it 'should get the date from the yaml front matter if there is one' do
45
+ @document = sample_document_with_date_in_yaml
46
+ assert_equal 2011, @document.year
47
+ assert_equal 4, @document.month
48
+ assert_equal 5, @document.day
49
+ end
50
+
51
+ it 'should not freak out if there is no date' do
52
+ @document = sample_document_without_date
53
+ assert_equal nil, @document.date
54
+ assert_equal nil, @document.year
55
+ assert_equal nil, @document.month
56
+ assert_equal nil, @document.day
57
+ end
58
+ end
59
+
60
+ describe 'loading a documents directory' do
61
+ it 'should load all the documents in that directory' do
62
+ MyDocument.directory = 'test/documents'
63
+ assert_equal [1,2,3,4], MyDocument.all.map(&:id)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe 'getting all/the first/the last MyDocument(s)' do
69
+ before do
70
+ @all_documents = [sample_document_1, sample_document_2]
71
+ end
72
+
73
+ it 'should return all documents' do
74
+ assert_equal @all_documents, MyDocument.all
75
+ end
76
+
77
+ it 'should return the first document' do
78
+ assert_equal @all_documents.first, MyDocument.first
79
+ end
80
+
81
+ it 'should return the last document' do
82
+ assert_equal @all_documents.last, MyDocument.last
83
+ end
84
+ end
85
+
86
+ describe 'using offset and limit' do
87
+ before do
88
+ MyDocument.directory = 'test/documents'
89
+ end
90
+
91
+ it 'should limit the documents to the number specified' do
92
+ assert_equal [1,2], MyDocument.limit(2).all.map(&:id)
93
+ end
94
+
95
+ it 'should offset the documents by the number specified' do
96
+ assert_equal [3,4], MyDocument.offset(2).all.map(&:id)
97
+ end
98
+
99
+ it 'should support offset and limit at the same time' do
100
+ assert_equal [2,3], MyDocument.offset(1).limit(2).all.map(&:id)
101
+ end
102
+ end
103
+
104
+ describe 'resetting the MyDocument class' do
105
+ it 'should clear all documents' do
106
+ one_document = sample_document_1
107
+ assert_equal [one_document], MyDocument.all
108
+ MyDocument.reset
109
+ assert_equal [], MyDocument.all
110
+ end
111
+ end
112
+
113
+ describe 'using where queries' do
114
+ before do
115
+ @document_1 = sample_document_1
116
+ @document_2 = sample_document_2
117
+ MyDocument.directory = 'test/documents'
118
+ end
119
+
120
+ describe 'with an equal operator' do
121
+ it 'should return the right documents' do
122
+ found_document = MyDocument.where(:title => @document_1.title).first
123
+ assert_equal @document_1, found_document
124
+ found_document = MyDocument.where(:title => @document_2.title).first
125
+ assert_equal @document_2, found_document
126
+ end
127
+
128
+ it 'should be chainable' do
129
+ document_proxy = MyDocument.where(:title => @document_1.title)
130
+ document_proxy.where(:id => @document_1.id)
131
+ assert_equal @document_1, document_proxy.first
132
+ end
133
+
134
+ it 'should work with dates' do
135
+ found_documents = MyDocument.where(:year => 2010).all
136
+ expected_documents = [sample_document_1, sample_document_2]
137
+ assert_equal expected_documents.map(&:id), found_documents.map(&:id)
138
+ end
139
+
140
+ it 'should not be confused by attributes not present in all documents' do
141
+ MyDocument.directory = 'test/documents'
142
+ result = MyDocument.where(:seldom_attribute => 'is seldom').all
143
+ assert_equal [4], result.map(&:id)
144
+ end
145
+ end
146
+
147
+ describe 'with a gt operator' do
148
+ it 'should return the right documents' do
149
+ selector = Selector.new :attribute => 'id', :operator => 'gt'
150
+ found_documents = MyDocument.where(selector => 2).all
151
+ assert_equal [3,4], found_documents.map(&:id)
152
+ end
153
+ end
154
+
155
+ describe 'with a gte operator' do
156
+ it 'should return the right documents' do
157
+ selector = Selector.new :attribute => 'id', :operator => 'gte'
158
+ found_documents = MyDocument.where(selector => 2).all
159
+ assert_equal [2,3,4], found_documents.map(&:id)
160
+ end
161
+ end
162
+
163
+ describe 'with an in operator' do
164
+ it 'should return the right documents' do
165
+ selector = Selector.new :attribute => 'id', :operator => 'in'
166
+ found_documents = MyDocument.where(selector => [2,3]).all
167
+ assert_equal [2,3], found_documents.map(&:id)
168
+ end
169
+ end
170
+
171
+ describe 'with an lt operator' do
172
+ it 'should return the right documents' do
173
+ selector = Selector.new :attribute => 'id', :operator => 'lt'
174
+ found_documents = MyDocument.where(selector => 2).all
175
+ assert_equal [1], found_documents.map(&:id)
176
+ end
177
+ end
178
+
179
+ describe 'with an lte operator' do
180
+ it 'should return the right documents' do
181
+ selector = Selector.new :attribute => 'id', :operator => 'lte'
182
+ found_documents = MyDocument.where(selector => 2).all
183
+ assert_equal [1,2], found_documents.map(&:id)
184
+ end
185
+ end
186
+
187
+ describe 'with mixed operators' do
188
+ it 'should return the right documents' do
189
+ in_selector = Selector.new :attribute => 'id', :operator => 'in'
190
+ gt_selector = Selector.new :attribute => 'id', :operator => 'gt'
191
+ documents_proxy = MyDocument.where(in_selector => [2,3])
192
+ found_documents = documents_proxy.where(gt_selector => 2).all
193
+ assert_equal [3], found_documents.map(&:id)
194
+ end
195
+ end
196
+
197
+ describe 'using multiple constrains in one where' do
198
+ it 'should return the right documents' do
199
+ selector = Selector.new :attribute => 'id', :operator => 'lte'
200
+ found_documents = MyDocument.where(selector => 2, :status => :published).all
201
+ assert_equal [1,2], found_documents.map(&:id)
202
+ end
203
+ end
204
+ end
205
+
206
+ describe 'reloading the Document class' do
207
+ it 'should discover new documents' do
208
+ @file_path = 'test/documents/2011-04-26-new-stuff.textile'
209
+ File.open(@file_path, 'w') do |f|
210
+ f.write <<-EOS
211
+ ---
212
+ id: 5
213
+ title: Some brand new document
214
+ ---
215
+
216
+ Very new stuff.
217
+ EOS
218
+ end
219
+ MyDocument.reload
220
+ assert_equal [1,2,3,4,5].sort, MyDocument.all.map(&:id).sort
221
+ end
222
+
223
+ def teardown
224
+ File.delete @file_path
225
+ end
226
+ end
227
+
228
+ def sample_file_path_1
229
+ 'test/documents/2010-08-08-test-document-file.textile'
230
+ end
231
+
232
+ def sample_file_path_2
233
+ 'test/documents/2010-08-09-another-test-document.textile'
234
+ end
235
+
236
+ def sample_document_1
237
+ MyDocument.from_file(sample_file_path_1)
238
+ end
239
+
240
+ def sample_document_2
241
+ MyDocument.from_file(sample_file_path_2)
242
+ end
243
+
244
+ def sample_document_with_date_in_yaml
245
+ file_path = 'test/documents/document_with_date_in_yaml.textile'
246
+ MyDocument.from_file(file_path)
247
+ end
248
+
249
+ def sample_document_without_date
250
+ file_path = 'test/documents/document_without_date.textile'
251
+ MyDocument.from_file(file_path)
252
+ end
253
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.expand_path(__FILE__), '..', '..', 'test_base')
2
+ include DocumentMapper
3
+
4
+ describe Selector do
5
+ it 'should initialize with an attribute and an operator' do
6
+ selector = Selector.new :attribute => 'author', :operator => 'equal'
7
+ assert_equal 'author', selector.attribute
8
+ assert_equal 'equal', selector.operator
9
+ end
10
+
11
+ it 'should raise an exception if the operator is not supported' do
12
+ assert_raises OperatorNotSupportedError do
13
+ selector = Selector.new :attribute => 'author', :operator => 'zomg'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ ---
2
+ id: 1
3
+ title: Some fancy title
4
+ tags: [ruby]
5
+ status: :published
6
+ ---
7
+
8
+ I like being the demo text.
@@ -0,0 +1,10 @@
1
+ ---
2
+ id: 2
3
+ title: Another title, that's for sure
4
+ tags: [ruby, rails]
5
+ special_attribute: Yes!
6
+ friends: [Anton, Paul]
7
+ status: :published
8
+ ---
9
+
10
+ The body copy.
@@ -0,0 +1,7 @@
1
+ ---
2
+ id: 3
3
+ title: Document with date in YAML
4
+ date: 2011-04-05
5
+ ---
6
+
7
+ This document has no date in the filename, but in the YAML front matter.
@@ -0,0 +1,7 @@
1
+ ---
2
+ id: 4
3
+ title: This document has no date
4
+ seldom_attribute: is seldom
5
+ ---
6
+
7
+ This document has no date at all.
data/test/test_base.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'minitest/spec'
2
+ MiniTest::Unit.autorun
3
+
4
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
5
+ $LOAD_PATH.unshift lib_dir unless $LOAD_PATH.include?(lib_dir)
6
+ require 'document_mapper'
7
+ TEST_DIR = File.dirname(__FILE__)
8
+
9
+ class MyDocument
10
+ include DocumentMapper::Document
11
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: document_mapper
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Ralph von der Heyden
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-30 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 3.0.0
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: activemodel
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 3.0.0
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ description: " DocumentMapper 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"
38
+ email: ralph@rvdh.de
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - LICENSE
47
+ - README.textile
48
+ - lib/document_mapper/attribute_methods.rb
49
+ - lib/document_mapper/constants.rb
50
+ - lib/document_mapper/core_ext/symbol.rb
51
+ - lib/document_mapper/document.rb
52
+ - lib/document_mapper/errors.rb
53
+ - lib/document_mapper/query.rb
54
+ - lib/document_mapper/selector.rb
55
+ - lib/document_mapper/version.rb
56
+ - lib/document_mapper/yaml_parsing.rb
57
+ - lib/document_mapper.rb
58
+ - test/document_mapper/core_ext/symbol_test.rb
59
+ - test/document_mapper/document_mapper_test.rb
60
+ - test/document_mapper/selector_test.rb
61
+ - test/documents/2010-08-08-test-document-file.textile
62
+ - test/documents/2010-08-09-another-test-document.textile
63
+ - test/documents/document_with_date_in_yaml.textile
64
+ - test/documents/document_without_date.textile
65
+ - test/test_base.rb
66
+ homepage: http://github.com/ralph/document_mapper
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options: []
71
+
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.7.2
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: DocumentMapper is an object mapper for plain text documents.
93
+ test_files: []
94
+