jekyll-recker 1.2.2 → 1.7.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.
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module Jekyll
6
+ module Recker
7
+ module Mixins
8
+ # Descendants
9
+ module Descendants
10
+ def self.included(base)
11
+ base.extend(self)
12
+ end
13
+
14
+ def descendants
15
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
16
+ end
17
+ end
18
+
19
+ # Introspection
20
+ module Introspection
21
+ def self.included(base)
22
+ base.extend(self)
23
+ end
24
+
25
+ def class_name
26
+ self.class.name.split('::').last
27
+ end
28
+ end
29
+
30
+ # Logging
31
+ module Logging
32
+ def self.included(base)
33
+ base.extend(self)
34
+ end
35
+
36
+ def logger
37
+ @logger ||= Logger.new(
38
+ STDOUT,
39
+ formatter: proc { |_severity, _datetime, _progname, msg| "jekyll-recker: #{msg}\n" }
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'slack-notifier'
4
+ require 'twitter'
5
+
6
+ module Jekyll
7
+ # Recker
8
+ module Recker
9
+ module Social
10
+ # Backend
11
+ #
12
+ # Backend base class for social sharing backends.
13
+ # @abstract
14
+ class Share
15
+ include Mixins::Introspection
16
+ include Mixins::Logging
17
+
18
+ def self.share(dry: false)
19
+ backend = new(dry: dry)
20
+ logger.info "#{backend.name} - building configuration"
21
+ backend.configure!
22
+
23
+ logger.info "#{backend.name} - sharing \"#{backend.latest_title}\""
24
+ backend.post!
25
+ end
26
+
27
+ def initialize(dry: false)
28
+ @dry = dry
29
+ end
30
+
31
+ def dry?
32
+ @dry
33
+ end
34
+
35
+ def config
36
+ @config ||= Jekyll::Recker::Configuration.recker.fetch(config_key)
37
+ end
38
+
39
+ def config_key
40
+ class_name.downcase
41
+ end
42
+ alias name config_key
43
+
44
+ def post_body
45
+ url = File.join Configuration.jekyll['url'], latest.url
46
+ <<~BODY
47
+ #{latest.data['date'].strftime('%A, %B %-d %Y')}
48
+ #{latest.data['title']}
49
+ #{url}
50
+ BODY
51
+ end
52
+
53
+ def latest
54
+ @latest ||= Configuration.latest_post
55
+ end
56
+
57
+ def latest_title
58
+ latest.data['title']
59
+ end
60
+
61
+ def configure!
62
+ raise NotImplementedError
63
+ end
64
+
65
+ def post!
66
+ raise NotImplementedError
67
+ end
68
+ end
69
+
70
+ # Slack
71
+ #
72
+ # Slack social sharing backend
73
+ class Slack < Share
74
+ def configure!
75
+ @creds = {}
76
+ workspaces.each do |key, data|
77
+ webhook = ENV["SLACK_#{key.upcase}_WEBHOOK"] || extract_from_config(data)
78
+ if webhook.nil?
79
+ raise ReckerError, "cannot find slack webhook for #{key} workspace!"
80
+ end
81
+
82
+ @creds[key] = webhook
83
+ end
84
+ end
85
+
86
+ def post!
87
+ message_body = ::Slack::Notifier::Util::LinkFormatter.format(post_body)
88
+ workspaces.each do |key, config|
89
+ logger.info "posting to #{key} workspace"
90
+ if @dry
91
+ logger.info("BEGIN MESSAGE\n#{message_body.strip}\nEND MESSAGE")
92
+ else
93
+ ::Slack::Notifier.new(
94
+ @creds[key].strip,
95
+ channel: config.fetch('channel'),
96
+ username: config.fetch('username'),
97
+ icon_emoji: config.fetch('emoji')
98
+ ).post(text: message_body)
99
+ end
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def extract_from_config(data)
106
+ cmd = data['webhook_cmd']
107
+ return nil if cmd.nil?
108
+
109
+ Jekyll::Recker.shell(cmd)
110
+ end
111
+
112
+ def workspaces
113
+ config.each
114
+ end
115
+ end
116
+
117
+ # Twitter
118
+ #
119
+ # Twitter social sharing backend
120
+ class Twitter < Share
121
+ def configure!
122
+ creds = extract_from_env || extract_from_config
123
+ raise ReckerError, 'cannot find twitter credentials!' if creds.nil?
124
+
125
+ @client = ::Twitter::REST::Client.new do |settings|
126
+ settings.consumer_key = creds['consumer_api_key']
127
+ settings.consumer_secret = creds['consumer_api_secret']
128
+ settings.access_token = creds['access_token']
129
+ settings.access_token_secret = creds['access_token_secret']
130
+ end
131
+ end
132
+
133
+ def post!
134
+ if dry?
135
+ logger.info('tweeting in dry mode, printing message')
136
+ logger.info("BEGIN TWEET\n#{post_body}END TWEET")
137
+ else
138
+ @client.update(post_body)
139
+ end
140
+ end
141
+
142
+ private
143
+
144
+ def extract_from_env
145
+ values = cred_fieldnames.map { |k| ENV["TWITTER_#{k.upcase}"] }
146
+
147
+ return nil if values.any? { |v| v.nil? || v.empty? }
148
+
149
+ Hash[cred_fieldnames.zip(values)]
150
+ end
151
+
152
+ def extract_from_config
153
+ values = cred_fieldnames.map do |k|
154
+ Recker.shell(Configuration.twitter["#{k}_cmd"]).strip
155
+ end
156
+
157
+ return nil if values.any? { |v| v.nil? || v.empty? }
158
+
159
+ Hash[cred_fieldnames.zip(values)]
160
+ end
161
+
162
+ def cred_fieldnames
163
+ [
164
+ 'access_token_secret',
165
+ 'access_token',
166
+ 'consumer_api_key',
167
+ 'consumer_api_secret'
168
+ ]
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -3,7 +3,7 @@
3
3
  module Jekyll
4
4
  module Recker
5
5
  module Tags
6
- # Version
6
+ # Returns the VERSION of the running jekyll-recker gem.
7
7
  class Version < Liquid::Tag
8
8
  def render(_context)
9
9
  VERSION
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Recker
5
- VERSION = '1.2.2'
5
+ VERSION = '1.7.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,37 +1,37 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-recker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Recker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-04 00:00:00.000000000 Z
11
+ date: 2020-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: jekyll
14
+ name: bump
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.8'
20
- type: :runtime
19
+ version: '0'
20
+ type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.8'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: slack-notifier
28
+ name: pry
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
- type: :runtime
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
@@ -39,13 +39,13 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: twitter
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
- type: :runtime
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: bundler
56
+ name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rake
70
+ name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -80,6 +80,62 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: jekyll
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.8'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.8'
111
+ - !ruby/object:Gem::Dependency
112
+ name: slack-notifier
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: twitter
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
83
139
  description:
84
140
  email:
85
141
  - alex@reckerfamily.com
@@ -88,33 +144,29 @@ extensions: []
88
144
  extra_rdoc_files: []
89
145
  files:
90
146
  - LICENSE
91
- - README.org
147
+ - README.md
148
+ - _includes/figure.html
92
149
  - _includes/footer.html
150
+ - _includes/head.html
93
151
  - _includes/header.html
94
152
  - _includes/nav.html
95
- - _layouts/default.html
153
+ - _includes/pager.html
96
154
  - _layouts/home.html
97
155
  - _layouts/page.html
98
156
  - _layouts/post.html
99
- - assets/jekyll-recker.scss
100
157
  - lib/jekyll-recker.rb
101
- - lib/jekyll-recker/commands.rb
102
- - lib/jekyll-recker/commands/share.rb
103
- - lib/jekyll-recker/commands/slack.rb
104
- - lib/jekyll-recker/commands/tweet.rb
105
- - lib/jekyll-recker/configuration.rb
106
- - lib/jekyll-recker/error.rb
107
- - lib/jekyll-recker/generators.rb
108
- - lib/jekyll-recker/logger.rb
109
- - lib/jekyll-recker/mixins.rb
110
- - lib/jekyll-recker/shell.rb
111
- - lib/jekyll-recker/slack.rb
112
- - lib/jekyll-recker/stats.rb
113
- - lib/jekyll-recker/tags.rb
114
- - lib/jekyll-recker/twitter.rb
115
- - lib/jekyll-recker/version.rb
116
- - lib/jekyll-recker/words.rb
117
- homepage: https://www.alexrecker.com/jekyll-recker.html
158
+ - lib/jekyll_recker/commands.rb
159
+ - lib/jekyll_recker/configuration.rb
160
+ - lib/jekyll_recker/error.rb
161
+ - lib/jekyll_recker/filters.rb
162
+ - lib/jekyll_recker/generators.rb
163
+ - lib/jekyll_recker/mixins.rb
164
+ - lib/jekyll_recker/shell.rb
165
+ - lib/jekyll_recker/social.rb
166
+ - lib/jekyll_recker/tags.rb
167
+ - lib/jekyll_recker/version.rb
168
+ - lib/jekyll_recker/words.rb
169
+ homepage: https://www.github.com/arecker/jekyll-recker/
118
170
  licenses:
119
171
  - GPLv3
120
172
  metadata: {}
@@ -136,5 +188,5 @@ requirements: []
136
188
  rubygems_version: 3.0.3
137
189
  signing_key:
138
190
  specification_version: 4
139
- summary: This is the jekyll theme for my personal website.
191
+ summary: The Greatest Jekyll Plugin in the World
140
192
  test_files: []
data/README.org DELETED
@@ -1,205 +0,0 @@
1
- #+TITLE: jekyll-recker
2
- #+SLUG: jekyll-recker.html
3
- #+PERMALINK: jekyll-recker.html
4
- #+STARTUP: showall
5
- #+DESCRIPTION: my website's custom jekyll plugin
6
-
7
- This is the jekyll plugin for my personal website. Source code
8
- available on [[https://github.com/arecker/blog][github]].
9
-
10
- ** Installation
11
-
12
- Add =jekyll-recker= to the =jekyll_plugins= group of your =Gemfile=.
13
-
14
- #+BEGIN_SRC ruby
15
- group :jekyll_plugins do
16
- gem 'jekyll-recker'
17
- end
18
- #+END_SRC
19
-
20
- Add =jekyll-recker= to the list of plugins in jekyll's =_config.yml=.
21
-
22
- #+BEGIN_SRC yaml
23
- # _config.yaml
24
- plugins:
25
- - jekyll-recker
26
- #+END_SRC
27
-
28
- Set the theme.
29
-
30
- #+BEGIN_SRC yaml
31
- theme: jekyll-recker
32
- #+END_SRC
33
-
34
- Install and enjoy.
35
-
36
- #+BEGIN_SRC sh
37
- bundle install
38
- bundle exec jekyll serve
39
- #+END_SRC
40
-
41
- ** Usage
42
-
43
- *** Commands
44
-
45
- **** =slack=
46
-
47
- The =slack= command posts a slack message advertising the latest
48
- published jekyll blog post using a private incoming webhook.
49
-
50
- Configure _config.yml
51
-
52
- #+BEGIN_SRC yaml
53
- # _config.yml
54
- recker:
55
- slack:
56
- MyTeam:
57
- channel: '#blogs' # required!
58
- username: 'blogbot' # required!
59
- emoji: ':robot:' # required!
60
- #+END_SRC
61
-
62
- Multiple teams are supported too!
63
-
64
- #+BEGIN_SRC yaml
65
- # _config.yml
66
- recker:
67
- slack:
68
- MyTeamA:
69
- channel: '#blogs' # required!
70
- username: 'blogbot' # required!
71
- emoji: ':robot:' # required!
72
- MyTeamB:
73
- channel: '#blogs' # required!
74
- username: 'blogbot' # required!
75
- emoji: ':robot:' # required!
76
- MyTeamC:
77
- channel: '#blogs' # required!
78
- username: 'blogbot' # required!
79
- emoji: ':robot:' # required!
80
- #+END_SRC
81
-
82
-
83
- Supply the private webhook through an environment variable.
84
-
85
- #+BEGIN_SRC sh
86
- export SLACK_MYTEAM_WEBHOOK="https://..." # SLACK_ + <MyTeam.upcase> + _WEBHOOK
87
- #+END_SRC
88
-
89
- Alternatively, add the command with which to retrieve the webhook in
90
- _config.yml
91
-
92
- #+BEGIN_SRC yaml
93
- # _config.yml
94
- recker:
95
- slack:
96
- MyTeam:
97
- webhook_cmd: cat secrets/my-teams-secret-webhook.txt
98
- #+END_SRC
99
-
100
- Run =bundle exec jekyll slack= to let it rip!
101
-
102
- [[assets/images/example-slack.png]]
103
-
104
- Using the =--dry= flag, you can preview the message post without
105
- actually posting anything.
106
-
107
- #+BEGIN_EXAMPLE
108
- arecker@25732-arecker:~/src/blog$ be jekyll slack --dry
109
- Configuration file: /Users/arecker/src/blog/_config.yml
110
- jekyll-recker: reckerfamily: discovering webhook
111
- Configuration file: /Users/arecker/src/blog/_config.yml
112
- jekyll-recker: reckerfamily: posting drag racing, windshield wipers, and alex's painting tips
113
- jekyll-recker: postign in dry mode, printing message
114
- jekyll-recker: BEGIN MESSAGE
115
- Sunday, March 15 2020
116
- drag racing, windshield wipers, and alex's painting tips
117
- https://www.alexrecker.com/2020-03-15.html
118
- END MESSAGE
119
- #+END_EXAMPLE
120
-
121
- **** =tweet=
122
-
123
- The =tweet= command tweets a link to the latest published jekyll blog
124
- post.
125
-
126
- Ensure the following environment variables are set,.
127
-
128
- #+BEGIN_SRC sh
129
- export ACCESS_TOKEN_SECRET="..."
130
- export ACCESS_TOKEN="..."
131
- export CONSUMER_API_KEY="..."
132
- export CONSUMER_API_SECRET="..."
133
- #+END_SRC
134
-
135
- Alternatively, configure which commands to run to fetch the secrets.
136
-
137
- #+BEGIN_SRC yaml
138
- # _config.yml
139
- recker:
140
- twitter:
141
- access_token_secret_cmd: cat secrets/access-token-secret
142
- access_token_cmd: cat secrets/access-token
143
- consumer_api_key_cmd: cat secrets/consumer-api-key
144
- consumer_api_secret_cmd: cat secrets/consumer-api-secret-key
145
- #+END_SRC
146
-
147
- Run =bundle exec jekyll tweet= to let it rip!
148
-
149
- [[assets/images/example-tweet.png]]
150
-
151
- Using the =--dry= flag, you can test your configuration without
152
- actually tweeting anything.
153
-
154
- #+BEGIN_EXAMPLE
155
- arecker@25732-arecker:~/src/blog$ be jekyll tweet --dry
156
- jekyll-recker: discovering credentials
157
- Configuration file: /Users/arecker/src/blog/_config.yml
158
- Configuration file: /Users/arecker/src/blog/_config.yml
159
- jekyll-recker: tweeting drag racing, windshield wipers, and alex's painting tips
160
- jekyll-recker: tweeting in dry mode, printing message
161
- jekyll-recker: BEGIN TWEET
162
- Sunday, March 15 2020
163
- drag racing, windshield wipers, and alex's painting tips
164
- https://www.alexrecker.com/2020-03-15.html
165
- END TWEET
166
- #+END_EXAMPLE
167
-
168
- *** Generators
169
-
170
- **** =stats=
171
-
172
- On build time, =jekyll-recker= calculates and stores the following
173
- stats in the =site.data.stats= object
174
-
175
- | Field Name | Field Description |
176
- |-----------------+------------------------------------------------------|
177
- | =posts= | The total number of published posts. |
178
- | =words.total= | The total number of words from all published post. |
179
- | =words.average= | The average number of words for each published post. |
180
- | =days.days= | Current streak of daily, consecutive posts. |
181
- | =days.start= | First day of current streak. |
182
- | =days.end= | Last day of current streak. |
183
-
184
- Use these variables to render your own page of neat writing statistics!
185
-
186
- #+BEGIN_SRC html
187
- <table>
188
- <tr>
189
- <th>Total Posts</th>
190
- <th>Total Words</th>
191
- <th>Average Words per Post</th>
192
- <th>Current Streak</th>
193
- <th>First day of current streak</th>
194
- <th>Last day of current streak</th>
195
- </tr>
196
- <tr>
197
- <td>{{ site.data.stats.posts }}</td>
198
- <td>{{ site.data.stats.words.total }}</td>
199
- <td>{{ site.data.stats.words.average }}</td>
200
- <td>{{ site.data.stats.days.days }}</td>
201
- <td>{{ site.data.stats.days.start }}</td>
202
- <td>{{ site.data.stats.days.end }}</td>
203
- </tr>
204
- </table>
205
- #+END_SRC