jekyll-recker 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/lib/blog/slack.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'slack-notifier'
4
+
5
+ module Blog
6
+ # Slack
7
+ module Slacky
8
+ def self.post(entry, url, info)
9
+ notifier = ::Slack::Notifier.new(
10
+ url.strip,
11
+ channel: info['channel'],
12
+ username: info['username'],
13
+ icon_emoji: ':reckerbot:'
14
+ )
15
+ message = "#{entry.title} - #{entry.excerpt}\n#{entry.permalink}"
16
+ Slack::Notifier::Util::LinkFormatter.format(message)
17
+ notifier.post text: message
18
+ end
19
+ end
20
+ end
data/lib/blog/words.rb ADDED
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blog
4
+ # Words
5
+ module Words
6
+ def self.array_to_and_list(array)
7
+ case array.length
8
+ when 0
9
+ ''
10
+ when 1
11
+ array.first
12
+ when 2
13
+ "#{array.first} and #{array.last}"
14
+ else
15
+ array[0...-1].join(', ') + ", and #{array.last}"
16
+ end
17
+ end
18
+
19
+ def self.and_list_to_array(str)
20
+ str = str.gsub(' and ', ', ')
21
+ str.split(',').map(&:strip).reject(&:empty?)
22
+ end
23
+
24
+ def self.prettify_number(number)
25
+ number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
26
+ end
27
+
28
+ def self.prettify_path(path, home = nil)
29
+ home ||= File.expand_path('~/')
30
+ path.sub(home, '~')
31
+ end
32
+
33
+ def self.to_word_list(str)
34
+ str.split(' ')
35
+ end
36
+
37
+ def self.to_weighted_list(arr)
38
+ arr.uniq.map do |word|
39
+ [word, arr.count(word)]
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ # Array extensions
46
+ class Array
47
+ def to_and_list
48
+ Blog::Words.array_to_and_list(self)
49
+ end
50
+
51
+ def to_weighted_list
52
+ Blog::Words.to_weighted_list(self)
53
+ end
54
+ end
55
+
56
+ # Integer extensions
57
+ class Integer
58
+ def pretty
59
+ Blog::Words.prettify_number(self)
60
+ end
61
+ end
62
+
63
+ # String extensions
64
+ class String
65
+ def words
66
+ Blog::Words.to_word_list(self)
67
+ end
68
+
69
+ def word_count
70
+ Blog::Words.to_word_list(self).count
71
+ end
72
+
73
+ def pretty_path(home = nil)
74
+ Blog::Words.prettify_path(self, home)
75
+ end
76
+
77
+ def to_and_array
78
+ Blog::Words.and_list_to_array(self)
79
+ end
80
+ end
data/lib/blog.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Blog
4
+ module Blog
5
+ require_relative 'blog/cli'
6
+ require_relative 'blog/config'
7
+ require_relative 'blog/entry'
8
+ require_relative 'blog/git'
9
+ require_relative 'blog/jekyll'
10
+ require_relative 'blog/journal'
11
+ require_relative 'blog/log'
12
+ require_relative 'blog/slack'
13
+ require_relative 'blog/words'
14
+ end
@@ -0,0 +1,26 @@
1
+ module Jekyll
2
+ module Recker
3
+ module Commands
4
+ # Tweet
5
+ class Tweet < Jekyll::Command
6
+ class << self
7
+ def init_with_program(prog)
8
+ prog.command(:tweet) do |c|
9
+ c.syntax "tweet"
10
+ c.description 'tweet latest post'
11
+ c.action do |args, options|
12
+ client = Jekyll::Recker::Twitter.new
13
+ Jekyll.logger.info 'discovering credentials'
14
+ client.discover_credentials!
15
+ Jekyll.logger.info "tweeting #{client.latest.data['title']}"
16
+ client.post_latest!
17
+ rescue => e
18
+ Jekyll.logger.abort_with e.message
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ module Jekyll
2
+ module Recker
3
+ # Configuration
4
+ module Configuration
5
+ def self.jekyll
6
+ @jekyll ||= Jekyll.configuration
7
+ end
8
+
9
+ def self.recker
10
+ jekyll.fetch('recker', {})
11
+ end
12
+
13
+ def self.twitter
14
+ recker.fetch('twitter', {})
15
+ end
16
+
17
+ def self.site
18
+ @site = Jekyll::Site.new(jekyll)
19
+ @site.reset
20
+ @site.read
21
+ @site
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Recker
5
+ module Generators
6
+ # StatsGenerator
7
+ class StatsGenerator < Jekyll::Generator
8
+ def generate(site)
9
+ site.data['stats'] = Stats.crunch(site)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+ require 'date'
3
+
4
+ module Jekyll
5
+ module Recker
6
+ # Stats
7
+ module Stats
8
+ def self.crunch(site)
9
+ stats = {}
10
+ BaseCruncher.descendants.each do |cruncher_class|
11
+ cruncher = cruncher_class.new(site)
12
+ stats[cruncher.stats_key] = cruncher.crunch
13
+ end
14
+ stats
15
+ end
16
+
17
+ # Base Cruncher
18
+ class BaseCruncher
19
+ include Jekyll::Filters
20
+
21
+ def self.descendants
22
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
23
+ end
24
+
25
+ def initialize(site)
26
+ @site = site
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :journal
32
+
33
+ def average(numlist)
34
+ calc = numlist.inject { |sum, el| sum + el }.to_f / numlist.size
35
+ calc.round
36
+ end
37
+
38
+ def total(numlist)
39
+ numlist.inject(0) { |sum, x| sum + x }
40
+ end
41
+
42
+ def entries
43
+ @site.posts.docs.select(&:published?)
44
+ end
45
+ end
46
+
47
+ # PostCountCruncher
48
+ class PostCountCruncher < BaseCruncher
49
+ def stats_key
50
+ 'posts'
51
+ end
52
+
53
+ def crunch
54
+ entries.count.pretty
55
+ end
56
+ end
57
+
58
+ # WordCountCruncher
59
+ class WordCountCruncher < BaseCruncher
60
+ def stats_key
61
+ 'words'
62
+ end
63
+
64
+ def crunch
65
+ total_counts = entries.collect(&:content).map { |c| number_of_words(c) }
66
+ {
67
+ 'average' => average(total_counts).pretty,
68
+ 'total' => total(total_counts).pretty
69
+ }
70
+ end
71
+ end
72
+
73
+ # Streak Cruncher
74
+ class StreakCruncher < BaseCruncher
75
+ def stats_key
76
+ 'days'
77
+ end
78
+
79
+ def crunch
80
+ streaks.take(1).map do |count, dates|
81
+ {
82
+ 'days' => count.pretty,
83
+ 'start' => dates[0],
84
+ 'end' => dates[1]
85
+ }
86
+ end.first
87
+ end
88
+
89
+ private
90
+
91
+ def streaks
92
+ _streaks = []
93
+ entry_dates.slice_when do |prev, curr|
94
+ curr != prev - 1
95
+ end.each do |dates|
96
+ first, last = dates.min, dates.max
97
+ _streaks << [(last - first).to_i, [first, last]]
98
+ end
99
+ _streaks
100
+ end
101
+
102
+ def entry_dates
103
+ entries.collect(&:date).map { |t| Date.new(t.year, t.month, t.day) }.sort.reverse
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Recker
5
+ module Tags
6
+ # Version
7
+ class Version < Liquid::Tag
8
+ def render(_context)
9
+ VERSION
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ Liquid::Template.register_tag('recker_version', Jekyll::Recker::Tags::Version)
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ require 'twitter'
3
+
4
+ module Jekyll
5
+ module Recker
6
+ # Twitter Client
7
+ class Twitter
8
+ class CannotFindCreds < StandardError
9
+ def initialize(msg = 'could not find twitter credentials')
10
+ super
11
+ end
12
+ end
13
+
14
+ def discover_credentials!
15
+ @creds = extract_from_env || extract_from_config
16
+ raise CannotFindCreds if @creds.nil?
17
+ set_credentials!
18
+ end
19
+
20
+ def post_latest!
21
+ @client.update(tweet_body)
22
+ end
23
+
24
+ def latest
25
+ @latest ||= Configuration.site.posts.docs.last
26
+ end
27
+
28
+ private
29
+
30
+ def tweet_body
31
+ url = File.join Configuration.jekyll['url'], latest.url
32
+ <<~TWEET
33
+ #{latest.data['excerpt']}
34
+ #{latest.data['title']}
35
+ #{url}
36
+ TWEET
37
+ end
38
+
39
+ def set_credentials!
40
+ @client ||= ::Twitter::REST::Client.new do |settings|
41
+ settings.consumer_key = @creds['consumer_api_key']
42
+ settings.consumer_secret = @creds['consumer_api_secret']
43
+ settings.access_token = @creds['access_token']
44
+ settings.access_token_secret = @creds['access_token_secret']
45
+ end
46
+ end
47
+
48
+ def extract_from_env
49
+ values = cred_fieldnames.map { |k| ENV[k.upcase] }
50
+ Hash[cred_fieldnames.zip(values)] unless values.any? { |v| v.nil? || v.empty? }
51
+ end
52
+
53
+ def extract_from_config
54
+ values = cred_fieldnames.map { |k| shell(Configuration.twitter["#{k}_cmd"]) }
55
+ Hash[cred_fieldnames.zip(values)] unless values.any? { |v| v.nil? || v.empty? }
56
+ end
57
+
58
+ def shell(cmd)
59
+ Jekyll.logger.info "running command: #{cmd}"
60
+ `#{cmd}`.strip
61
+ end
62
+
63
+ def cred_fieldnames
64
+ [
65
+ 'access_token_secret',
66
+ 'access_token',
67
+ 'consumer_api_key',
68
+ 'consumer_api_secret'
69
+ ]
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Recker
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Recker
5
+ # Words
6
+ module Words
7
+ def self.array_to_and_list(array)
8
+ case array.length
9
+ when 0
10
+ ''
11
+ when 1
12
+ array.first
13
+ when 2
14
+ "#{array.first} and #{array.last}"
15
+ else
16
+ array[0...-1].join(', ') + ", and #{array.last}"
17
+ end
18
+ end
19
+
20
+ def self.and_list_to_array(str)
21
+ str = str.gsub(' and ', ', ')
22
+ str.split(',').map(&:strip).reject(&:empty?)
23
+ end
24
+
25
+ def self.prettify_number(number)
26
+ number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
27
+ end
28
+
29
+ def self.prettify_path(path, home = nil)
30
+ home ||= File.expand_path('~/')
31
+ path.sub(home, '~')
32
+ end
33
+
34
+ def self.to_word_list(str)
35
+ str.split(' ')
36
+ end
37
+
38
+ def self.to_weighted_list(arr)
39
+ arr.uniq.map do |word|
40
+ [word, arr.count(word)]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ # Array extensions
48
+ class Array
49
+ def to_and_list
50
+ Jekyll::Recker::Words.array_to_and_list(self)
51
+ end
52
+
53
+ def to_weighted_list
54
+ Jekyll::Recker::Words.to_weighted_list(self)
55
+ end
56
+ end
57
+
58
+ # Integer extensions
59
+ class Integer
60
+ def pretty
61
+ Jekyll::Recker::Words.prettify_number(self)
62
+ end
63
+ end
64
+
65
+ # String extensions
66
+ class String
67
+ def words
68
+ Jekyll::Recker::Words.to_word_list(self)
69
+ end
70
+
71
+ def word_count
72
+ Jekyll::Recker::Words.to_word_list(self).count
73
+ end
74
+
75
+ def pretty_path(home = nil)
76
+ Jekyll::Recker::Words.prettify_path(self, home)
77
+ end
78
+
79
+ def to_and_array
80
+ Jekyll::Recker::Words.and_list_to_array(self)
81
+ end
82
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ # Recker
5
+ module Recker
6
+ require 'jekyll-recker/commands.rb'
7
+ require 'jekyll-recker/configuration.rb'
8
+ require 'jekyll-recker/generators.rb'
9
+ require 'jekyll-recker/stats.rb'
10
+ require 'jekyll-recker/tags.rb'
11
+ require 'jekyll-recker/twitter.rb'
12
+ require 'jekyll-recker/version.rb'
13
+ require 'jekyll-recker/words.rb'
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-recker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Recker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: twitter
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - alex@reckerfamily.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - LICENSE
77
+ - README.org
78
+ - _includes/archive.html
79
+ - _includes/nav.html
80
+ - _includes/pager.html
81
+ - _includes/stats.html
82
+ - _layouts/default.html
83
+ - _layouts/home.html
84
+ - _layouts/page.html
85
+ - _layouts/post.html
86
+ - _sass/jekyll-recker.sass
87
+ - assets/images/example-stats.png
88
+ - assets/images/example-tweet.png
89
+ - assets/images/me.jpg
90
+ - assets/images/words.png
91
+ - assets/jekyll-recker.scss
92
+ - lib/blog.rb
93
+ - lib/blog/cli.rb
94
+ - lib/blog/config.rb
95
+ - lib/blog/entry.rb
96
+ - lib/blog/git.rb
97
+ - lib/blog/jekyll.rb
98
+ - lib/blog/journal.rb
99
+ - lib/blog/log.rb
100
+ - lib/blog/slack.rb
101
+ - lib/blog/words.rb
102
+ - lib/jekyll-recker.rb
103
+ - lib/jekyll-recker/commands.rb
104
+ - lib/jekyll-recker/configuration.rb
105
+ - lib/jekyll-recker/generators.rb
106
+ - lib/jekyll-recker/stats.rb
107
+ - lib/jekyll-recker/tags.rb
108
+ - lib/jekyll-recker/twitter.rb
109
+ - lib/jekyll-recker/version.rb
110
+ - lib/jekyll-recker/words.rb
111
+ homepage: https://www.alexrecker.com/jekyll-recker.html
112
+ licenses:
113
+ - GPLv3
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubygems_version: 3.0.3
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: This is the jekyll theme for my personal website.
134
+ test_files: []