octopress-gauges-popular-posts 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ todo.taskpaper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in octopress-gauges-popular-posts.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Bastian Bartmann
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # Octopress Gauges Popular Posts Plugin #
2
+
3
+ Popular posts plugin adds a popular asides section to your [Octopress][1] blog. Popularity of the posts is calculated by page views tracked through [Gaug.es][2].
4
+
5
+ This gem is modelled after the [octopress-popular-posts gem][2].
6
+
7
+ ## Installation ##
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'octopress-gauges-popular-posts'
12
+
13
+ Install it using Bundler:
14
+
15
+ $ bundle
16
+
17
+ And run the installation to copy the plugin to your source:
18
+
19
+ $ bundle exec octopress-gauges-popular-posts install
20
+
21
+ ## Post install configurations ##
22
+
23
+ Add the Gaug.es Tracking ID of your blog and your Gaug.es API token to your **config.yml**:
24
+
25
+ gauges_tracking_id: <your-tracking-id>
26
+
27
+ Also add the following line:
28
+
29
+ popular_posts_count: 5 # Posts in the sidebar Popular Posts section
30
+
31
+ This sets the number of popular posts to show.
32
+
33
+ Next, we need to add the popular post aside section:
34
+
35
+ 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]
36
+
37
+ Note the **custom/asides/popular_posts.html** that is added on the third entry of the array.
38
+
39
+ The installation created the `config` file in the `.page_views` directory. In there you have to add your Gaug.es API token and you can also add the date started tracking your site with Gaug.es.
40
+
41
+ :token: <your-api-token>
42
+ :signup_date: 2013-06-03
43
+
44
+ If a `singup_date` is given, thes gem will fetch the views since then. Depending on the distance, this may take a while.
45
+
46
+ Once done, you need to generate the blog:
47
+
48
+ $ rake generate
49
+
50
+ I also suggest that you ignore the cached page views files and the config file with your Gaug.es API token by adding this line to your **.gitignore**:
51
+
52
+ .page_views
53
+
54
+ ## Usage ##
55
+
56
+ Once installed, the popular posts asides section will be generated whenever you run
57
+
58
+ $ rake generate
59
+
60
+ No additional steps are necesary.
61
+
62
+ ## Updating the plugin ##
63
+
64
+ After updating the gem:
65
+
66
+ $ bundle update octopress-gauges-popular-posts
67
+
68
+ Run the following command:
69
+
70
+ $ bundle exec octopress-gauges-popular-posts install
71
+
72
+ ## Removal ##
73
+
74
+ To remove the plugin, run the following command:
75
+
76
+ $ bundle exec octopress-gauges-popular-posts remove
77
+
78
+ You will also need to remove the following configurations:
79
+
80
+ 1. The octopress-popular-posts gem from your **Gemfile**
81
+ 2. The **gauges_tracking_id** variable from your **config.yml**
82
+ 3. The **popular_posts_count** variable from your **config.yml**
83
+ 4. The popular posts asides under **defaults_asides** from your **config.yml**
84
+ 5. The cache directory **.page_views**
85
+
86
+ ## Contributing ##
87
+
88
+ 1. Fork it
89
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
90
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
91
+ 4. Push to the branch (`git push origin my-new-feature`)
92
+ 5. Create new Pull Request
93
+
94
+ [1]: http://octopress.org
95
+ [2]: http://get.gaug.es
96
+ [2]: https://github.com/octothemes/popular-posts
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/octopress-gauges-popular-posts')
@@ -0,0 +1,16 @@
1
+ require 'fileutils'
2
+ require "octopress-gauges-popular-posts/version"
3
+ require 'octopress-gauges-popular-posts/utilities'
4
+
5
+ # Handles the command line options
6
+ if ARGV.length == 1 && ARGV[0] == 'install'
7
+ PopularPost::Utilities.install
8
+ puts 'Octopress Gauges Popular Posts plugin: installed'
9
+ puts 'Please view the README on https://github.com/coding-chimp/octopress-gauges-popular-posts for post installation configurations.'
10
+ elsif ARGV.length == 1 && ARGV[0] == 'remove'
11
+ PopularPost::Utilities.remove
12
+ puts 'Octopress Gauges Popular Posts plugin: removed'
13
+ puts 'Please view the README on https://github.com/coding-chimp/octopress-gauges-popular-posts for post removal configurations.'
14
+ else
15
+ puts 'Usage: octopress-gauges-popular-posts [install|remove]'
16
+ end
@@ -0,0 +1,121 @@
1
+ # Public: Module for handling the installation and removal of the Octopress Gauges Popular Post
2
+ # plugin
3
+ module PopularPost
4
+ module Utilities
5
+ TEMPLATES_DIR = File.expand_path(File.dirname(__FILE__) + '/../../templates')
6
+
7
+ # Public: Installs the templates to the designated locations
8
+ #
9
+ # Examples
10
+ #
11
+ # PopularPost.install
12
+ # # => nil
13
+ #
14
+ # Returns nothing
15
+ def self.install
16
+ FileUtils.copy_file plugin_path, plugin_destination
17
+ FileUtils.copy_file aside_path, aside_destination
18
+ Dir.mkdir cache_path unless File.directory?(cache_path)
19
+ FileUtils.copy_file config_path, config_destination unless File.exists?(config_path)
20
+ end
21
+
22
+ # Public: Removes plugin files
23
+ #
24
+ # Examples
25
+ #
26
+ # 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(TEMPLATES_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(TEMPLATES_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
+
85
+ # Private: Returns the file path to the cache direcetory
86
+ #
87
+ # Examples
88
+ #
89
+ # aside_path
90
+ # # => /path/to/.page_views
91
+ #
92
+ # Returns a String
93
+ def self.cache_path
94
+ File.join(Dir.pwd, '.page_views')
95
+ end
96
+
97
+ # Private: Returns the file path to the config template
98
+ #
99
+ # Examples
100
+ #
101
+ # aside_path
102
+ # # => /path/to/config
103
+ #
104
+ # Returns a String
105
+ def self.config_path
106
+ File.join(TEMPLATES_DIR, 'config')
107
+ end
108
+
109
+ # Private: Returns the file path to the config destination
110
+ #
111
+ # Examples
112
+ #
113
+ # aside_path
114
+ # # => /path/to/destination/config
115
+ #
116
+ # Returns a String
117
+ def self.config_destination
118
+ File.join(Dir.pwd, '.page_views', 'config')
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,3 @@
1
+ module PopularPosts
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'octopress-gauges-popular-posts/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "octopress-gauges-popular-posts"
8
+ gem.version = PopularPosts::VERSION
9
+ gem.authors = ["Bastian Bartmann"]
10
+ gem.email = ["xarfai27@gmail.com"]
11
+ gem.description = "Octopress Gauges Popular Posts adds a popular posts asides section to your Octopress blog. It makes use of GitHub's Gaug.es to determine the popularity of the posts."
12
+ gem.summary = 'Adds a popular posts asides section to your Octopress blog.'
13
+ gem.homepage = "https://github.com/coding-chimp/octopress-gauges-popular-posts"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
data/templates/config ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ :token:
3
+ :signup_date:
@@ -0,0 +1,278 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'open-uri'
4
+
5
+ # Public: Popular posts plugin for Octopress. This plugin
6
+ # opens up the Jekyll Post and Site classes to allow
7
+ # Jekyll to render the popular posts aside section
8
+ module PopularPost
9
+ module Post
10
+
11
+ def self.included(base)
12
+ if base.class.instance_methods.include?('page_views') ||
13
+ base.class.protected_instance_methods.include?(%w(cache_page_views read_page_views_cache))
14
+ raise 'Octopress Gauges 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_VIEWS_CACHE = '.page_views'
27
+
28
+ # Public: Returns the page views of the post. It also caches the page views.
29
+ # If a cached page rank is found, it returns the cached version.
30
+ #
31
+ # Examples
32
+ #
33
+ # page_views
34
+ # # => 34
35
+ #
36
+ # Returns the Integer page views of the post
37
+ def page_views
38
+ post_name = self.url.split('/').last
39
+ cache_dir_path = File.join(Dir.pwd, PAGE_VIEWS_CACHE)
40
+ post_path = File.join(Dir.pwd, PAGE_VIEWS_CACHE, post_name)
41
+
42
+ if File.exists?(post_path)
43
+ read_page_views_cache(post_path)[:views]
44
+ else
45
+ post_views = 0
46
+ page_views_content = { path: self.url, views: post_views }
47
+ cache_page_views(page_views_content, post_path)
48
+ post_views
49
+ end
50
+ end
51
+ end
52
+
53
+ module ProtectedInstanceMethods
54
+
55
+ # Private: Caches the page views of the post.
56
+ #
57
+ # page_views_content - The Hash which is contains view and
58
+ # the path of the post.
59
+ # cache_path - The String which is the file path
60
+ # to the cache
61
+ #
62
+ # Examples
63
+ #
64
+ # cache_page_views({path: '/blog/bar', views: 2}, '/path/to/cache')
65
+ # # => nil
66
+ #
67
+ # Returns nothing.
68
+ def cache_page_views(page_views_content, cache_path)
69
+ File.open(cache_path, 'w') do |file|
70
+ file.puts YAML.dump(page_views_content)
71
+ end
72
+ end
73
+
74
+ # Private: Reads the cached page views
75
+ #
76
+ # cache_path - The String which is the file path to the cache
77
+ #
78
+ # Examples
79
+ #
80
+ # read_page_views('/path/to/cache')
81
+ # # => {path: 'http://foo', views: 2}
82
+ #
83
+ # Returns a Hash
84
+ def read_page_views_cache(cache_path)
85
+ YAML.load_file(cache_path)
86
+ end
87
+ end
88
+ end # Post
89
+
90
+ module Site
91
+
92
+ CACHE_DIR_PATH = File.join(Dir.pwd, '.page_views')
93
+
94
+ def self.included(base)
95
+ base.class_eval do
96
+ attr_accessor :popular_posts
97
+ alias_method :old_read, :read
98
+ alias_method :old_site_payload, :site_payload
99
+
100
+ # Public: Making use of the read method to define popular
101
+ # posts. Popular posts are sorted by page views
102
+ #
103
+ # Examples
104
+ #
105
+ # read
106
+ # # => nil
107
+ #
108
+ # Returns nothing
109
+ def read
110
+ old_read
111
+ update_views
112
+ self.popular_posts = self.posts.sort do |post_x, post_y|
113
+ if post_y.page_views > post_x.page_views then 1
114
+ elsif post_y.page_views == post_x.page_views then 0
115
+ else -1
116
+ end
117
+ end
118
+ end
119
+
120
+ # Public: We need to add popular_posts to site_payload, so that
121
+ # it gets passed to Liquid to be rendered.
122
+ #
123
+ # Examples
124
+ #
125
+ # site_payload
126
+ # # => nil
127
+ #
128
+ # Returns nothing
129
+ def site_payload
130
+ old_site_hash = old_site_payload
131
+ old_site_hash["site"].merge!({"popular_posts" => self.popular_posts})
132
+ old_site_hash
133
+ end
134
+
135
+ protected
136
+
137
+ # Private: Checks wether there is a last_run or signup_date and
138
+ # fetches views since then.
139
+ #
140
+ # Examples
141
+ #
142
+ # update_views
143
+ # # => nil
144
+ #
145
+ # Returns nothing
146
+ def update_views
147
+ gauges_config = YAML.load_file("#{CACHE_DIR_PATH}/config")
148
+ views = load_views
149
+ last_run = gauges_config[:last_run] || gauges_config[:signup_date]
150
+ yesterday = Date.today - 1
151
+
152
+ if last_run.nil?
153
+ views = fetch_views(views, yesterday, gauges_config[:token])
154
+ elsif last_run && last_run != Date.today
155
+ for date in last_run..yesterday do
156
+ views = fetch_views(views, date, gauges_config[:token])
157
+ end
158
+ end
159
+
160
+ cache_views(views)
161
+ update_last_run(gauges_config)
162
+ end
163
+
164
+ # Private: Sets the last run date to today and caches it.
165
+ #
166
+ # gauges_config - The path to the gauges config file
167
+ #
168
+ # Examples
169
+ #
170
+ # update_last_run('/path/to/page/gauges/config')
171
+ # # => nil
172
+ #
173
+ # Returns nothing
174
+ def update_last_run(gauges_config)
175
+ gauges_config[:last_run] = Date.today
176
+ File.open("#{CACHE_DIR_PATH}/config", 'w') do |file|
177
+ file.puts YAML.dump(gauges_config)
178
+ end
179
+ end
180
+
181
+ # Private: Caches the views.
182
+ #
183
+ # views - A hash of hashes that contain the page views
184
+ # and path of the post.
185
+ #
186
+ # Examples
187
+ #
188
+ # cache_views({{path: '/blog/bar', views: 2}, ...})
189
+ # # => nil
190
+ #
191
+ # Returns nothing
192
+ def cache_views(views)
193
+ views.each do |k, v|
194
+ content = { path: k, views: v }
195
+ file_path = "#{CACHE_DIR_PATH}#{k.to_s}"
196
+
197
+ File.open(file_path, 'w') do |file|
198
+ file.puts YAML.dump(content)
199
+ end
200
+ end
201
+ end
202
+
203
+ # Private: Loads the view counts from the cache.
204
+ #
205
+ # Examples
206
+ #
207
+ # load_views
208
+ # # => {{path: '/blog/bar', views: 2}, ...}
209
+ #
210
+ # Returns a hash of of hashes that contain the path and
211
+ # views of a post
212
+ def load_views
213
+ posts = {}
214
+ Dir.foreach(CACHE_DIR_PATH) do |file|
215
+ next if file == '.' || file == '..' || file == 'config'
216
+ content = YAML.load_file("#{CACHE_DIR_PATH}/#{file}")
217
+ posts[content[:path]] = content[:views]
218
+ end
219
+ posts
220
+ end
221
+
222
+ # Private: Takes the the current views loaded from cash,
223
+ # calls the Gaug.es API for the views of a specified
224
+ # day, updates the loaded views and returns them.
225
+ #
226
+ # views - An hash of hashes containing the path and views
227
+ # of posts loaded from the cache
228
+ # date - The date for which the API call will be made
229
+ # token - The Gaug.es API token needed for the API call
230
+ #
231
+ # Examples
232
+ #
233
+ # fetch_views({{path: '/blog/bar', views: 2}, ...},
234
+ # 2013-06-03, 188fa4710f08973145c1038af83ba78b)
235
+ # # => {{path: '/blog/bar', views: 11}, ...}
236
+ #
237
+ # Returns a hash of hashed containing the path and updated page
238
+ # updated page views
239
+ def fetch_views(views, date, token)
240
+ puts "Popular posts: fetches views for #{date}"
241
+ gauge_id = config['gauges_tracking_id']
242
+ host = config['url'].gsub "http://", ""
243
+
244
+ content = JSON.parse(open("https://secure.gaug.es/gauges/#{gauge_id}/content?date=#{date}",
245
+ 'X-Gauges-Token' => token).read)['content']
246
+
247
+ content.each do |page|
248
+ unless page['path'] == "/" || page['path'].include?("/categories/") ||
249
+ page['path'] == "/archives/" || page['path'].include?("/page/") ||
250
+ page['path'] == "/about/" || page['host'] != host
251
+ path = page['path'].gsub(/(\/|\/#.*)$/, "")
252
+ current_views = views[path]
253
+ if current_views.nil?
254
+ updated_views = page['views'].to_i
255
+ else
256
+ updated_views = current_views.to_i + page['views'].to_i
257
+ end
258
+ views[path] = updated_views
259
+ end
260
+ end
261
+ views
262
+ end
263
+
264
+ end
265
+ end # included
266
+ end # Site
267
+
268
+ end # PopularPost
269
+
270
+ module Jekyll
271
+ class Post
272
+ include PopularPost::Post
273
+ end
274
+
275
+ class Site
276
+ include PopularPost::Site
277
+ end
278
+ end
@@ -0,0 +1,10 @@
1
+ <section>
2
+ <h1>Popular Posts</h1>
3
+ <ul id="recent_posts">
4
+ {% for post in site.popular_posts limit: site.popular_posts_count %}
5
+ <li class="post">
6
+ <a href="{{ root_url }}{{ post.url }}">{{ post.title }}</a>
7
+ </li>
8
+ {% endfor %}
9
+ </ul>
10
+ </section>
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: octopress-gauges-popular-posts
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bastian Bartmann
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-03 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Octopress Gauges Popular Posts adds a popular posts asides section to
15
+ your Octopress blog. It makes use of GitHub's Gaug.es to determine the popularity
16
+ of the posts.
17
+ email:
18
+ - xarfai27@gmail.com
19
+ executables:
20
+ - octopress-gauges-popular-posts
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - .gitignore
25
+ - Gemfile
26
+ - LICENSE.txt
27
+ - README.md
28
+ - Rakefile
29
+ - bin/octopress-gauges-popular-posts
30
+ - lib/octopress-gauges-popular-posts.rb
31
+ - lib/octopress-gauges-popular-posts/utilities.rb
32
+ - lib/octopress-gauges-popular-posts/version.rb
33
+ - octopress-gauges-popular-posts.gemspec
34
+ - templates/config
35
+ - templates/popular_post.rb
36
+ - templates/popular_posts.html
37
+ homepage: https://github.com/coding-chimp/octopress-gauges-popular-posts
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.24
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: Adds a popular posts asides section to your Octopress blog.
61
+ test_files: []
62
+ has_rdoc: