octopress-popular-posts 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +7 -0
- data/README.md +105 -0
- data/bin/octopress-popular-posts +2 -0
- data/lib/popular_posts.rb +15 -0
- data/lib/popular_posts/utilities.rb +86 -0
- data/templates/asides/popular_posts.html +10 -0
- data/templates/plugins/popular_post.rb +194 -0
- metadata +103 -0
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (C) 2012 Wong Liang Zan<zan@liangzan.net>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Octopress Popular Posts Plugin
|
2
|
+
|
3
|
+
Popular posts plugin adds a popular posts asides section to your [Octopress](http://octopress.org) blog. Popularity of the post is calculated by the [Google page rank](http://en.wikipedia.org/wiki/PageRank).
|
4
|
+
|
5
|
+
## How it works
|
6
|
+
|
7
|
+
The popular posts template is generated with the blog. It makes queries to check the page rank for each post. Once generated, the popular posts asides section is a static page. Which means popularity is updated only when the site is generated.
|
8
|
+
|
9
|
+
Popular posts plugin caches the page rank results of each post. The results are stored in the __.page_ranks__ directory of your blog. When there is a cache, the plugin will read from it. When there is no cache, it will generate one. Caches expires in 1 month. This shortens the time needed to generate your blog.
|
10
|
+
|
11
|
+
Google page rank is updated every 3 months. A static page is sufficient as page rank don't change every hour.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
The plugin is distributed by Ruby gems.
|
16
|
+
|
17
|
+
Add this line to your __Gemfile__
|
18
|
+
|
19
|
+
```
|
20
|
+
gem 'octopress-popular-posts'
|
21
|
+
```
|
22
|
+
|
23
|
+
Install it using Bundler
|
24
|
+
|
25
|
+
```
|
26
|
+
bundle install
|
27
|
+
```
|
28
|
+
|
29
|
+
We have to run installation commands to copy the plugin to your source
|
30
|
+
|
31
|
+
```
|
32
|
+
bundle exec octopress-popular-posts install
|
33
|
+
```
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
Once installed, the popular posts asides section will be generated whenever you run
|
38
|
+
|
39
|
+
```
|
40
|
+
rake generate
|
41
|
+
```
|
42
|
+
|
43
|
+
No additional steps are necesary.
|
44
|
+
|
45
|
+
## Post install configurations
|
46
|
+
|
47
|
+
In your blog's __config.yml__, add this line.
|
48
|
+
|
49
|
+
```
|
50
|
+
popular_posts_count: 5 # Posts in the sidebar Popular Posts section
|
51
|
+
```
|
52
|
+
|
53
|
+
This sets the number of popular posts to show.
|
54
|
+
|
55
|
+
Next, we need to add the popular post aside section.
|
56
|
+
|
57
|
+
```
|
58
|
+
default_asides: [custom/asides/about.html, custom/asides/subscribe.html, custom/asides/popular_posts.html, asides/recent_posts.html, asides/github.html, asides/twitter.html, asides/delicious.html, asides/pinboard.html, asides/googleplus.html]
|
59
|
+
```
|
60
|
+
|
61
|
+
Note the __custom/asides/popular_posts.html__ that is added on the third entry of the array.
|
62
|
+
|
63
|
+
Once done, you need to generate the blog.
|
64
|
+
|
65
|
+
```
|
66
|
+
rake generate
|
67
|
+
```
|
68
|
+
|
69
|
+
The first run will take some time as the cache for popular plugins is created. You should see the popular posts aside section on your blog.
|
70
|
+
|
71
|
+
I also suggest that you ignore the cached page rank files by adding this line to your __.gitignore__
|
72
|
+
|
73
|
+
```
|
74
|
+
.page_ranks
|
75
|
+
```
|
76
|
+
|
77
|
+
## Updating the plugin
|
78
|
+
|
79
|
+
Upon new updates, run the following command
|
80
|
+
|
81
|
+
```
|
82
|
+
bundle exec octopress-popular-posts install
|
83
|
+
```
|
84
|
+
|
85
|
+
## Post remove configurations
|
86
|
+
|
87
|
+
To remove the plugin, run the following command
|
88
|
+
|
89
|
+
```
|
90
|
+
bundle exec octopress-popular-posts remove
|
91
|
+
```
|
92
|
+
|
93
|
+
You will also need to remove the following configurations
|
94
|
+
|
95
|
+
1. The octopress-popular-posts gem from your __Gemfile__
|
96
|
+
2. The __popular_posts_count__ variable from your __config.yml__
|
97
|
+
3. The popular posts asides under __defaults_asides__ from your __config.yml__
|
98
|
+
|
99
|
+
## Other themes and plugins
|
100
|
+
|
101
|
+
Shameless plug: more themes and plugins are available on [Octopress themes](http://octopressthemes.com). Feel free to take a look.
|
102
|
+
|
103
|
+
## Copyright
|
104
|
+
|
105
|
+
Copyright © 2012 [Wong Liang Zan](http://liangzan.net). MIT License
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require File.join(File.dirname(__FILE__) + '/popular_posts/utilities')
|
3
|
+
|
4
|
+
# Handles the command line options
|
5
|
+
if ARGV.length == 1 && ARGV[0] == 'install'
|
6
|
+
OctopressThemes::PopularPost::Utilities.install
|
7
|
+
puts 'Octopress popular posts plugin: installed'
|
8
|
+
puts 'Please view the README on https://github.com/octopress-themes/popular-posts for post installation configurations.'
|
9
|
+
elsif ARGV.length == 1 && ARGV[0] == 'remove'
|
10
|
+
OctopressThemes::PopularPost::Utilities.remove
|
11
|
+
puts 'Octopress popular posts plugin: removed'
|
12
|
+
puts 'Please view the README on https://github.com/octopress-themes/popular-posts for post removal configurations.'
|
13
|
+
else
|
14
|
+
puts 'Usage: octopress-popular-posts [install|remove]'
|
15
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Public: Module for handling the installation and removal of the Octopress popular post
|
2
|
+
# plugin
|
3
|
+
module OctopressThemes
|
4
|
+
module PopularPost
|
5
|
+
module Utilities
|
6
|
+
PLUGINS_DIR = File.expand_path(File.dirname(__FILE__) + '/../../templates/plugins')
|
7
|
+
ASIDES_DIR = File.expand_path(File.dirname(__FILE__) + '/../../templates/asides')
|
8
|
+
|
9
|
+
# Public: Installs the templates to the designated locations
|
10
|
+
#
|
11
|
+
# Examples
|
12
|
+
#
|
13
|
+
# OctopressThemes::PopularPost.install
|
14
|
+
# # => nil
|
15
|
+
#
|
16
|
+
# Returns nothing
|
17
|
+
def self.install
|
18
|
+
FileUtils.copy_file plugin_path, plugin_destination
|
19
|
+
FileUtils.copy_file aside_path, aside_destination
|
20
|
+
end
|
21
|
+
|
22
|
+
# Public: Removes plugin files
|
23
|
+
#
|
24
|
+
# Examples
|
25
|
+
#
|
26
|
+
# OctopressThemes::PopularPost.remove
|
27
|
+
# # => nil
|
28
|
+
#
|
29
|
+
# Returns nothing
|
30
|
+
def self.remove
|
31
|
+
FileUtils.rm plugin_destination
|
32
|
+
FileUtils.rm aside_destination
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
# Private: Returns the file path to the plugin template
|
38
|
+
#
|
39
|
+
# Examples
|
40
|
+
#
|
41
|
+
# plugin_path
|
42
|
+
# # => /path/to/plugin.rb
|
43
|
+
#
|
44
|
+
# Returns a String
|
45
|
+
def self.plugin_path
|
46
|
+
File.join(PLUGINS_DIR, 'popular_post.rb')
|
47
|
+
end
|
48
|
+
|
49
|
+
# Private: Returns the file path to the plugin destination
|
50
|
+
#
|
51
|
+
# Examples
|
52
|
+
#
|
53
|
+
# plugin_destination
|
54
|
+
# # => /path/to/destination/plugin.rb
|
55
|
+
#
|
56
|
+
# Returns a String
|
57
|
+
def self.plugin_destination
|
58
|
+
File.join(Dir.pwd, 'plugins', 'popular_post.rb')
|
59
|
+
end
|
60
|
+
|
61
|
+
# Private: Returns the file path to the aside template
|
62
|
+
#
|
63
|
+
# Examples
|
64
|
+
#
|
65
|
+
# aside_path
|
66
|
+
# # => /path/to/aside.html
|
67
|
+
#
|
68
|
+
# Returns a String
|
69
|
+
def self.aside_path
|
70
|
+
File.join(ASIDES_DIR, 'popular_posts.html')
|
71
|
+
end
|
72
|
+
|
73
|
+
# Private: Returns the file path to the aside destination
|
74
|
+
#
|
75
|
+
# Examples
|
76
|
+
#
|
77
|
+
# aside_destination
|
78
|
+
# # => /path/to/destination/aside.html
|
79
|
+
#
|
80
|
+
# Returns a String
|
81
|
+
def self.aside_destination
|
82
|
+
File.join(Dir.pwd, 'source', '_includes', 'custom', 'asides', 'popular_posts.html')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'page_rankr'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
# Public: Popular posts plugin for Octopress. This plugin
|
5
|
+
# opens up the Jekyll Post and Site classes to allow
|
6
|
+
# Jekyll to render the popular posts aside section
|
7
|
+
module OctopressThemes
|
8
|
+
module PopularPost
|
9
|
+
module Post
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
if base.class.instance_methods.include?('page_rank') ||
|
13
|
+
base.class.protected_instance_methods.include?(%w(page_rank_expired? cache_page_rank read_page_rank_cache query_page_rank))
|
14
|
+
raise 'Octopress Popular Posts: Name clashes'
|
15
|
+
else
|
16
|
+
base.class_eval do
|
17
|
+
include PublicInstanceMethods
|
18
|
+
protected
|
19
|
+
include ProtectedInstanceMethods
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module PublicInstanceMethods
|
25
|
+
|
26
|
+
PAGE_RANK_CACHE = '.page_ranks'
|
27
|
+
|
28
|
+
# Public: Returns the page rank of the post. It also caches the page rank.
|
29
|
+
# If a cached page rank is found, it returns the cached version.
|
30
|
+
# Caches expire in a month.
|
31
|
+
#
|
32
|
+
# host - The String which is the host name of the web site.
|
33
|
+
# It is defined in _config.yml. It is needed to form the full url
|
34
|
+
# of the post.
|
35
|
+
#
|
36
|
+
# Examples
|
37
|
+
#
|
38
|
+
# page_rank('http://foo.com')
|
39
|
+
# # => 3
|
40
|
+
#
|
41
|
+
# Returns the Integer page rank of the post
|
42
|
+
def page_rank(host)
|
43
|
+
post_name = self.url.split('/').last
|
44
|
+
cache_dir_path = File.join(Dir.pwd, PAGE_RANK_CACHE)
|
45
|
+
post_path = File.join(Dir.pwd, PAGE_RANK_CACHE, post_name)
|
46
|
+
|
47
|
+
if !File.directory?(cache_dir_path)
|
48
|
+
Dir.mkdir cache_dir_path
|
49
|
+
end
|
50
|
+
|
51
|
+
if File.exists?(post_path) && !page_rank_expired?(post_path)
|
52
|
+
read_page_rank_cache(post_path)[:rank]
|
53
|
+
else
|
54
|
+
post_page_rank = query_page_rank(host)
|
55
|
+
page_rank_content = { url: self.url, rank: post_page_rank }
|
56
|
+
cache_page_rank(page_rank_content, post_path)
|
57
|
+
post_page_rank
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module ProtectedInstanceMethods
|
63
|
+
|
64
|
+
DAY_IN_SECS = 86400
|
65
|
+
|
66
|
+
# Private: Checks if the cached page rank has expired. It is set
|
67
|
+
# to expire in 1 month. It assumes the presence of a
|
68
|
+
# cached page rank.
|
69
|
+
#
|
70
|
+
# cache_path - The String which is the file path to the cached
|
71
|
+
# page rank.
|
72
|
+
#
|
73
|
+
# Examples
|
74
|
+
#
|
75
|
+
# page_rank_expired?('/path/to/cached/page_rank')
|
76
|
+
# # => true
|
77
|
+
#
|
78
|
+
# Returns a Boolean.
|
79
|
+
def page_rank_expired?(cache_path)
|
80
|
+
file_modified_time = File.mtime(cache_path)
|
81
|
+
time_past = Time.now - file_modified_time
|
82
|
+
|
83
|
+
# if file has not been modified for over a month
|
84
|
+
time_past > (30 * DAY_IN_SECS)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Private: Caches the page rank of the post.
|
88
|
+
#
|
89
|
+
# page_rank_content - The Hash which is contains rank and
|
90
|
+
# the full url of the post.
|
91
|
+
# cache_path - The String which is the file path
|
92
|
+
# to the cache
|
93
|
+
#
|
94
|
+
# Examples
|
95
|
+
#
|
96
|
+
# cache_page_rank({url: 'http://foo/blog/bar', rank: 2}, '/path/to/cache')
|
97
|
+
# # => nil
|
98
|
+
#
|
99
|
+
# Returns nothing.
|
100
|
+
def cache_page_rank(page_rank_content, cache_path)
|
101
|
+
File.open(cache_path, 'w') do |file|
|
102
|
+
file.puts YAML.dump(page_rank_content)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Private: Reads the cached page rank
|
107
|
+
#
|
108
|
+
# cache_path - The String which is the file path to the cache
|
109
|
+
#
|
110
|
+
# Examples
|
111
|
+
#
|
112
|
+
# read_page_rank('/path/to/cache')
|
113
|
+
# # => {url: 'http://foo', rank: 2}
|
114
|
+
#
|
115
|
+
# Returns a Hash
|
116
|
+
def read_page_rank_cache(cache_path)
|
117
|
+
YAML.load_file(cache_path)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Private: Queries Google for the page rank of the post
|
121
|
+
#
|
122
|
+
# host - The String which is the host name of the web site.
|
123
|
+
# It is defined in _config.yml. It is needed to form the full url
|
124
|
+
# of the post.
|
125
|
+
#
|
126
|
+
# Examples
|
127
|
+
#
|
128
|
+
# query_page_rank('http://foo.com')
|
129
|
+
# # => {:google => 3}
|
130
|
+
#
|
131
|
+
# Returns a Hash
|
132
|
+
def query_page_rank(host)
|
133
|
+
PageRankr.ranks("#{host}#{self.url}", :google)[:google] || 0
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end # Post
|
137
|
+
|
138
|
+
module Site
|
139
|
+
def self.included(base)
|
140
|
+
base.class_eval do
|
141
|
+
attr_accessor :popular_posts
|
142
|
+
alias_method :old_read, :read
|
143
|
+
alias_method :old_site_payload, :site_payload
|
144
|
+
|
145
|
+
# Public: Making use of the read method to define popular
|
146
|
+
# posts. Popular posts are sorted by page rank
|
147
|
+
#
|
148
|
+
# Examples
|
149
|
+
#
|
150
|
+
# read
|
151
|
+
# # => nil
|
152
|
+
#
|
153
|
+
# Returns nothing
|
154
|
+
def read
|
155
|
+
old_read
|
156
|
+
host = self.config['url']
|
157
|
+
self.popular_posts = self.posts.sort do |post_x, post_y|
|
158
|
+
if post_y.page_rank(host) > post_x.page_rank(host) then 1
|
159
|
+
elsif post_y.page_rank(host) == post_x.page_rank(host) then 0
|
160
|
+
else -1
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Public: We need to add popular_posts to site_payload, so that
|
166
|
+
# it gets passed to Liquid to be rendered.
|
167
|
+
#
|
168
|
+
# Examples
|
169
|
+
#
|
170
|
+
# site_payload
|
171
|
+
# # => nil
|
172
|
+
#
|
173
|
+
# Returns nothing
|
174
|
+
def site_payload
|
175
|
+
old_site_hash = old_site_payload
|
176
|
+
old_site_hash["site"].merge!({"popular_posts" => self.popular_posts})
|
177
|
+
old_site_hash
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end # included
|
181
|
+
end # Site
|
182
|
+
|
183
|
+
end # PopularPost
|
184
|
+
end # OctopressThemes
|
185
|
+
|
186
|
+
module Jekyll
|
187
|
+
class Post
|
188
|
+
include OctopressThemes::PopularPost::Post
|
189
|
+
end
|
190
|
+
|
191
|
+
class Site
|
192
|
+
include OctopressThemes::PopularPost::Site
|
193
|
+
end
|
194
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: octopress-popular-posts
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Wong Liang Zan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: PageRankr
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.11.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.11.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: jekyll
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.11.2
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.11.2
|
62
|
+
description: Octopress popular posts adds a popular posts asides section to your Octopress
|
63
|
+
blog. It makes use of Google page rank to determine the popularity of the posts.
|
64
|
+
email:
|
65
|
+
- zan@liangzan.net
|
66
|
+
executables:
|
67
|
+
- octopress-popular-posts
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- lib/popular_posts/utilities.rb
|
72
|
+
- lib/popular_posts.rb
|
73
|
+
- bin/octopress-popular-posts
|
74
|
+
- templates/asides/popular_posts.html
|
75
|
+
- templates/plugins/popular_post.rb
|
76
|
+
- LICENSE
|
77
|
+
- README.md
|
78
|
+
homepage: https://github.com/octopress-themes/popular-posts
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 1.8.24
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: Adds a popular posts asides section to your Octopress blog.
|
103
|
+
test_files: []
|