zzot-semi-static 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+ = Semi Static
2
+
3
+ Semi Static is yet another static site generator. I've been playing around
4
+ with similar systems off and on for years, but it's
5
+ Jekyll[http://github.com/mojombo/jekyll] that finally convinced me to build
6
+ (and finish) one for myself. The main idea that I take from Jekyll is using
7
+ Git[http://git-scm.com/] as the database. The idea from Jekyll that I'm not
8
+ adopting is avoiding Ruby[http://ruby-lang.org/] code evaluation at all
9
+ costs -- I'm not letting other people feed documents into it (as
10
+ GitHub[http://github.com/] Pages[http://pages.github.com] does), so I don't
11
+ need to protect myself from them.
12
+
13
+ At some point Semi Static had a sister project, Semi Live, that would generate
14
+ the site dynamically (probably via Rails[http://rubyonrails.org/]). I stopped
15
+ working on it not long after I first started, so don't expect to see it on my
16
+ projects[http://github.com/zzot] page.
17
+
18
+ == Features
19
+
20
+ * Layouts can be Haml[http://haml.hamptoncatlin.com/] or
21
+ ERB[http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/] -- but not
22
+ Liquid[http://www.liquidmarkup.org/].
23
+ * Stylesheets can be Sass[http://haml.hamptoncatlin.com/] or raw CSS.
24
+ * Pages and posts can be Maruku[http://maruku.rubyforge.org/] or raw HTML.
25
+ * Code highlighting by Pygments[http://pygments.org/].
26
+
27
+ == Installation
28
+
29
+ The easiest way to install Semi-Static is via RubyGems[http://www.rubygems.org/]:
30
+
31
+ $ sudo gem install zzot-semi-static -s http://gems.github.com/
32
+
33
+ Semi-Static requires the `Haml` and `Maruku` gems and the `Pygments`
34
+ library to be installed.
35
+
36
+ == Usage
37
+
38
+ $ semi source-path [output-path]
39
+
40
+ == License
41
+
42
+ (The MIT License)
43
+
44
+ Copyright (c) 2009 Josh Dady
45
+
46
+ Permission is hereby granted, free of charge, to any person obtaining
47
+ a copy of this software and associated documentation files (the
48
+ 'Software'), to deal in the Software without restriction, including
49
+ without limitation the rights to use, copy, modify, merge, publish,
50
+ distribute, sublicense, and/or sell copies of the Software, and to
51
+ permit persons to whom the Software is furnished to do so, subject to
52
+ the following conditions:
53
+
54
+ The above copyright notice and this permission notice shall be
55
+ included in all copies or substantial portions of the Software.
56
+
57
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
58
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
59
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
60
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
61
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
62
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
63
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 0
3
- :patch: 2
4
2
  :major: 0
3
+ :minor: 0
4
+ :patch: 3
@@ -1,6 +1,7 @@
1
1
  # Core requirements
2
2
  require 'erb'
3
3
  require 'tempfile'
4
+ require 'time'
4
5
  require 'yaml'
5
6
 
6
7
  # Gem requirements
@@ -25,6 +26,72 @@ require 'semi-static/post'
25
26
  require 'semi-static/snippet'
26
27
  require 'semi-static/posts'
27
28
  require 'semi-static/index'
28
- require 'semi-static/categories'
29
+ require 'semi-static/tags'
29
30
  require 'semi-static/statistics'
30
31
  require 'semi-static/site'
32
+
33
+ ##
34
+ # Semi Static is yet another static site generator. I've been playing around
35
+ # with similar systems off and on for years, but it's
36
+ # Jekyll[http://github.com/mojombo/jekyll] that finally convinced me to build
37
+ # (and finish) one for myself. The main idea that I take from Jekyll is using
38
+ # Git[http://git-scm.com/] as the database. The idea from Jekyll that I'm not
39
+ # adopting is avoiding Ruby[http://ruby-lang.org/] code evaluation at all
40
+ # costs -- I'm not letting other people feed documents into it (as
41
+ # GitHub[http://github.com/] Pages[http://pages.github.com] does), so I don't
42
+ # need to protect myself from them.
43
+ #
44
+ # At some point Semi Static had a sister project, Semi Live, that would generate
45
+ # the site dynamically (probably via Rails[http://rubyonrails.org/]). I stopped
46
+ # working on it not long after I first started, so don't expect to see it on my
47
+ # projects[http://github.com/zzot] page.
48
+ #
49
+ # == Features
50
+ #
51
+ # * Layouts can be Haml[http://haml.hamptoncatlin.com/] or
52
+ # ERB[http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/] -- but not
53
+ # Liquid[http://www.liquidmarkup.org/].
54
+ # * Stylesheets can be Sass[http://haml.hamptoncatlin.com/] or raw CSS.
55
+ # * Pages and posts can be Maruku[http://maruku.rubyforge.org/] or raw HTML.
56
+ # * Code highlighting by Pygments[http://pygments.org/].
57
+ #
58
+ # == Installation
59
+ #
60
+ # The easiest way to install Semi-Static is via RubyGems[http://www.rubygems.org/]:
61
+ #
62
+ # $ sudo gem install zzot-semi-static -s http://gems.github.com/
63
+ #
64
+ # Semi-Static requires the `Haml` and `Maruku` gems and the `Pygments`
65
+ # library to be installed.
66
+ #
67
+ # == Usage
68
+ #
69
+ # $ semi source-path [output-path]
70
+ #
71
+ # == License
72
+ #
73
+ # (The MIT License)
74
+ #
75
+ # Copyright (c) 2009 Josh Dady
76
+ #
77
+ # Permission is hereby granted, free of charge, to any person obtaining
78
+ # a copy of this software and associated documentation files (the
79
+ # 'Software'), to deal in the Software without restriction, including
80
+ # without limitation the rights to use, copy, modify, merge, publish,
81
+ # distribute, sublicense, and/or sell copies of the Software, and to
82
+ # permit persons to whom the Software is furnished to do so, subject to
83
+ # the following conditions:
84
+ #
85
+ # The above copyright notice and this permission notice shall be
86
+ # included in all copies or substantial portions of the Software.
87
+ #
88
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
89
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
90
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
91
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
92
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
93
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
94
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
95
+
96
+ module SemiStatic
97
+ end
@@ -1,8 +1,7 @@
1
1
  module SemiStatic
2
- # Base represents a single source file and its associated metadata.
3
- # Base loads the source file, and strips and parses any metadata set
4
- # in the file's header. It stores an absolute path to the file so we
5
- # can refer to it later.
2
+ # Base is a single source file and its associated metadata. Base loads
3
+ # itself from the source file and strips off and parses the metadata in
4
+ # the file's header.
6
5
  class Base
7
6
  ##
8
7
  # The associated Site object
@@ -1,8 +1,10 @@
1
1
  module SemiStatic
2
+ ##
3
+ # Support conversion of the source file into another format.
2
4
  module Convertable
3
5
  include ERB::Util
4
6
 
5
- def load
7
+ def load #:nodoc:
6
8
  @content = nil
7
9
  if layout
8
10
  layout.load
@@ -10,6 +12,8 @@ module SemiStatic
10
12
  super
11
13
  end
12
14
 
15
+ ##
16
+ # Format the source file.
13
17
  def content(options={})
14
18
  return @content unless @content.nil?
15
19
 
@@ -25,7 +29,9 @@ module SemiStatic
25
29
  when '.haml'
26
30
  Haml::Engine.new(self.source_content, :filename => source_path).render(binding)
27
31
  when '.erb'
28
- ERB.new(self.source_content, nil, '-').result(binding)
32
+ erb = ERB.new self.source_content, nil, '-'
33
+ erb.filename = source_path
34
+ erb.result(binding)
29
35
  when '.html'
30
36
  self.source_content
31
37
  else
@@ -34,13 +40,13 @@ module SemiStatic
34
40
  end
35
41
  end
36
42
 
37
- def layout_name
43
+ def layout_name #:nodoc:
38
44
  unless source_metadata.nil? || !source_metadata.include?(:layout)
39
45
  source_metadata[:layout].to_sym
40
46
  end
41
47
  end
42
48
 
43
- def layout
49
+ def layout #:nodoc:
44
50
  if layout_name.nil?
45
51
  return nil
46
52
  else
@@ -48,6 +54,9 @@ module SemiStatic
48
54
  end
49
55
  end
50
56
 
57
+ ##
58
+ # Add the layout used (if any) to the list of files used to determine
59
+ # the objects modification time.
51
60
  def source_mtime
52
61
  mtime = super
53
62
  if layout && layout.source_mtime > mtime
@@ -56,6 +65,8 @@ module SemiStatic
56
65
  return mtime
57
66
  end
58
67
 
68
+ ##
69
+ # Wrap the formatted source file in the Layout (if any).
59
70
  def render(options={})
60
71
  content = self.content(options)
61
72
  if layout
@@ -65,6 +76,8 @@ module SemiStatic
65
76
  return content
66
77
  end
67
78
 
79
+ ##
80
+ # Helper method used to insert a Snippet into the formatted output.
68
81
  def snippet(name)
69
82
  name = name.to_s
70
83
  site.snippets[name].render :page => self
@@ -73,7 +86,7 @@ module SemiStatic
73
86
  # This method is adapted from Haml::Buffer#parse_object_ref -- it's
74
87
  # used to make it easier for Haml and ERB layouts to generate the
75
88
  # same output so I can use the same test output for both.
76
- def object_ref(object)
89
+ def object_ref(object) #:nodoc:
77
90
  return '' if object.nil?
78
91
  name = underscore(object.class)
79
92
  id = "#{name}_#{object.id || 'new'}"
@@ -83,7 +96,7 @@ module SemiStatic
83
96
  # Changes a word from camel case to underscores. Based on the method
84
97
  # of the same name in Rails' Inflector, but copied here so it'll run
85
98
  # properly without Rails.
86
- def underscore(camel_cased_word)
99
+ def underscore(camel_cased_word) #:nodoc:
87
100
  camel_cased_word.to_s.gsub(/::/, '_').
88
101
  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
89
102
  gsub(/([a-z\d])([A-Z])/,'\1_\2').
@@ -1,9 +1,27 @@
1
1
  module SemiStatic
2
+ ##
3
+ # Index is used to generate several site index pages that don't have a
4
+ # fixed path (i.e., the yearly index pages) from a single source file.
5
+ # It can have a Layout and use any number of Snippets. Index's modification
6
+ # time is the most recent of itself, its layout, and any Snippets used.
7
+ # Indices are also considered out-of-date if any posts in the index's range
8
+ # are changed.
2
9
  class Index < Base
3
10
  include Convertable
4
11
 
5
- attr_accessor :posts, :context
12
+ ##
13
+ # Posts in range for the Index's current path.
14
+ attr_accessor :posts
6
15
 
16
+ ##
17
+ # The Index's current context (usually a Date).
18
+ attr_accessor :context
19
+
20
+ ##
21
+ # Initializes a new Index
22
+ #
23
+ # +site+:: The Site object we belong to
24
+ # +path+:: The relative path to the source file
7
25
  def initialize(site, path)
8
26
  super
9
27
  @metadata = [ :layout ]
@@ -1,9 +1,18 @@
1
1
  module SemiStatic
2
+ ##
3
+ # Layout embeds the formatted output of a Convertable within a large document.
2
4
  class Layout < Base
3
5
  include Convertable
4
6
 
7
+ ##
8
+ # The Layout's name
5
9
  attr_reader :name
6
10
 
11
+ ##
12
+ # Initialize a new Layout
13
+ #
14
+ # +site+: The Site we belong to.
15
+ # +path+: The path to the source file.
7
16
  def initialize(site, path)
8
17
  super
9
18
  @metadata = [ :layout ]
@@ -10,10 +10,6 @@ module SemiStatic
10
10
  # The Post's name
11
11
  attr_reader :name
12
12
 
13
- ##
14
- # The Post's Category
15
- attr_reader :category
16
-
17
13
  ##
18
14
  # The Post's Tags
19
15
  attr_reader :tags
@@ -57,9 +53,6 @@ module SemiStatic
57
53
 
58
54
  @name = File.basename(source_path, source_ext)
59
55
 
60
- @category = site.categories[source_metadata[:category]]
61
- @category << self
62
-
63
56
  @tags = []
64
57
  unless source_metadata[:tags].nil?
65
58
  for tag in source_metadata[:tags]
@@ -92,20 +85,6 @@ module SemiStatic
92
85
  return "#{uri}"
93
86
  end
94
87
 
95
- # def comments_link
96
- # "#{uri}#comments"
97
- # end
98
- #
99
- # def comment_count
100
- # 0
101
- # end
102
-
103
- ##
104
- # Formatted date the Post was published (i.e., "March 15, 2009")
105
- def date
106
- created.strftime '%B %e, %Y'
107
- end
108
-
109
88
  ##
110
89
  # Year the Post was published as a String (i.e., "2009")
111
90
  def year
@@ -1,7 +1,27 @@
1
1
  module SemiStatic
2
+ ##
3
+ # Collection of Posts for the current site.
2
4
  class Posts
3
- attr_reader :site, :posts, :names, :indices
5
+ ##
6
+ # The Site object we belong to.
7
+ attr_reader :site
4
8
 
9
+ ##
10
+ # The raw list of posts.
11
+ attr_reader :posts
12
+
13
+ ##
14
+ # Posts indexed by name.
15
+ attr_reader :names
16
+
17
+ ##
18
+ # Indices that correspond to the Posts.
19
+ attr_reader :indices
20
+
21
+ ##
22
+ # Initializes a new Posts
23
+ #
24
+ # +site+: The Site we belong to.
5
25
  def initialize(site)
6
26
  @site = site
7
27
  @posts = []
@@ -9,8 +29,14 @@ module SemiStatic
9
29
  @indices = Set.new
10
30
  end
11
31
 
32
+ ##
33
+ # The format of the Date portion of a post's filename.
12
34
  NAME_RE = /^([0-9]{4})-([0-9]{2})-([0-9]{2})-(.*)/
13
35
 
36
+ ##
37
+ # Parse the given file as a Post and add it to the list.
38
+ #
39
+ # +source_path+: Path to the source file
14
40
  def <<(source_path)
15
41
  unless File.file?(source_path)
16
42
  $stderr.puts "[#{source_path}]"
@@ -28,6 +54,10 @@ module SemiStatic
28
54
  end
29
55
  end
30
56
 
57
+ ##
58
+ # Truncate the list of Posts to the given number (to speed up testing).
59
+ #
60
+ # +count+: The number of posts to keep.
31
61
  def chop!(count)
32
62
  raise ArgumentError unless count > 0
33
63
  posts = self.posts.first(count)
@@ -43,10 +73,16 @@ module SemiStatic
43
73
  end
44
74
  end
45
75
 
76
+ ##
77
+ # Number of posts.
46
78
  def length
47
79
  self.posts.length
48
80
  end
49
81
 
82
+ ##
83
+ # Fetch the least recent posts.
84
+ #
85
+ # +n+: Number of Posts to return.
50
86
  def first(n=nil)
51
87
  if n.nil?
52
88
  self.posts.first
@@ -55,6 +91,10 @@ module SemiStatic
55
91
  end
56
92
  end
57
93
 
94
+ ##
95
+ # Fetch the most recent posts.
96
+ #
97
+ # +n+: Number of Posts to return.
58
98
  def last(n=nil)
59
99
  if n.nil?
60
100
  self.posts.last
@@ -63,6 +103,8 @@ module SemiStatic
63
103
  end
64
104
  end
65
105
 
106
+ ##
107
+ # Fetch the Posts for the given Date range.
66
108
  def from(year, month=nil, day=nil)
67
109
  if year.is_a?(String) && month.nil? && day.nil?
68
110
  date = year.split('/', 3)
@@ -95,15 +137,21 @@ module SemiStatic
95
137
  return result
96
138
  end
97
139
 
140
+ ##
141
+ # Get the post with the given name.
98
142
  def [](name)
99
143
  return self.names[name]
100
144
  end
101
145
 
102
- def each(&block)
146
+ ##
147
+ # Iterate over all posts.
148
+ def each(&block) # :yields: Post
103
149
  self.posts.each(&block)
104
150
  end
105
151
 
106
- def each_index(&block)
152
+ ##
153
+ # Iterate over all indices.
154
+ def each_index(&block) # :yields: String
107
155
  indices.each(&block)
108
156
  end
109
157
  end