Class: Jekyll::Post

Inherits:
Object
  • Object
show all
Includes:
Comparable, Convertible
Defined in:
lib/jekyll/post.rb

Constant Summary collapse

MATCHER =
/^(.+\/)*(\d+-\d+-\d+(?:_\d+-\d+)?)-(.*)(\.[^.]+)$/

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Convertible

#content_type, #do_layout, #read_yaml, #render_haml_in_context, #to_s, #transform

Constructor Details

#initialize(site, source, dir, name) ⇒ Post

Initialize this Post instance.

+site+ is the Site
+base+ is the String path to the dir containing the post file
+name+ is the String filename of the post file
+categories+ is an Array of Strings for the categories for this post
+tags+ is an Array of Strings for the tags for this post

Returns <Post>



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/jekyll/post.rb', line 38

def initialize(site, source, dir, name)
  @site = site
  @base = File.join(source, dir, '_posts')
  @name = name

  self.categories = dir.split('/').reject { |x| x.empty? }

  parts = name.split('/')
  self.topics = parts.size > 1 ? parts[0..-2] : []

  self.process(name)
  self.data = self.site.post_defaults.dup
  self.read_yaml(@base, name)

  extract_title_from_first_header_or_slug

  if self.data.has_key?('published') && self.data['published'] == false
    self.published = false
  else
    self.published = true
  end

  if self.data.has_key?("tag")
    self.tags = [self.data["tag"]]
  elsif self.data.has_key?("tags")
    self.tags = self.data['tags']
  else
    self.tags = []
  end
  
  if self.categories.empty?
    if self.data.has_key?('category')
      self.categories << self.data['category']
    elsif self.data.has_key?('categories')
      # Look for categories in the YAML-header, either specified as
      # an array or a string.
      if self.data['categories'].kind_of? String
        self.categories = self.data['categories'].split
      else
        self.categories = self.data['categories']
      end
    end
  end
end

Class Attribute Details

.lsiObject

Returns the value of attribute lsi.



8
9
10
# File 'lib/jekyll/post.rb', line 8

def lsi
  @lsi
end

Instance Attribute Details

#categoriesObject



26
27
28
# File 'lib/jekyll/post.rb', line 26

def categories
  @categories ||= []
end

#contentObject

Returns the value of attribute content.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def content
  @content
end

#dataObject

Returns the value of attribute data.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def data
  @data
end

#dateObject

The post date and time

Returns <Time>



182
183
184
# File 'lib/jekyll/post.rb', line 182

def date
  @date
end

#excerptObject

Returns the value of attribute excerpt.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def excerpt
  @excerpt
end

#extObject

Returns the value of attribute ext.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def ext
  @ext
end

#outputObject

Returns the value of attribute output.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def output
  @output
end

#publishedObject

Returns the value of attribute published.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def published
  @published
end

#remainderObject

Returns the value of attribute remainder.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def remainder
  @remainder
end

#siteObject

Returns the value of attribute site.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def site
  @site
end

#slugObject

Returns the value of attribute slug.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def slug
  @slug
end

#tagsObject

Returns the value of attribute tags.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def tags
  @tags
end

#topicsObject

Returns the value of attribute topics.



23
24
25
# File 'lib/jekyll/post.rb', line 23

def topics
  @topics
end

Class Method Details

.valid?(name) ⇒ Boolean

Post name validator. Post filenames must be like:

2008-11-05-my-awesome-post.textile

or:

2008-11-05_12-45-my-awesome-post.textile

Returns <Bool>

Returns:

  • (Boolean)


19
20
21
# File 'lib/jekyll/post.rb', line 19

def self.valid?(name)
  name =~ MATCHER
end

Instance Method Details

#<=>(other) ⇒ Object

Spaceship is based on Post#date, slug

Returns -1, 0, 1



86
87
88
89
90
91
92
# File 'lib/jekyll/post.rb', line 86

def <=>(other)
  cmp = self.date <=> other.date
  if 0 == cmp
   cmp = self.slug <=> other.slug
  end
  return cmp
end

#dirObject

The generated directory into which the post will be placed upon generation. This is derived from the permalink or, if permalink is absent, set to the default date e.g. “/2008/11/05/” if the permalink style is :date, otherwise nothing

Returns <String>



112
113
114
# File 'lib/jekyll/post.rb', line 112

def dir
  File.dirname(generated_path)
end

#extract_title_from_first_header_or_slugObject

Attempt to extract title from topmost header or slug.

Returns <String>



261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/jekyll/post.rb', line 261

