jadof 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/jadof/page.rb +250 -0
- data/lib/jadof/post.rb +26 -0
- data/lib/jadof/spec/examples_for_page.rb +324 -0
- data/lib/jadof/spec/examples_for_post.rb +33 -0
- data/lib/jadof/spec/helpers.rb +34 -0
- data/lib/jadof/spec.rb +32 -0
- data/lib/jadof.rb +13 -0
- metadata +61 -0
data/lib/jadof/page.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
module JADOF #:nodoc:
|
2
|
+
|
3
|
+
# This is the class interface for {Page}.
|
4
|
+
#
|
5
|
+
# This is split out into a separate module so we can
|
6
|
+
# extend other classes (that inherit from Page) with
|
7
|
+
# this.
|
8
|
+
#
|
9
|
+
# Actually, if you inherit from Page, you automatically
|
10
|
+
# get this module extended into your class.
|
11
|
+
module PageAPI
|
12
|
+
|
13
|
+
# @return [String] The root directory that pages are loaded from. Defaults to "./pages/"
|
14
|
+
attr_accessor :dir
|
15
|
+
|
16
|
+
attr_accessor :formatters
|
17
|
+
|
18
|
+
# This can be set to a standard cache object and, if it is set,
|
19
|
+
# all pages will be cached so they don't have to be re-opened
|
20
|
+
# and we don't have to look for the files.
|
21
|
+
#
|
22
|
+
# Any cache object that supports these standard methods is supported:
|
23
|
+
#
|
24
|
+
# get(key)
|
25
|
+
# set(key, value)
|
26
|
+
# clear
|
27
|
+
#
|
28
|
+
# @return [#get, #set, #clear]
|
29
|
+
attr_accessor :cache
|
30
|
+
|
31
|
+
def dir
|
32
|
+
@dir ||= File.expand_path DEFAULT_DIR
|
33
|
+
end
|
34
|
+
|
35
|
+
# When dir is set, we save it as an expanded path.
|
36
|
+
# We also clear the cache (if it's enabled)
|
37
|
+
def dir= value
|
38
|
+
cache.clear if cache
|
39
|
+
@dir = File.expand_path value
|
40
|
+
end
|
41
|
+
|
42
|
+
# A Hash of available formatters. The key is used to match
|
43
|
+
# a given file extension and the value should be something
|
44
|
+
# that you can #call (like a lambda) with text which returns
|
45
|
+
# the formatted text.
|
46
|
+
# @return [Hash{String => #call}]
|
47
|
+
def formatters
|
48
|
+
@formatters ||= DEFAULT_FORMATTERS
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Page] Get a Page by name
|
52
|
+
def get name
|
53
|
+
first :full_name => name.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [Page] Alias for Page.get
|
57
|
+
def [] name
|
58
|
+
get name
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Array(Page)] Get all Pages in Page.dir
|
62
|
+
def all
|
63
|
+
cache_for 'all' do
|
64
|
+
Dir[ File.join(dir, "**/*") ].reject {|path| File.directory?(path) }.map {|path| from_path(path) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Fixnum] Returns the count of all Pages
|
69
|
+
def count
|
70
|
+
all.length
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Page, nil] Returns the last Page
|
74
|
+
def last
|
75
|
+
all.last
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [Array(Page)] Gets pages given some simple conditions (only == equality is supported)
|
79
|
+
def where conditions
|
80
|
+
all.select { |page| matches_conditions? page, conditions }
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Page, nil] Gets a page given some simple conditions
|
84
|
+
def first conditions = nil
|
85
|
+
if conditions
|
86
|
+
all.find { |page| matches_conditions? page, conditions }
|
87
|
+
else
|
88
|
+
all.first
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Page] Loads a Page from a given path to a file
|
93
|
+
def from_path path
|
94
|
+
path = File.expand_path path
|
95
|
+
filename = File.basename path
|
96
|
+
name = filename[/^[^\.]+/] # get everything before a .
|
97
|
+
body = File.read path
|
98
|
+
|
99
|
+
# Remove YAML from top of body and get the YAML variables from it.
|
100
|
+
# Then we can merge in the name, path, etc, and use it to inialize a page
|
101
|
+
body.sub! /^---(.*)\n---\n/m, ''
|
102
|
+
variables = $1 ? YAML.load($1) : {}
|
103
|
+
variables.merge! :name => name, :path => path, :filename => filename, :body => body
|
104
|
+
|
105
|
+
# If the file is in a subdirectory, get the name of the subdirectory[ies]
|
106
|
+
# and set it as :parent, so it's easily accessible from the Page.
|
107
|
+
# Also, we strip the first and last '/' characters off of it.
|
108
|
+
variables[:parent] = File.dirname(path).sub(dir, '').sub(/^\//, '')
|
109
|
+
|
110
|
+
new variables
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [String] Using the #filename of the page given and available
|
114
|
+
# Page.formatters, we render and return the page #body.
|
115
|
+
def to_html page
|
116
|
+
html = page.body
|
117
|
+
|
118
|
+
page.filename.scan(/\.([^\.]+)/).reverse.each do |match| # [ ["markdown"], ["erb"] ]
|
119
|
+
if formatter = formatters[ match.first ]
|
120
|
+
html = formatter.call(html)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
html
|
125
|
+
end
|
126
|
+
|
127
|
+
# @private
|
128
|
+
# Helper for caching. Will check to see if the {Page.cache}
|
129
|
+
# contains the given key and, if not, it will set the cache by calling
|
130
|
+
# the block given
|
131
|
+
def cache_for key, &block
|
132
|
+
return block.call unless cache
|
133
|
+
|
134
|
+
from_cache = cache.get(key)
|
135
|
+
unless from_cache
|
136
|
+
from_cache = block.call
|
137
|
+
cache.set(key, from_cache)
|
138
|
+
end
|
139
|
+
from_cache
|
140
|
+
end
|
141
|
+
|
142
|
+
# @private
|
143
|
+
# @return [true, false] Helper for #where and #first
|
144
|
+
def matches_conditions? page, conditions
|
145
|
+
matches = true
|
146
|
+
conditions.each {|k,v| matches = false unless page.send(k) == v }
|
147
|
+
matches
|
148
|
+
end
|
149
|
+
|
150
|
+
# @private
|
151
|
+
# When a class inheritcs from Page (or from any class that inherits page),
|
152
|
+
# we extend that class with {PageAPI} so it will get methods like `Page.all`.
|
153
|
+
def inherited base
|
154
|
+
base.extend PageAPI
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# A {Page} wraps a file on the filesystem.
|
159
|
+
#
|
160
|
+
# If you set `Page.dir` to a directory, `Page.all` will
|
161
|
+
# give you all of the files inside that directory as {Page}
|
162
|
+
# objects.
|
163
|
+
#
|
164
|
+
# For all of the available class methods, see {PageAPI}.
|
165
|
+
#
|
166
|
+
class Page
|
167
|
+
extend PageAPI
|
168
|
+
include IndifferentVariableHash
|
169
|
+
|
170
|
+
DEFAULT_DIR = './pages/'
|
171
|
+
|
172
|
+
DEFAULT_FORMATTERS = {
|
173
|
+
'markdown' => lambda { |text| require 'maruku'; Maruku.new(text).to_html },
|
174
|
+
'erb' => lambda { |text| require 'erb'; ERB.new(text).result }
|
175
|
+
}
|
176
|
+
|
177
|
+
# @return [String] A simple name for this {Page}.
|
178
|
+
#
|
179
|
+
# If the filename is `foo.markdown`, the name will be `foo`
|
180
|
+
#
|
181
|
+
# If the file is in a subdirectory below `Page.dir`, eg.
|
182
|
+
# `foo/bar.markdown`, the name will be `bar` but the
|
183
|
+
# #full_name will be `foo/bar`.
|
184
|
+
attr_accessor :name
|
185
|
+
|
186
|
+
# @return [String] The full system path to this file
|
187
|
+
attr_accessor :path
|
188
|
+
|
189
|
+
# @return [String] The filename (without a directory), eg. `foo.markdown`
|
190
|
+
attr_accessor :filename
|
191
|
+
|
192
|
+
# @return [String] The body of the file, *without* the YAML at
|
193
|
+
# the top of the file (if YAML was included).
|
194
|
+
#
|
195
|
+
# We strip out the YAML and use it to set variables on
|
196
|
+
# the Page. If you need the *full* text from the file,
|
197
|
+
# you should `File.read(@page.path)`.
|
198
|
+
attr_accessor :body
|
199
|
+
|
200
|
+
# @return [String] The parent directory of this file, if this file is
|
201
|
+
# in a subdirectory below `Page.dir`. This will be `""` if
|
202
|
+
# it is in `Page.dir` or it will be `"sub/directories"` if
|
203
|
+
# it is in subdirectories.
|
204
|
+
attr_accessor :parent
|
205
|
+
|
206
|
+
# A page is a dumb object and doesn't know how to load itself from
|
207
|
+
# a file on the filesystem. See `Page.from_path` to load a {Page}
|
208
|
+
# from a file.
|
209
|
+
#
|
210
|
+
# @param [Hash] of attributes
|
211
|
+
def initialize options = nil
|
212
|
+
options.each {|attribute, value| send "#{attribute}=", value } if options
|
213
|
+
end
|
214
|
+
|
215
|
+
# @return [String] combines {#name} with {#parent}
|
216
|
+
def full_name
|
217
|
+
parent == '' ? name : File.join(parent, name)
|
218
|
+
end
|
219
|
+
|
220
|
+
# Returns the formatted {#body} of this {Page} using `Page.formatters`.
|
221
|
+
#
|
222
|
+
# The file extensions from the {#filename} are used to match formatters.
|
223
|
+
#
|
224
|
+
# For `foo.markdown`, `Page.formatters['markdown']` will be used.
|
225
|
+
# For `foo.markdown.erb`, `Page.formatters['erb']` and `Page.formatters['markdown']` will be used.
|
226
|
+
#
|
227
|
+
# With multiple extensions, the *last* extension is used first, and then the second-to-last, etc.
|
228
|
+
def to_html
|
229
|
+
self.class.to_html self
|
230
|
+
end
|
231
|
+
|
232
|
+
# @return [true, false] If 2 pages have the same system path, they're the same.
|
233
|
+
def == other_page
|
234
|
+
return false unless other_page.is_a? Page
|
235
|
+
return other_page.path == path
|
236
|
+
end
|
237
|
+
|
238
|
+
# @return [String] This page as a string. Defaults to {#full_name}.
|
239
|
+
def to_s
|
240
|
+
full_name
|
241
|
+
end
|
242
|
+
|
243
|
+
# @return [String] A param representation of this page for us in web applications. Defaults to {#full_name}.
|
244
|
+
def to_param
|
245
|
+
full_name
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
data/lib/jadof/post.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module JADOF #:nodoc:
|
4
|
+
|
5
|
+
# Represents a blog post. Has the same functionality as {Page}
|
6
|
+
# but with a {#date} added (which makes {#to_param}) include
|
7
|
+
# a date, in the conventional way: `2010/01/31/name-of-post`
|
8
|
+
class Post < Page
|
9
|
+
|
10
|
+
# @return [Time] the date that this post was created.
|
11
|
+
# If a [String] is passed in, it will be parsed as a time.
|
12
|
+
attr_accessor :date
|
13
|
+
|
14
|
+
def date= value
|
15
|
+
@date = Time.parse value.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String] The conventional way to display blog
|
19
|
+
# post urls, eg. `2010/01/31/name-of-post`
|
20
|
+
def to_param
|
21
|
+
date ? "#{ date.strftime('%Y/%m/%d') }/#{ full_name }" : super
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
shared_examples_for "JADOF Page" do
|
2
|
+
|
3
|
+
describe ':: Behaves like JADOF Page' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@jadof_page_class ||= JADOF::Page # override this in your specs to test a different class!
|
7
|
+
|
8
|
+
@root_page_directory ||= './jadof_spec_pages/'
|
9
|
+
@jadof_page_class.dir = File.join(@root_page_directory, 'pages')
|
10
|
+
delete_root_page_directory
|
11
|
+
end
|
12
|
+
|
13
|
+
after :all do
|
14
|
+
delete_root_page_directory
|
15
|
+
end
|
16
|
+
|
17
|
+
it '#create_page works as expected for creating fake pages for these specs' do
|
18
|
+
path = File.join(@jadof_page_class.dir, '/foo.markdown')
|
19
|
+
File.file?(path).should be_false
|
20
|
+
|
21
|
+
create_page 'foo.markdown'
|
22
|
+
|
23
|
+
File.file?(path).should be_true
|
24
|
+
@jadof_page_class[:foo].body.should == ''
|
25
|
+
|
26
|
+
create_page 'foo.markdown', %{
|
27
|
+
it should fix
|
28
|
+
the spaces
|
29
|
+
for me
|
30
|
+
}
|
31
|
+
|
32
|
+
@jadof_page_class[:foo].body.should == "it should fix\n the spaces\nfor me"
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'can set the @jadof_page_class.dir to specify the directory to fetch pages from' do
|
36
|
+
dir1, dir2 = @jadof_page_class.dir, File.join(@root_page_directory, '/more_pages')
|
37
|
+
|
38
|
+
create_page 'foo.markdown', 'hello world', dir1
|
39
|
+
create_page 'bar.markdown', 'hello world', dir2
|
40
|
+
|
41
|
+
@jadof_page_class[:foo].should_not be_nil
|
42
|
+
@jadof_page_class[:bar].should be_nil
|
43
|
+
|
44
|
+
@jadof_page_class.dir = dir2
|
45
|
+
|
46
|
+
@jadof_page_class[:foo].should be_nil
|
47
|
+
@jadof_page_class[:bar].should_not be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'has a filename (the actual filename, without a path)' do
|
51
|
+
create_page 'foo.markdown'
|
52
|
+
|
53
|
+
@jadof_page_class[:foo].should_not be_nil
|
54
|
+
@jadof_page_class[:foo].filename.should == 'foo.markdown'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'has a path (the full system path to the file)' do
|
58
|
+
create_page 'foo.markdown'
|
59
|
+
|
60
|
+
@jadof_page_class[:foo].should_not be_nil
|
61
|
+
@jadof_page_class[:foo].path.should == File.expand_path(File.join(@jadof_page_class.dir, '/foo.markdown'))
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'has a name (the name of the file, without extensions)' do
|
65
|
+
create_page 'foo.markdown'
|
66
|
+
|
67
|
+
@jadof_page_class[:foo].should_not be_nil
|
68
|
+
@jadof_page_class[:foo].name.should == 'foo'
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'has a body (the content of the file)' do
|
72
|
+
create_page 'foo.markdown'
|
73
|
+
@jadof_page_class[:foo].body.should == ''
|
74
|
+
|
75
|
+
create_page 'foo.markdown', %{
|
76
|
+
Hello World!
|
77
|
+
}
|
78
|
+
|
79
|
+
@jadof_page_class[:foo].body.strip.should == 'Hello World!'
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'can return all pages' do
|
83
|
+
@jadof_page_class.count.should == 0
|
84
|
+
@jadof_page_class.all.length.should == 0
|
85
|
+
|
86
|
+
create_page 'foo.markdown'
|
87
|
+
|
88
|
+
@jadof_page_class.count.should == 1
|
89
|
+
@jadof_page_class.all.length.should == 1
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'can return #first and #last page' do
|
93
|
+
create_page 'foo.markdown'
|
94
|
+
create_page 'bar.markdown'
|
95
|
+
|
96
|
+
@jadof_page_class.first.should == @jadof_page_class.all.first
|
97
|
+
@jadof_page_class.last.should == @jadof_page_class.all.last
|
98
|
+
|
99
|
+
@jadof_page_class.first.should_not == @jadof_page_class.last
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'can get a page by name' do
|
103
|
+
@jadof_page_class.get(:foo).should be_nil
|
104
|
+
@jadof_page_class[:foo].should be_nil
|
105
|
+
|
106
|
+
create_page 'foo.markdown'
|
107
|
+
|
108
|
+
@jadof_page_class.get(:foo).should_not be_nil
|
109
|
+
@jadof_page_class[:foo].should_not be_nil
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'supports 1 level of sub-directories' do
|
113
|
+
create_page 'hi.markdown'
|
114
|
+
@jadof_page_class['hi'].parent.should == ''
|
115
|
+
|
116
|
+
create_page 'foo/bar.markdown'
|
117
|
+
|
118
|
+
@jadof_page_class['foo/bar'].name.should == 'bar'
|
119
|
+
@jadof_page_class['foo/bar'].full_name.should == 'foo/bar'
|
120
|
+
@jadof_page_class['foo/bar'].parent.should == 'foo'
|
121
|
+
@jadof_page_class['foo/bar'].filename.should == 'bar.markdown'
|
122
|
+
@jadof_page_class['foo/bar'].path.should include('foo/bar.markdown')
|
123
|
+
|
124
|
+
@jadof_page_class.first(:name => 'bar').name.should == 'bar'
|
125
|
+
@jadof_page_class.first(:name => 'bar').filename.should == 'bar.markdown'
|
126
|
+
@jadof_page_class.first(:name => 'bar').path.should include('foo/bar.markdown')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'supports n levels of sub-directories' do
|
130
|
+
create_page 'foo/bar/hello/there/crazy/person-123.markdown'
|
131
|
+
|
132
|
+
@jadof_page_class['foo/bar/hello/there/crazy/person-123'].name.should == 'person-123'
|
133
|
+
@jadof_page_class['foo/bar/hello/there/crazy/person-123'].full_name.should == 'foo/bar/hello/there/crazy/person-123'
|
134
|
+
@jadof_page_class['foo/bar/hello/there/crazy/person-123'].parent.should == 'foo/bar/hello/there/crazy'
|
135
|
+
@jadof_page_class['foo/bar/hello/there/crazy/person-123'].filename.should == 'person-123.markdown'
|
136
|
+
@jadof_page_class['foo/bar/hello/there/crazy/person-123'].path.should include('/crazy/person-123.markdown')
|
137
|
+
|
138
|
+
@jadof_page_class.first(:name => 'person-123').name.should == 'person-123'
|
139
|
+
@jadof_page_class.first(:name => 'person-123').filename.should == 'person-123.markdown'
|
140
|
+
@jadof_page_class.first(:name => 'person-123').path.should include('/crazy/person-123.markdown')
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'implements #to_s (defaults to #full_name)' do
|
144
|
+
create_page 'hi.markdown'
|
145
|
+
create_page 'foo/bar/hello/there/crazy/person-123.markdown'
|
146
|
+
|
147
|
+
@jadof_page_class[:hi].to_s.should == 'hi'
|
148
|
+
@jadof_page_class.first(:name => 'person-123').to_s.should == 'foo/bar/hello/there/crazy/person-123'
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'implements #to_param (defaults to #full_name)' do
|
152
|
+
create_page 'hi.markdown'
|
153
|
+
create_page 'foo/bar/hello/there/crazy/person-123.markdown'
|
154
|
+
|
155
|
+
@jadof_page_class[:hi].to_param.should == 'hi'
|
156
|
+
@jadof_page_class.first(:name => 'person-123').to_param.should == 'foo/bar/hello/there/crazy/person-123'
|
157
|
+
end
|
158
|
+
|
159
|
+
describe ':: YAML header' do
|
160
|
+
|
161
|
+
it 'can add any kind of arbitrary data to a page via YAML' do
|
162
|
+
create_page 'foo.markdown'
|
163
|
+
@jadof_page_class[:foo].foo.should be_nil # @jadof_page_class's don't raise NoMethodError's
|
164
|
+
|
165
|
+
create_page 'foo.markdown', %{
|
166
|
+
---
|
167
|
+
foo: bar
|
168
|
+
---
|
169
|
+
Hello World!
|
170
|
+
}
|
171
|
+
|
172
|
+
@jadof_page_class[:foo].foo.should == 'bar' # got value from YAML
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'can get a page by the value of any arbitrary data (from the YAML)' do
|
176
|
+
create_page 'foo.markdown', %{
|
177
|
+
---
|
178
|
+
foo: bar
|
179
|
+
---
|
180
|
+
Hello World!
|
181
|
+
}
|
182
|
+
|
183
|
+
@jadof_page_class.first(:foo => 'not bar').should be_nil
|
184
|
+
@jadof_page_class.first(:foo => 'bar' ).should_not be_nil
|
185
|
+
@jadof_page_class.first(:foo => 'bar' ).foo.should == 'bar'
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'can get a page by *multiple* arbitrary conditions' do
|
189
|
+
create_page 'foo.markdown', %{
|
190
|
+
---
|
191
|
+
foo: bar
|
192
|
+
---
|
193
|
+
Hello World!
|
194
|
+
}
|
195
|
+
|
196
|
+
@jadof_page_class.where(:foo => 'bar', :name => 'not foo').should be_empty
|
197
|
+
@jadof_page_class.where(:foo => 'not bar', :name => 'foo').should be_empty
|
198
|
+
@jadof_page_class.where(:foo => 'bar', :name => 'foo').should_not be_empty
|
199
|
+
@jadof_page_class.where(:foo => 'bar', :name => 'foo').first.name.should == 'foo'
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
describe ':: Rendering' do
|
205
|
+
|
206
|
+
before do
|
207
|
+
@jadof_page_class.formatters = {}
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'should render plain text if formatter not found for file extension' do
|
211
|
+
create_page 'foo.markdown', %{
|
212
|
+
**Hello World!**
|
213
|
+
}
|
214
|
+
|
215
|
+
@jadof_page_class[:foo].to_html.should == '**Hello World!**'
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'should render using formatter if found for file extension' do
|
219
|
+
@jadof_page_class.formatters['markdown'] = lambda {|text| Maruku.new(text).to_html }
|
220
|
+
|
221
|
+
create_page 'foo.markdown', %{
|
222
|
+
**Hello World!**
|
223
|
+
}
|
224
|
+
|
225
|
+
@jadof_page_class[:foo].to_html.should == '<p><strong>Hello World!</strong></p>'
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should support multiple file extensions, eg. foo.markdown.erb (erb renders first, then markdown)' do
|
229
|
+
@jadof_page_class.formatters['markdown'] = lambda {|text| Maruku.new(text).to_html }
|
230
|
+
|
231
|
+
create_page 'foo.markdown.erb', %{
|
232
|
+
<%= '*' * 2 %>Hello World!<%= '*' * 2 %>
|
233
|
+
}
|
234
|
+
|
235
|
+
@jadof_page_class[:foo].to_html.should ==
|
236
|
+
'<p><%= ’<em>’</em> 2 %>Hello World!<%= ’<em>’</em> 2 %></p>'
|
237
|
+
|
238
|
+
|
239
|
+
@jadof_page_class.formatters['erb'] = lambda {|text| ERB.new(text).result }
|
240
|
+
@jadof_page_class[:foo].to_html.should == '<p><strong>Hello World!</strong></p>'
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should have markdown and erb out of the box' do
|
244
|
+
create_page 'foo.markdown.erb', %{
|
245
|
+
<%= '*' * 2 %>Hello World!<%= '*' * 2 %>
|
246
|
+
}
|
247
|
+
|
248
|
+
@jadof_page_class.formatters = @jadof_page_class::DEFAULT_FORMATTERS
|
249
|
+
@jadof_page_class[:foo].to_html.should == '<p><strong>Hello World!</strong></p>'
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
describe ':: Caching' do
|
255
|
+
|
256
|
+
before do
|
257
|
+
@jadof_page_class.cache = Hash::Cache.new # Hash that has #get(k) and #set(k,v) methods and #clear
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'with the cache enabled, files should only be #read once' do
|
261
|
+
create_page 'foo.markdown'
|
262
|
+
path = File.join @jadof_page_class.dir, 'foo.markdown'
|
263
|
+
|
264
|
+
File.should_receive(:read).with(File.expand_path(path)).once.and_return('') # only once!
|
265
|
+
|
266
|
+
@jadof_page_class[:foo]
|
267
|
+
@jadof_page_class[:foo]
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'with the cache enabled, Dir[] should only look for files once' do
|
271
|
+
create_page 'foo.markdown'
|
272
|
+
create_page 'bar.markdown'
|
273
|
+
|
274
|
+
dir = @root_page_directory
|
275
|
+
Dir.should_receive(:[]).once.and_return([File.join(dir, '/pages/bar.markdown'), File.join(dir, '/pages/foo.markdown')])
|
276
|
+
File.should_receive(:read).twice.and_return('')
|
277
|
+
|
278
|
+
@jadof_page_class.all
|
279
|
+
@jadof_page_class.all # calls everyhing again if caching is disabled (@jadof_page_class.cache is nil or false)
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'with the cache disabled, Dir[] should only look for files more than once' do
|
283
|
+
@jadof_page_class.cache = false
|
284
|
+
|
285
|
+
create_page 'foo.markdown'
|
286
|
+
create_page 'bar.markdown'
|
287
|
+
|
288
|
+
dir = @root_page_directory
|
289
|
+
Dir.should_receive(:[]).twice.and_return([File.join(dir, '/pages/bar.markdown'), File.join(dir, '/pages/foo.markdown')])
|
290
|
+
File.should_receive(:read).exactly(4).times.and_return('')
|
291
|
+
|
292
|
+
@jadof_page_class.all
|
293
|
+
@jadof_page_class.all # calls everyhing again if caching is disabled (@jadof_page_class.cache is nil or false)
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'should be able to clear the cache' do
|
297
|
+
@jadof_page_class.cache.get('all').should be_nil
|
298
|
+
@jadof_page_class.all
|
299
|
+
@jadof_page_class.cache.get('all').should_not be_nil
|
300
|
+
|
301
|
+
@jadof_page_class.cache.clear
|
302
|
+
|
303
|
+
@jadof_page_class.cache.get('all').should be_nil
|
304
|
+
@jadof_page_class.all
|
305
|
+
@jadof_page_class.cache.get('all').should_not be_nil
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'should clear the cache when the @jadof_page_class.dir is changed' do
|
309
|
+
@jadof_page_class.cache.get('all').should be_nil
|
310
|
+
@jadof_page_class.all
|
311
|
+
@jadof_page_class.cache.get('all').should_not be_nil
|
312
|
+
|
313
|
+
@jadof_page_class.dir = File.join(@root_page_directory, 'different-directory')
|
314
|
+
|
315
|
+
@jadof_page_class.cache.get('all').should be_nil
|
316
|
+
@jadof_page_class.all
|
317
|
+
@jadof_page_class.cache.get('all').should_not be_nil
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
shared_examples_for "JADOF Post" do
|
2
|
+
|
3
|
+
describe ':: Behaves like JADOF Post' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@jadof_post_class ||= JADOF::Post # override this in your specs to test a different class!
|
7
|
+
|
8
|
+
@root_page_directory ||= './jadof_spec_pages/'
|
9
|
+
@jadof_post_class.dir = File.join(@root_page_directory, 'posts')
|
10
|
+
delete_root_page_directory
|
11
|
+
end
|
12
|
+
|
13
|
+
after :all do
|
14
|
+
delete_root_page_directory
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'it should have a date (which is used in to_param)' do
|
18
|
+
create_page 'foo.markdown', %{
|
19
|
+
---
|
20
|
+
date: 01/31/2010
|
21
|
+
---
|
22
|
+
|
23
|
+
hello world
|
24
|
+
}, @jadof_post_class.dir
|
25
|
+
|
26
|
+
@jadof_post_class.first.name.should == 'foo'
|
27
|
+
@jadof_post_class.first.to_s.should == 'foo'
|
28
|
+
@jadof_post_class.first.to_param.should == '2010/01/31/foo'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Helper for creating page files in the specs, at spec/pages/
|
2
|
+
#
|
3
|
+
# create_page 'foo.markdown'
|
4
|
+
#
|
5
|
+
# create_page 'foo.markdown', %{
|
6
|
+
# This is the body
|
7
|
+
# of the page that will
|
8
|
+
# be created.
|
9
|
+
# }
|
10
|
+
#
|
11
|
+
# create_page 'foo.markdown', 'body', './directory/to/create/page/in/'
|
12
|
+
#
|
13
|
+
def create_page filename, body = '', page_dir = @jadof_page_class.dir
|
14
|
+
body.sub!("\n", '') if body.lines.first == "\n" # get rid of first empty line
|
15
|
+
body.sub!(/\n\s+$/, '') if body.lines.count > 0 # get rid of last empty line
|
16
|
+
|
17
|
+
# grab the spaces (if any) from the 1st line and remove that
|
18
|
+
# many spaces from the rest of the lines so our specs look clean
|
19
|
+
if body.lines.first
|
20
|
+
spaces = body.lines.first[/^[ ]+/]
|
21
|
+
body.gsub!(/^#{spaces}/, '') if spaces
|
22
|
+
end
|
23
|
+
|
24
|
+
body ||= '' # if it's nil for some reason, make it an empty string
|
25
|
+
|
26
|
+
path = File.join(page_dir, filename)
|
27
|
+
FileUtils.mkdir_p File.dirname(path)
|
28
|
+
File.open(path, 'w'){|f| f << body }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Deletes the root directory that we create pages in
|
32
|
+
def delete_root_page_directory
|
33
|
+
FileUtils.rm_rf @root_page_directory
|
34
|
+
end
|
data/lib/jadof/spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# If you want to extend JADOF, you'll probably want to
|
2
|
+
# create specs to make sure that your functionality works.
|
3
|
+
#
|
4
|
+
# You'll probably also want to run the JADOF specs, as
|
5
|
+
# regression tests, so you know if you break any of the
|
6
|
+
# core functionality.
|
7
|
+
#
|
8
|
+
# For that, we use RSpec shared examples so, in your specs,
|
9
|
+
# you can require 'jadof/test' and then add this to your specs:
|
10
|
+
#
|
11
|
+
# it_should_behave_like "JADOF Page"
|
12
|
+
#
|
13
|
+
# The shared examples use a few instance variables which you
|
14
|
+
# can override.
|
15
|
+
#
|
16
|
+
# @root_page_directory
|
17
|
+
# : the directory to save fake pages in while the
|
18
|
+
# tests run. these are cleaned up by the tests.
|
19
|
+
# default: './jadof_spec_pages/'. we delete this
|
20
|
+
# directory when running specs do don't use a
|
21
|
+
# directory with things you care about!
|
22
|
+
#
|
23
|
+
require 'rubygems'
|
24
|
+
require 'spec'
|
25
|
+
require 'fileutils' # for creating/deleting directories for fake pages
|
26
|
+
require 'hash-cache' # for testing caching
|
27
|
+
require 'maruku' # for testing rendering
|
28
|
+
require 'erb' # for testing rendering
|
29
|
+
require File.dirname(__FILE__) + '/../jadof' unless defined? JADOF
|
30
|
+
require File.dirname(__FILE__) + '/spec/helpers'
|
31
|
+
require File.dirname(__FILE__) + '/spec/examples_for_page'
|
32
|
+
require File.dirname(__FILE__) + '/spec/examples_for_post'
|
data/lib/jadof.rb
ADDED
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jadof
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- remi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-10 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: remi@remitaylor.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/jadof/spec/examples_for_post.rb
|
26
|
+
- lib/jadof/spec/examples_for_page.rb
|
27
|
+
- lib/jadof/spec/helpers.rb
|
28
|
+
- lib/jadof/post.rb
|
29
|
+
- lib/jadof/spec.rb
|
30
|
+
- lib/jadof/page.rb
|
31
|
+
- lib/jadof.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/remi/jadof
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Just A Directory Of Files (JADOF)
|
60
|
+
test_files: []
|
61
|
+
|