serum 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/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
|