def extract_title_from_first_header_or_slug
  # Done before the transformation to HTML, or it won't go into <title>s.
  self.data["title"] ||=
    case content_type
    when 'textile'
      self.content[/\A\s*h\d\.\s*(.+)/, 1]               # h1. Header
    when 'markdown'
      self.content[/\A\s*#+\s*(.+)\s*#*$/, 1] ||         # "# Header"
      self.content[/\A\s*(\S.*)\r?\n\s*(-+|=+)\s*$/, 1]  # "Header\n====="
    end
  self.data["title"] ||= self.slug.split('-').select {|w| w.capitalize! || w }.join(' ')
end

#generated_pathObject

The generated relative path of this post e.g. /2008/11/05/my-awesome-post.html

Returns <String>



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/jekyll/post.rb', line 142

def generated_path
  return permalink if permalink

  @generated_path ||= {
    "year"       => date.strftime("%Y"),
    "month"      => date.strftime("%m"),
    "day"        => date.strftime("%d"),
    "title"      => CGI.escape(slug),
    "categories" => categories.sort.join('/')
  }.inject(template) { |result, token|
    result.gsub(/:#{token.first}/, token.last)
  }.gsub("//", "/")
end

#idObject

The UID for this post (useful in feeds) e.g. /2008/11/05/my-awesome-post

Returns <String>



168
169
170
# File 'lib/jekyll/post.rb', line 168

def id
  File.join(self.dir, self.slug)
end

#inspectObject



292
293
294
# File 'lib/jekyll/post.rb', line 292

def inspect
  "<Post: #{self.id}>"
end

#nextObject



296
297
298
299
300
301
302
303
304
# File 'lib/jekyll/post.rb', line 296

def next
  pos = self.site.posts.index(self)

  if pos && pos < self.site.posts.length-1
    self.site.posts[pos+1]
  else
    nil
  end
end

#pathObject

The path to the post file.

Returns <String>



196
197
198
# File 'lib/jekyll/post.rb', line 196

def path
  File.expand_path(File.join(@base, @name))
end

The full path and filename of the post. Defined in the YAML of the post body (Optional)

Returns <String>



121
122
123
# File 'lib/jekyll/post.rb', line 121

def permalink
  self.data && self.data['permalink']
end

#previousObject



306
307
308
309
310
311
312
313
# File 'lib/jekyll/post.rb', line 306

def previous
  pos = self.site.posts.index(self)
  if pos && pos > 0
    self.site.posts[pos-1]
  else
    nil
  end
end

#process(name) ⇒ Object

Extract information from the post filename

+name+ is the String filename of the post file

Returns nothing



98
99
100
101
102
103
104
# File 'lib/jekyll/post.rb', line 98

def process(name)
  m, cats, date, slug, ext = *name.match(MATCHER)
  date = date.sub(/_(\d+)-(\d+)\Z/, ' \1:\2')  # Make optional time part parsable.
  self.date = Time.parse(date)
  self.slug = slug
  self.ext = ext
end

Calculate related posts.

Returns [<Post>]



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/jekyll/post.rb', line 203

def related_posts(posts)
  return [] unless posts.size > 1

  if self.site.lsi
    self.class.lsi ||= begin
      puts "Running the classifier... this could take a while."
      lsi = Classifier::LSI.new
      posts.each { |x| $stdout.print(".");$stdout.flush;lsi.add_item(x) }
      puts ""
      lsi
    end

    related = self.class.lsi.find_related(self.content, 11)
    related - [self]
  else
    (posts - [self])[0..9]
  end
end

#render(layouts, site_payload) ⇒ Object

Add any necessary layouts to this post

+layouts+ is a Hash of {"name" => "layout"}
+site_payload+ is the site payload hash

Returns nothing



227
228
229
230
231
232
233
234
235
236
237
# File 'lib/jekyll/post.rb', line 227

def render(layouts, site_payload)
  # construct payload
  payload =
  {
    "site" => { "related_posts" => related_posts(site_payload["site"]["posts"]) },
    "page" => self.to_liquid
  }
  payload = payload.deep_merge(site_payload)

  do_layout(payload, layouts)
end

#templateObject



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/jekyll/post.rb', line 125

def template
  case self.site.permalink_style
  when :pretty
    "/:categories/:year/:month/:day/:title/"
  when :none
    "/:categories/:title.html"
  when :date
    "/:categories/:year/:month/:day/:title.html"
  else
    self.site.permalink_style.to_s
  end
end

#titleObject

The post title

Returns <String>



175
176
177
# File 'lib/jekyll/post.rb', line 175

def title
  self.data && self.data["title"]
end

#to_liquidObject

Convert this post into a Hash for use in Liquid templates.

Returns <Hash>



277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/jekyll/post.rb', line 277

def to_liquid
  { "title"      => self.title,
    "url"        => self.url,
    "date"       => self.date,
    "id"         => self.id,
    "topics"     => self.topics,
    "categories" => self.categories,
    "next"       => self.next,
    "previous"   => self.previous,
    "tags"       => self.tags,
    "content"    => self.content,
    "excerpt"    => self.excerpt,
    "remainder"  => self.remainder }.deep_merge(self.data)
end

#urlObject

The generated relative url of this post e.g. /2008/11/05/my-awesome-post

Returns <String>



160
161
162
# File 'lib/jekyll/post.rb', line 160

def url
  site.config['multiviews'] ? generated_path.sub(/\.html$/, '') : generated_path
end

#write(dest) ⇒ Object

Write the generated post file to the destination directory.

+dest+ is the String path to the destination dir

Returns nothing



243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/jekyll/post.rb', line 243

def write(dest)
  FileUtils.mkdir_p(File.join(dest, dir))

  path = File.join(dest, self.generated_path)

  if template[/\.html$/].nil?
    FileUtils.mkdir_p(path)
    path = File.join(path, "index.html")
  end

  File.open(path, 'w') do |f|
    f.write(self.output)
  end
end