serum 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/LICENSE +23 -0
- data/README.md +55 -0
- data/Rakefile +10 -0
- data/lib/serum.rb +71 -0
- data/lib/serum/core_ext.rb +68 -0
- data/lib/serum/errors.rb +4 -0
- data/lib/serum/mime.types +84 -0
- data/lib/serum/post.rb +177 -0
- data/lib/serum/site.rb +116 -0
- data/lib/serum/static_file.rb +53 -0
- data/serum.gemspec +85 -0
- data/test/helper.rb +26 -0
- data/test/source/2008-02-02-not-published.textile +8 -0
- data/test/source/2008-02-02-published.textile +8 -0
- data/test/source/2008-10-18-foo-bar.textile +8 -0
- data/test/source/2008-11-21-complex.textile +8 -0
- data/test/source/2008-12-03-permalinked-post.textile +9 -0
- data/test/source/2008-12-13-include.markdown +8 -0
- data/test/source/2009-01-27-array-categories.textile +10 -0
- data/test/source/2009-01-27-categories.textile +7 -0
- data/test/source/2009-01-27-category.textile +7 -0
- data/test/source/2009-01-27-empty-categories.textile +7 -0
- data/test/source/2009-01-27-empty-category.textile +7 -0
- data/test/source/2009-03-12-hash-#1.markdown +6 -0
- data/test/source/2009-05-18-empty-tag.textile +6 -0
- data/test/source/2009-05-18-empty-tags.textile +6 -0
- data/test/source/2009-05-18-tag.textile +6 -0
- data/test/source/2009-05-18-tags.textile +9 -0
- data/test/source/2009-05-24-yaml-linebreak.markdown +7 -0
- data/test/source/2009-06-22-empty-yaml.textile +3 -0
- data/test/source/2009-06-22-no-yaml.textile +1 -0
- data/test/source/2010-01-08-triple-dash.markdown +6 -0
- data/test/source/2010-01-09-date-override.textile +7 -0
- data/test/source/2010-01-09-time-override.textile +7 -0
- data/test/source/2010-01-09-timezone-override.textile +7 -0
- data/test/source/2010-01-16-override-data.textile +4 -0
- data/test/source/2011-04-12-md-extension.md +7 -0
- data/test/source/2011-04-12-text-extension.text +0 -0
- data/test/source/2013-01-02-post-excerpt.markdown +14 -0
- data/test/source/2013-01-12-nil-layout.textile +6 -0
- data/test/source/2013-01-12-no-layout.textile +5 -0
- data/test/suite.rb +11 -0
- data/test/test_core_ext.rb +88 -0
- data/test/test_post.rb +138 -0
- data/test/test_site.rb +68 -0
- metadata +194 -0
data/lib/serum/site.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module Serum
|
2
|
+
class Site
|
3
|
+
attr_accessor :config, :posts, :static_files, :exclude, :include, :source
|
4
|
+
attr_accessor :time, :baseurl
|
5
|
+
|
6
|
+
# Public: Initialize a new Site.
|
7
|
+
#
|
8
|
+
# config - A Hash containing site configuration details.
|
9
|
+
def initialize(config)
|
10
|
+
self.config = config.clone
|
11
|
+
|
12
|
+
self.source = File.expand_path(config['source'])
|
13
|
+
self.baseurl = config['baseurl']
|
14
|
+
self.exclude = config['exclude'] || []
|
15
|
+
self.include = config['include'] || []
|
16
|
+
|
17
|
+
self.reset
|
18
|
+
self.read_directories
|
19
|
+
end
|
20
|
+
|
21
|
+
# Reset Site details.
|
22
|
+
#
|
23
|
+
# Returns nothing
|
24
|
+
def reset
|
25
|
+
self.time = if self.config['time']
|
26
|
+
Time.parse(self.config['time'].to_s)
|
27
|
+
else
|
28
|
+
Time.now
|
29
|
+
end
|
30
|
+
self.posts = []
|
31
|
+
self.static_files = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# Recursively traverse directories to find posts and static files
|
35
|
+
# that will become part of the site according to the rules in
|
36
|
+
# filter_entries.
|
37
|
+
#
|
38
|
+
# dir - The String relative path of the directory to read. Default: ''.
|
39
|
+
#
|
40
|
+
# Returns nothing.
|
41
|
+
def read_directories(dir = '')
|
42
|
+
self.reset
|
43
|
+
base = File.join(self.source, dir)
|
44
|
+
entries = Dir.chdir(base) { filter_entries(Dir.entries('.')) }
|
45
|
+
|
46
|
+
self.read_posts(dir)
|
47
|
+
self.posts.sort!
|
48
|
+
|
49
|
+
entries.each do |f|
|
50
|
+
f_abs = File.join(base, f)
|
51
|
+
f_rel = File.join(dir, f)
|
52
|
+
if File.directory?(f_abs)
|
53
|
+
read_directories(f_rel)
|
54
|
+
elsif !File.symlink?(f_abs)
|
55
|
+
static_files << StaticFile.new(self, self.source, dir, f)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Read all the files in <source>/<dir> and create a new Post
|
61
|
+
# object with each one.
|
62
|
+
#
|
63
|
+
# dir - The String relative path of the directory to read.
|
64
|
+
#
|
65
|
+
# Returns nothing.
|
66
|
+
def read_posts(dir)
|
67
|
+
entries = get_entries(dir, '')
|
68
|
+
|
69
|
+
# first pass processes, but does not yet render post content
|
70
|
+
entries.each do |f|
|
71
|
+
if Post.valid?(f)
|
72
|
+
post = Post.new(self, self.source, dir, f)
|
73
|
+
|
74
|
+
if post.published && post.date <= self.time
|
75
|
+
self.posts << post
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Filter out any files/directories that are hidden or backup files (start
|
82
|
+
# with "." or "#" or end with "~"), or contain site content (start with "_"),
|
83
|
+
# or are excluded in the site configuration, unless they are web server
|
84
|
+
# files such as '.htaccess'.
|
85
|
+
#
|
86
|
+
# entries - The Array of String file/directory entries to filter.
|
87
|
+
#
|
88
|
+
# Returns the Array of filtered entries.
|
89
|
+
def filter_entries(entries)
|
90
|
+
entries.reject do |e|
|
91
|
+
unless self.include.glob_include?(e)
|
92
|
+
['.', '_', '#'].include?(e[0..0]) ||
|
93
|
+
e[-1..-1] == '~' ||
|
94
|
+
self.exclude.glob_include?(e) ||
|
95
|
+
(File.symlink?(e) && self.safe)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Read the entries from a particular directory for processing
|
101
|
+
#
|
102
|
+
# dir - The String relative path of the directory to read
|
103
|
+
# subfolder - The String directory to read
|
104
|
+
#
|
105
|
+
# Returns the list of entries to process
|
106
|
+
def get_entries(dir, subfolder)
|
107
|
+
base = File.join(self.source, dir, subfolder)
|
108
|
+
return [] unless File.exists?(base)
|
109
|
+
entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def inspect
|
113
|
+
"<Site: #{source}>"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Serum
|
2
|
+
class StaticFile
|
3
|
+
# The cache of last modification times [path] -> mtime.
|
4
|
+
@@mtimes = Hash.new
|
5
|
+
|
6
|
+
# Initialize a new StaticFile.
|
7
|
+
#
|
8
|
+
# site - The Site.
|
9
|
+
# base - The String path to the <source>.
|
10
|
+
# dir - The String path between <source> and the file.
|
11
|
+
# name - The String filename of the file.
|
12
|
+
def initialize(site, base, dir, name)
|
13
|
+
@site = site
|
14
|
+
@base = base
|
15
|
+
@dir = dir
|
16
|
+
@name = name
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns source file path.
|
20
|
+
def path
|
21
|
+
File.join(@base, @dir, @name)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Obtain destination path.
|
25
|
+
#
|
26
|
+
# dest - The String path to the destination dir.
|
27
|
+
#
|
28
|
+
# Returns destination file path.
|
29
|
+
def destination(dest)
|
30
|
+
File.join(dest, @dir, @name)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns last modification time for this file.
|
34
|
+
def mtime
|
35
|
+
File.stat(path).mtime.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
# Is source path modified?
|
39
|
+
#
|
40
|
+
# Returns true if modified since last write.
|
41
|
+
def modified?
|
42
|
+
@@mtimes[path] != mtime
|
43
|
+
end
|
44
|
+
|
45
|
+
# Reset the mtimes cache (for testing purposes).
|
46
|
+
#
|
47
|
+
# Returns nothing.
|
48
|
+
def self.reset_cache
|
49
|
+
@@mtimes = Hash.new
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/serum.gemspec
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
3
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
|
+
s.rubygems_version = '1.3.5'
|
5
|
+
|
6
|
+
s.name = 'serum'
|
7
|
+
s.version = '0.1.0'
|
8
|
+
s.license = 'MIT'
|
9
|
+
s.date = '2013-03-30'
|
10
|
+
s.rubyforge_project = 'serum'
|
11
|
+
|
12
|
+
s.summary = "A simple object model on static posts with YAML front matter."
|
13
|
+
s.description = "Serum is a simple object model on static posts with YAML front matter."
|
14
|
+
|
15
|
+
s.authors = ["Brad Fults"]
|
16
|
+
s.email = 'bfults@gmail.com'
|
17
|
+
s.homepage = 'http://github.com/h3h/serum'
|
18
|
+
|
19
|
+
s.require_paths = %w[lib]
|
20
|
+
|
21
|
+
s.executables = []
|
22
|
+
|
23
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
24
|
+
s.extra_rdoc_files = %w[README.md LICENSE]
|
25
|
+
|
26
|
+
s.add_runtime_dependency('safe_yaml', "~> 0.7.0")
|
27
|
+
|
28
|
+
s.add_development_dependency('rake', "~> 10.0.3")
|
29
|
+
s.add_development_dependency('rdoc', "~> 3.11")
|
30
|
+
s.add_development_dependency('redgreen', "~> 1.2")
|
31
|
+
s.add_development_dependency('shoulda', "~> 3.3.2")
|
32
|
+
s.add_development_dependency('rr', "~> 1.0")
|
33
|
+
|
34
|
+
# = MANIFEST =
|
35
|
+
s.files = %w[
|
36
|
+
Gemfile
|
37
|
+
LICENSE
|
38
|
+
Rakefile
|
39
|
+
lib/serum.rb
|
40
|
+
lib/serum/core_ext.rb
|
41
|
+
lib/serum/errors.rb
|
42
|
+
lib/serum/mime.types
|
43
|
+
lib/serum/post.rb
|
44
|
+
lib/serum/site.rb
|
45
|
+
lib/serum/static_file.rb
|
46
|
+
serum.gemspec
|
47
|
+
test/helper.rb
|
48
|
+
test/source/2008-02-02-not-published.textile
|
49
|
+
test/source/2008-02-02-published.textile
|
50
|
+
test/source/2008-10-18-foo-bar.textile
|
51
|
+
test/source/2008-11-21-complex.textile
|
52
|
+
test/source/2008-12-03-permalinked-post.textile
|
53
|
+
test/source/2008-12-13-include.markdown
|
54
|
+
test/source/2009-01-27-array-categories.textile
|
55
|
+
test/source/2009-01-27-categories.textile
|
56
|
+
test/source/2009-01-27-category.textile
|
57
|
+
test/source/2009-01-27-empty-categories.textile
|
58
|
+
test/source/2009-01-27-empty-category.textile
|
59
|
+
test/source/2009-03-12-hash-#1.markdown
|
60
|
+
test/source/2009-05-18-empty-tag.textile
|
61
|
+
test/source/2009-05-18-empty-tags.textile
|
62
|
+
test/source/2009-05-18-tag.textile
|
63
|
+
test/source/2009-05-18-tags.textile
|
64
|
+
test/source/2009-05-24-yaml-linebreak.markdown
|
65
|
+
test/source/2009-06-22-empty-yaml.textile
|
66
|
+
test/source/2009-06-22-no-yaml.textile
|
67
|
+
test/source/2010-01-08-triple-dash.markdown
|
68
|
+
test/source/2010-01-09-date-override.textile
|
69
|
+
test/source/2010-01-09-time-override.textile
|
70
|
+
test/source/2010-01-09-timezone-override.textile
|
71
|
+
test/source/2010-01-16-override-data.textile
|
72
|
+
test/source/2011-04-12-md-extension.md
|
73
|
+
test/source/2011-04-12-text-extension.text
|
74
|
+
test/source/2013-01-02-post-excerpt.markdown
|
75
|
+
test/source/2013-01-12-nil-layout.textile
|
76
|
+
test/source/2013-01-12-no-layout.textile
|
77
|
+
test/suite.rb
|
78
|
+
test/test_core_ext.rb
|
79
|
+
test/test_post.rb
|
80
|
+
test/test_site.rb
|
81
|
+
]
|
82
|
+
# = MANIFEST =
|
83
|
+
|
84
|
+
s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
|
85
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require 'serum'
|
5
|
+
|
6
|
+
require 'redgreen' if RUBY_VERSION < '1.9'
|
7
|
+
require 'shoulda'
|
8
|
+
require 'rr'
|
9
|
+
|
10
|
+
include Serum
|
11
|
+
|
12
|
+
# Send STDERR into the void to suppress program output messages
|
13
|
+
STDERR.reopen(test(?e, '/dev/null') ? '/dev/null' : 'NUL:')
|
14
|
+
|
15
|
+
class Test::Unit::TestCase
|
16
|
+
include RR::Adapters::TestUnit
|
17
|
+
|
18
|
+
def source_dir(*subdirs)
|
19
|
+
test_dir('source', *subdirs)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_dir(*subdirs)
|
23
|
+
File.join(File.dirname(__FILE__), *subdirs)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|