jekyll-recker 1.3.0 → 1.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 446f90bccab24d4aba5fcb31778d961863db98d95314b4a6b7966f9c569d8d61
4
- data.tar.gz: 5ecc070929d03cdce18ca8f7b77482b1dc38395a585be2ffe8112cad6cb56f2f
3
+ metadata.gz: bc0bc14a94bfceaa78cca2b93c977b7f54ec9b25f40aead7be6462eb0ccb01cb
4
+ data.tar.gz: 280235bc9e48a76f7e7a8731e7737fa3a5618cee5f14d39a6b427b6ec22bb93d
5
5
  SHA512:
6
- metadata.gz: 9bdbb621367ba9487c4cfc1e713533e4337e17f7464b99a33f47a4d3de1b54672db45e1a6e12baaf9f1ca9276a9da333f23653029c1a7497108a767fdb1596a7
7
- data.tar.gz: cc860da7f47e5cc5b20e8e2c93072f6b30c38ffde2ebc36b22f4b7a2c33a9a947621742b65ce039bc0aaa058008e38619acb31ca429c115bc3fa8a4fd37b3530
6
+ metadata.gz: 6f469867ce018439e8bbde4406f627e643c969cd65f1d33e70efa966db22c7e2fa3e0f8930e5e23af2861fa88fc68b34072cf37d6646d8e58f0ee5038e006a42
7
+ data.tar.gz: 2bf8be1723090a4350ec2945d4cd615395f819e7442ab1cb116a3c626003ab3613ee6f60b0c83c3e287a5d995e4f2947da6c4205df45af96c95e15d141fa1567
data/README.md CHANGED
@@ -95,10 +95,10 @@ Configure the tweet share in `_config.yml`.
95
95
 
96
96
  Alternatively, ensure these environment variables are set.
97
97
 
98
- export ACCESS_TOKEN_SECRET="..."
99
- export ACCESS_TOKEN="..."
100
- export CONSUMER_API_KEY="..."
101
- export CONSUMER_API_SECRET="..."
98
+ export TWITTER_ACCESS_TOKEN_SECRET="..."
99
+ export TWITTER_ACCESS_TOKEN="..."
100
+ export TWITTER_CONSUMER_API_KEY="..."
101
+ export TWITTER_CONSUMER_API_SECRET="..."
102
102
 
103
103
  [example slack]: screenshots/example-slack.png
104
104
  [example tweet]: screenshots/example-tweet.png
@@ -0,0 +1,14 @@
1
+ <figure>
2
+ {%- if include.url %}
3
+ <a href="{{ include.url }}">
4
+ {%- endif %}
5
+ <img alt="{{ include.alt | default: include.filename }}" src="{{ site.baseurl }}assets/images/{{ include.filename }}"/>
6
+ {%- if include.url %}
7
+ </a>
8
+ {%- endif %}
9
+ {%- if include.caption %}
10
+ <figcaption>
11
+ <p>{{ include.caption }}</p>
12
+ </figcaption>
13
+ {%- endif %}
14
+ </figure>
@@ -0,0 +1,21 @@
1
+ {%- capture title %}{{ include.title | default: page.title }}{%- endcapture %}
2
+ {%- capture description %}{{ include.description | default: site.description }}{%- endcapture %}
3
+ {%- capture image %}{{ include.image | default: page.image }}{%- endcapture %}
4
+ <head>
5
+ <meta charset="UTF-8"/>
6
+ <title>{{ title }} | {{ description }}</title>
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <meta name="twitter:card" content="summary" />
9
+ <meta name="twitter:site" content="@{{ site.twitter_username }}" />
10
+ <meta name="twitter:title" content="{{ include.title }}" />
11
+ <meta name="twitter:description" content="{{ include.description }}" />
12
+ <meta property="og:url" content="{{ site.url }}{{ page.url }}" />
13
+ <meta property="og:type" content="article" />
14
+ <meta property="og:title" content="{{ title }}"/>
15
+ <meta property="og:description" content="{{ description }}" />
16
+ {%- if image %}
17
+ <meta name="twitter:image" content="{{ site.url }}{{ site.base_url }}/assets/images/{{ image }}"/>
18
+ <meta property="og:image" content="{{ site.url }}{{ site.base_url }}/assets/images/{{ image }}"/>
19
+ {%- endif %}
20
+ <link href="{{ site.baseurl }}/assets/jekyll-recker.css" rel="stylesheet"/>
21
+ </head>
@@ -0,0 +1,13 @@
1
+ <nav class="clearfix">
2
+ {%- if page.next -%}
3
+ <a href="{{ page.next.url }}">
4
+ ⟵ {{ page.next.slug }}
5
+ </a>
6
+ {%- endif -%}
7
+ {%- if page.previous -%}
8
+ <a class="float-right" href="{{ page.previous.url }}">
9
+ {{ page.previous.slug }} ⟶
10
+ </a>
11
+ {%- endif -%}
12
+ </nav>
13
+
@@ -1,9 +1,13 @@
1
- ---
2
- layout: default
3
- ---
4
- {% include header.html title=site.title subtitle=site.description %}
5
- <hr/>
6
- {% include nav.html %}
7
- <hr/>
8
- {{ content }}
9
-
1
+ <!doctype html>
2
+ <html lang="en">
3
+ {% include head.html title=site.title %}
4
+ <body>
5
+ {% include header.html title=site.title subtitle=site.description %}
6
+ <hr/>
7
+ {% include nav.html %}
8
+ <hr/>
9
+ {{ content }}
10
+ <hr/>
11
+ {% include footer.html %}
12
+ </body>
13
+ </html>
@@ -1,8 +1,13 @@
1
- ---
2
- layout: default
3
- ---
4
- {% include header.html title=page.title subtitle=page.description %}
5
- <hr/>
6
- {% include nav.html %}
7
- <hr/>
8
- {{ content }}
1
+ <!doctype html>
2
+ <html lang="en">
3
+ {% include head.html title=site.title %}
4
+ <body>
5
+ {% include header.html title=page.title subtitle=page.description %}
6
+ <hr/>
7
+ {% include nav.html %}
8
+ <hr/>
9
+ {{ content }}
10
+ <hr/>
11
+ {% include footer.html %}
12
+ </body>
13
+ </html>
@@ -1,28 +1,20 @@
1
- ---
2
- layout: default
3
- ---
4
- {% capture datestring %}{{ page.date | date: '%A, %B %d %Y' }}{% endcapture %}
5
- {% include header.html title=datestring subtitle=page.title %}
6
- <hr/>
7
- {% include nav.html %}
8
- <hr/>
9
- {%- if page.image -%}
10
- <br/>
11
- <figure>
12
- <img alt="page.image" src="{{ site.baseurl }}assets/images/{{ page.image }}"/>
13
- </figure>
14
- <br/>
15
- {%- endif -%}
16
- {{ content }}
17
- <nav class="clearfix">
18
- {%- if page.next -%}
19
- <a href="{{ page.next.url }}">
20
- ⟵ {{ page.next.slug }}
21
- </a>
22
- {%- endif -%}
23
- {%- if page.previous -%}
24
- <a class="float-right" href="{{ page.previous.url }}">
25
- {{ page.previous.slug }} ⟶
26
- </a>
27
- </nav>
28
- {%- endif -%}
1
+ {%- capture datestring %}{{ page.date | uyd_date }}{% endcapture %}
2
+ <!doctype html>
3
+ <html lang="en">
4
+ {% include head.html title=datestring description=page.title %}
5
+ <body>
6
+ {% include header.html title=datestring subtitle=page.title %}
7
+ <hr/>
8
+ {% include nav.html %}
9
+ <hr/>
10
+ {%- if page.image -%}
11
+ <br/>
12
+ {% include figure.html filename=page.image %}
13
+ <br/>
14
+ {%- endif -%}
15
+ {{ content }}
16
+ {% include pager.html %}
17
+ <hr/>
18
+ {% include footer.html %}
19
+ </body>
20
+ </html>
@@ -2,21 +2,20 @@
2
2
 
3
3
  require 'jekyll'
4
4
 
5
- module Jekyll
6
- # Recker
7
- module Recker
8
- require 'jekyll_recker/logger.rb'
9
- require 'jekyll_recker/mixins.rb'
5
+ # jekyll-recker
6
+ #
7
+ # The greatest jekyll plugin in the world
8
+ module JekyllRecker
9
+ autoload :Configuration, 'jekyll_recker/configuration.rb'
10
+ autoload :Error, 'jekyll_recker/error.rb'
11
+ autoload :Mixins, 'jekyll_recker/mixins.rb'
12
+ autoload :Shell, 'jekyll_recker/shell.rb'
13
+ autoload :Social, 'jekyll_recker/social.rb'
14
+ autoload :VERSION, 'jekyll_recker/version.rb'
10
15
 
11
- require 'jekyll_recker/commands.rb'
12
- require 'jekyll_recker/configuration.rb'
13
- require 'jekyll_recker/error.rb'
14
- require 'jekyll_recker/generators.rb'
15
- require 'jekyll_recker/shell.rb'
16
- require 'jekyll_recker/slack.rb'
17
- require 'jekyll_recker/tags.rb'
18
- require 'jekyll_recker/twitter.rb'
19
- require 'jekyll_recker/version.rb'
20
- require 'jekyll_recker/words.rb'
21
- end
16
+ # Eager loads!
17
+ require 'jekyll_recker/commands.rb'
18
+ require 'jekyll_recker/filters.rb'
19
+ require 'jekyll_recker/generators.rb'
20
+ require 'jekyll_recker/tags.rb'
22
21
  end
@@ -1,73 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Jekyll
4
- module Recker
5
- # Commands
6
- module Commands
7
- # Share
8
- class Share < Jekyll::Command
9
- include Mixins::Logging
3
+ module JekyllRecker
4
+ # Commands
5
+ module Commands
6
+ # Share
7
+ class Share < Jekyll::Command
8
+ include Mixins::Logging
10
9
 
11
- def self.init_with_program(prog)
12
- prog.command(:share) do |c|
13
- c.syntax 'share'
14
- c.description 'Share latest post with each configured backend'
15
- c.option 'dry', '-d', '--dry', 'perform dry run'
16
- c.action do |_args, _options|
17
- logger.info 'normally I\'d share here'
18
- rescue ReckerError => e
19
- logger.abort_with e.message
20
- end
21
- end
10
+ def self.init_with_program(prog)
11
+ prog.command(:share) do |c|
12
+ c.syntax 'share'
13
+ c.description 'Share latest post with each configured backend'
14
+ c.option 'dry', '-d', '--dry', 'perform dry run'
15
+ c.action { |args, opts| action(args, opts) }
22
16
  end
23
17
  end
24
18
 
25
- # Slack
26
- class Slack < Jekyll::Command
27
- include Mixins::Logging
28
- def self.init_with_program(prog)
29
- prog.command(:slack) do |c|
30
- c.syntax 'slack'
31
- c.description 'slack latest post'
32
- c.option 'dry', '-d', '--dry', 'print message instead of posting'
33
- c.action { |args, opts| action(args, opts) }
34
- end
35
- end
36
-
37
- def self.action(_args, options)
38
- Recker::Slack.each_in_config(dry: options['dry']) do |client|
39
- logger.info "#{client.key}: discovering webhook"
40
- client.discover_webhook!
41
- logger.info "#{client.key}: posting #{client.latest.data['title']}"
42
- client.post_latest!
43
- end
44
- rescue ReckerError => e
45
- logger.abort_with e.message
46
- end
47
- end
48
-
49
- # Tweet
50
- class Tweet < Jekyll::Command
51
- include Mixins::Logging
52
-
53
- def self.init_with_program(prog)
54
- prog.command(:tweet) do |c|
55
- c.syntax 'tweet'
56
- c.description 'tweet latest post'
57
- c.option 'dry', '-d', '--dry', 'print message instead of tweeting'
58
- c.action { |args, opts| action(args, opts) }
59
- end
60
- end
61
-
62
- def self.action(_args, options)
63
- client = Jekyll::Recker::Twitter.new(dry: options['dry'])
64
- logger.info 'discovering credentials'
65
- client.discover_credentials!
66
- logger.info "tweeting #{client.latest.data['title']}"
67
- client.post_latest!
68
- rescue ReckerError => e
69
- logger.abort_with e.message
70
- end
19
+ def self.action(args, options)
20
+ JekyllRecker::Social.action(args, options)
21
+ rescue ::JekyllRecker::Error => e
22
+ logger.error e.message
23
+ exit 1
71
24
  end
72
25
  end
73
26
  end
@@ -1,35 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Jekyll
4
- module Recker
5
- # Configuration
6
- module Configuration
7
- def self.jekyll
8
- @jekyll ||= Jekyll.configuration
9
- end
3
+ module JekyllRecker
4
+ # Configuration
5
+ module Configuration
6
+ def self.jekyll
7
+ @jekyll ||= Jekyll.configuration
8
+ end
10
9
 
11
- def self.recker
12
- jekyll.fetch('recker', {})
13
- end
10
+ def self.recker
11
+ jekyll.fetch('recker', {})
12
+ end
14
13
 
15
- def self.twitter
16
- recker.fetch('twitter', {})
17
- end
14
+ def self.facebook
15
+ recker.fetch('facebook', {})
16
+ end
18
17
 
19
- def self.slack
20
- recker.fetch('slack', {})
21
- end
18
+ def self.twitter
19
+ recker.fetch('twitter', {})
20
+ end
22
21
 
23
- def self.site
24
- @site = Jekyll::Site.new(jekyll)
25
- @site.reset
26
- @site.read
27
- @site
28
- end
22
+ def self.slack
23
+ recker.fetch('slack', {})
24
+ end
25
+
26
+ def self.site
27
+ @site = Jekyll::Site.new(jekyll)
28
+ @site.reset
29
+ @site.read
30
+ @site
31
+ end
29
32
 
30
- def self.latest_post
31
- @latest_post ||= site.posts.docs.last
32
- end
33
+ def self.latest_post
34
+ @latest_post ||= site.posts.docs.last
33
35
  end
34
36
  end
35
37
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Jekyll
4
- module Recker
5
- # ReckerError
6
- class ReckerError < StandardError; end
7
- end
3
+ module JekyllRecker
4
+ # Error
5
+ class Error < StandardError; end
8
6
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JekyllRecker
4
+ # Filters
5
+ module Filters
6
+ # Converts a date object to standard Uhh Yeah Dude format.
7
+ def uyd_date(date)
8
+ date.strftime('%A, %B %d %Y')
9
+ end
10
+
11
+ # Adds commas to a number
12
+ def pretty(num)
13
+ num.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
14
+ end
15
+ end
16
+ end
17
+
18
+ Liquid::Template.register_filter(JekyllRecker::Filters)
@@ -1,111 +1,109 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Jekyll
4
- module Recker
5
- module Generators
6
- # Stats Module
3
+ module JekyllRecker
4
+ module Generators
5
+ # Stats Module
6
+ #
7
+ # Functions for stats generators.
8
+ # @abstract
9
+ module Stats
10
+ include Mixins::Logging
11
+ include Jekyll::Filters
12
+
13
+ def key
14
+ self.class.const_get(:KEY)
15
+ end
16
+
17
+ def generate(site)
18
+ @site = site
19
+ logger.info "crunching stats.#{key}"
20
+ @site.data['stats'] ||= {}
21
+ @site.data['stats'][key] = crunch
22
+ end
23
+
24
+ def crunch
25
+ raise NotImplementedError, '#crunch not implemented!'
26
+ end
27
+
28
+ # Calculates the average of a list of numbers.
7
29
  #
8
- # Functions for stats generators.
9
- # @abstract
10
- module Stats
11
- include Mixins::Logging
12
- include Jekyll::Filters
13
-
14
- def key
15
- self.class.const_get(:KEY)
16
- end
30
+ # @param [Array<Numeric>] numlist list of numbers to be averaged.
31
+ # @return [Numeric] rounded, calculated average of numlist.
32
+ def average(numlist)
33
+ calc = numlist.inject { |sum, el| sum + el }.to_f / numlist.size
34
+ calc.round
35
+ end
17
36
 
18
- def generate(site)
19
- @site = site
20
- logger.info "crunching stats.#{key}"
21
- @site.data['stats'] ||= {}
22
- @site.data['stats'][key] = crunch
23
- end
37
+ # Calculates the total of a list of numbers.
38
+ #
39
+ # @param [Array<Numeric>] numlist list of numbers to be totaled.
40
+ # @return [Numeric] calculated total of numlist.
41
+ def total(numlist)
42
+ numlist.inject(0) { |sum, x| sum + x }
43
+ end
24
44
 
25
- def crunch
26
- raise NotImplementedError, '#crunch not implemented!'
27
- end
45
+ def entries
46
+ @site.posts.docs.select(&:published?)
47
+ end
48
+ end
28
49
 
29
- # Calculates the average of a list of numbers.
30
- #
31
- # @param [Array<Numeric>] numlist list of numbers to be averaged.
32
- # @return [Numeric] rounded, calculated average of numlist.
33
- def average(numlist)
34
- calc = numlist.inject { |sum, el| sum + el }.to_f / numlist.size
35
- calc.round
36
- end
50
+ # Post Count Generator
51
+ class PostCount < Jekyll::Generator
52
+ include Stats
37
53
 
38
- # Calculates the total of a list of numbers.
39
- #
40
- # @param [Array<Numeric>] numlist list of numbers to be totaled.
41
- # @return [Numeric] calculated total of numlist.
42
- def total(numlist)
43
- numlist.inject(0) { |sum, x| sum + x }
44
- end
54
+ KEY = 'posts'
45
55
 
46
- def entries
47
- @site.posts.docs.select(&:published?)
48
- end
56
+ def crunch
57
+ entries.count
49
58
  end
59
+ end
50
60
 
51
- # Post Count Generator
52
- class PostCount < Jekyll::Generator
53
- include Stats
61
+ # Word Count Generator
62
+ class Words < Jekyll::Generator
63
+ include Stats
54
64
 
55
- KEY = 'posts'
65
+ KEY = 'words'
56
66
 
57
- def crunch
58
- entries.count.pretty
59
- end
67
+ def crunch
68
+ total_counts = entries.collect(&:content).map { |c| number_of_words(c) }
69
+ {
70
+ 'average' => average(total_counts),
71
+ 'total' => total(total_counts)
72
+ }
60
73
  end
74
+ end
61
75
 
62
- # Word Count Generator
63
- class Words < Jekyll::Generator
64
- include Stats
76
+ # Streak Count Generator
77
+ class Streaks < Jekyll::Generator
78
+ include Stats
65
79
 
66
- KEY = 'words'
80
+ KEY = 'days'
67
81
 
68
- def crunch
69
- total_counts = entries.collect(&:content).map { |c| number_of_words(c) }
82
+ def crunch
83
+ streaks.take(1).map do |count, dates|
70
84
  {
71
- 'average' => average(total_counts).pretty,
72
- 'total' => total(total_counts).pretty
85
+ 'days' => count,
86
+ 'start' => dates[0],
87
+ 'end' => dates[1]
73
88
  }
74
- end
89
+ end.first
75
90
  end
76
91
 
77
- # Streak Count Generator
78
- class Streaks < Jekyll::Generator
79
- include Stats
80
-
81
- KEY = 'days'
82
-
83
- def crunch
84
- streaks.take(1).map do |count, dates|
85
- {
86
- 'days' => count.pretty,
87
- 'start' => dates[0],
88
- 'end' => dates[1]
89
- }
90
- end.first
91
- end
92
+ private
92
93
 
93
- private
94
-
95
- def streaks
96
- _streaks = []
97
- entry_dates.slice_when do |prev, curr|
98
- curr != prev - 1
99
- end.each do |dates|
100
- first, last = dates.minmax
101
- _streaks << [(last - first).to_i, [first, last]]
102
- end
103
- _streaks
94
+ def streaks
95
+ _streaks = []
96
+ entry_dates.slice_when do |prev, curr|
97
+ curr != prev - 1
98
+ end.each do |dates|
99
+ first, last = dates.minmax
100
+ _streaks << [(last - first).to_i, [first, last]]
104
101
  end
102
+ _streaks
103
+ end
105
104
 
106
- def entry_dates
107
- entries.collect(&:date).map { |t| Date.new(t.year, t.month, t.day) }.sort.reverse
108
- end
105
+ def entry_dates
106
+ entries.collect(&:date).map { |t| Date.new(t.year, t.month, t.day) }.sort.reverse
109
107
  end
110
108
  end
111
109
  end
@@ -1,28 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Jekyll
4
- module Recker
5
- module Mixins
6
- # Descendants
7
- module Descendants
8
- def self.included(base)
9
- base.extend(self)
10
- end
3
+ require 'logger'
11
4
 
12
- def descendants
13
- ObjectSpace.each_object(Class).select { |klass| klass < self }
14
- end
5
+ module JekyllRecker
6
+ module Mixins
7
+ # Descendants
8
+ module Descendants
9
+ def self.included(base)
10
+ base.extend(self)
15
11
  end
16
12
 
17
- # Logging
18
- module Logging
19
- def self.included(base)
20
- base.extend(self)
21
- end
13
+ def descendants
14
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
15
+ end
16
+ end
17
+
18
+ # Introspection
19
+ module Introspection
20
+ def self.included(base)
21
+ base.extend(self)
22
+ end
23
+
24
+ def class_name
25
+ self.class.name.split('::').last
26
+ end
27
+ end
28
+
29
+ # Logging
30
+ module Logging
31
+ def self.included(base)
32
+ base.extend(self)
33
+ end
22
34
 
23
- def logger
24
- Jekyll::Recker.logger
25
- end
35
+ def logger
36
+ @logger ||= Logger.new(
37
+ STDOUT,
38
+ formatter: proc { |_severity, _datetime, _progname, msg| "jekyll-recker: #{msg}\n" }
39
+ )
26
40
  end
27
41
  end
28
42
  end
@@ -2,13 +2,13 @@
2
2
 
3
3
  require 'open3'
4
4
 
5
- module Jekyll
6
- # Recker
7
- module Recker
5
+ module JekyllRecker
6
+ # Shell
7
+ module Shell
8
8
  # ShellCommandFailed
9
- class ShellCommandFailed < ReckerError; end
9
+ class ShellCommandFailed < JekyllRecker::Error; end
10
10
 
11
- def self.shell(cmd)
11
+ def self.run(cmd)
12
12
  out, err, status = Open3.capture3(cmd)
13
13
  return out if status.success?
14
14
 
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'slack-notifier'
4
+ require 'twitter'
5
+
6
+ module JekyllRecker
7
+ module Social
8
+ def self.action(args, options)
9
+ args += %w[slack twitter] if args.empty?
10
+ Slack.share(dry: options['dry']) if args.include?('slack')
11
+ Twitter.share(dry: options['dry']) if args.include?('twitter')
12
+ end
13
+ # Backend
14
+ #
15
+ # Backend base class for social sharing backends.
16
+ # @abstract
17
+ class Share
18
+ include Mixins::Introspection
19
+ include Mixins::Logging
20
+
21
+ def self.share(dry: false)
22
+ backend = new(dry: dry)
23
+ logger.info "#{backend.name} - building configuration"
24
+ backend.configure!
25
+
26
+ logger.info "#{backend.name} - sharing \"#{backend.latest_title}\""
27
+ backend.post!
28
+ end
29
+
30
+ def initialize(dry: false)
31
+ @dry = dry
32
+ end
33
+
34
+ def dry?
35
+ @dry
36
+ end
37
+
38
+ def config
39
+ @config ||= JekyllRecker::Configuration.recker.fetch(config_key)
40
+ end
41
+
42
+ def config_key
43
+ class_name.downcase
44
+ end
45
+ alias name config_key
46
+
47
+ def post_body
48
+ url = File.join Configuration.jekyll['url'], latest.url
49
+ <<~BODY
50
+ #{latest.data['date'].strftime('%A, %B %-d %Y')}
51
+ #{latest.data['title']}
52
+ #{url}
53
+ BODY
54
+ end
55
+
56
+ def latest
57
+ @latest ||= Configuration.latest_post
58
+ end
59
+
60
+ def latest_title
61
+ latest.data['title']
62
+ end
63
+
64
+ def configure!
65
+ raise NotImplementedError
66
+ end
67
+
68
+ def post!
69
+ raise NotImplementedError
70
+ end
71
+ end
72
+
73
+ # Slack
74
+ #
75
+ # Slack social sharing backend
76
+ class Slack < Share
77
+ def configure!
78
+ @creds = {}
79
+ workspaces.each do |key, data|
80
+ webhook = ENV["SLACK_#{key.upcase}_WEBHOOK"] || extract_from_config(data)
81
+ if webhook.nil?
82
+ raise ReckerError, "cannot find slack webhook for #{key} workspace!"
83
+ end
84
+
85
+ @creds[key] = webhook
86
+ end
87
+ end
88
+
89
+ def post!
90
+ message_body = ::Slack::Notifier::Util::LinkFormatter.format(post_body)
91
+ workspaces.each do |key, config|
92
+ logger.info "posting to #{key} workspace"
93
+ if @dry
94
+ logger.info("BEGIN MESSAGE\n#{message_body.strip}\nEND MESSAGE")
95
+ else
96
+ ::Slack::Notifier.new(
97
+ @creds[key].strip,
98
+ channel: config.fetch('channel'),
99
+ username: config.fetch('username'),
100
+ icon_emoji: config.fetch('emoji')
101
+ ).post(text: message_body)
102
+ end
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ def extract_from_config(data)
109
+ cmd = data['webhook_cmd']
110
+ return nil if cmd.nil?
111
+
112
+ Shell.run(cmd)
113
+ end
114
+
115
+ def workspaces
116
+ config.each
117
+ end
118
+ end
119
+
120
+ # Twitter
121
+ #
122
+ # Twitter social sharing backend
123
+ class Twitter < Share
124
+ def configure!
125
+ creds = extract_from_env || extract_from_config
126
+ raise ReckerError, 'cannot find twitter credentials!' if creds.nil?
127
+
128
+ @client = ::Twitter::REST::Client.new do |settings|
129
+ settings.consumer_key = creds['consumer_api_key']
130
+ settings.consumer_secret = creds['consumer_api_secret']
131
+ settings.access_token = creds['access_token']
132
+ settings.access_token_secret = creds['access_token_secret']
133
+ end
134
+ end
135
+
136
+ def post!
137
+ if dry?
138
+ logger.info('tweeting in dry mode, printing message')
139
+ logger.info("BEGIN TWEET\n#{post_body}END TWEET")
140
+ else
141
+ @client.update(post_body)
142
+ end
143
+ end
144
+
145
+ private
146
+
147
+ def extract_from_env
148
+ values = cred_fieldnames.map { |k| ENV["TWITTER_#{k.upcase}"] }
149
+
150
+ return nil if values.any? { |v| v.nil? || v.empty? }
151
+
152
+ Hash[cred_fieldnames.zip(values)]
153
+ end
154
+
155
+ def extract_from_config
156
+ values = cred_fieldnames.map do |k|
157
+ Shell.run(Configuration.twitter["#{k}_cmd"]).strip
158
+ end
159
+
160
+ return nil if values.any? { |v| v.nil? || v.empty? }
161
+
162
+ Hash[cred_fieldnames.zip(values)]
163
+ end
164
+
165
+ def cred_fieldnames
166
+ [
167
+ 'access_token_secret',
168
+ 'access_token',
169
+ 'consumer_api_key',
170
+ 'consumer_api_secret'
171
+ ]
172
+ end
173
+ end
174
+ end
175
+ end
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Jekyll
4
- module Recker
5
- module Tags
6
- # Returns the VERSION of the running jekyll-recker gem.
7
- class Version < Liquid::Tag
8
- def render(_context)
9
- VERSION
10
- end
3
+ module JekyllRecker
4
+ module Tags
5
+ # Returns the VERSION of the running jekyll-recker gem.
6
+ class Version < Liquid::Tag
7
+ def render(_context)
8
+ VERSION
11
9
  end
12
10
  end
13
11
  end
14
12
  end
15
13
 
16
- Liquid::Template.register_tag('recker_version', Jekyll::Recker::Tags::Version)
14
+ Liquid::Template.register_tag('recker_version', JekyllRecker::Tags::Version)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Jekyll
4
- module Recker
5
- VERSION = '1.3.0'
6
- end
3
+ module JekyllRecker
4
+ VERSION = '1.9.0'
7
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-recker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.9.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-05-23 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
14
  name: bump
@@ -145,10 +145,12 @@ extra_rdoc_files: []
145
145
  files:
146
146
  - LICENSE
147
147
  - README.md
148
+ - _includes/figure.html
148
149
  - _includes/footer.html
150
+ - _includes/head.html
149
151
  - _includes/header.html
150
152
  - _includes/nav.html
151
- - _layouts/default.html
153
+ - _includes/pager.html
152
154
  - _layouts/home.html
153
155
  - _layouts/page.html
154
156
  - _layouts/post.html
@@ -156,15 +158,13 @@ files:
156
158
  - lib/jekyll_recker/commands.rb
157
159
  - lib/jekyll_recker/configuration.rb
158
160
  - lib/jekyll_recker/error.rb
161
+ - lib/jekyll_recker/filters.rb
159
162
  - lib/jekyll_recker/generators.rb
160
- - lib/jekyll_recker/logger.rb
161
163
  - lib/jekyll_recker/mixins.rb
162
164
  - lib/jekyll_recker/shell.rb
163
- - lib/jekyll_recker/slack.rb
165
+ - lib/jekyll_recker/social.rb
164
166
  - lib/jekyll_recker/tags.rb
165
- - lib/jekyll_recker/twitter.rb
166
167
  - lib/jekyll_recker/version.rb
167
- - lib/jekyll_recker/words.rb
168
168
  homepage: https://www.github.com/arecker/jekyll-recker/
169
169
  licenses:
170
170
  - GPLv3
@@ -1,14 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8"/>
5
- <title>{{ site.title }} | {{ page.title | default: site.description }}</title>
6
- <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <link href="{{ site.baseurl }}/assets/jekyll-recker.css" rel="stylesheet"/>
8
- </head>
9
- <body>
10
- {{ content }}
11
- <hr/>
12
- {% include footer.html %}
13
- </body>
14
- </html>
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
-
5
- module Jekyll
6
- # Recker
7
- module Recker
8
- def self.logger
9
- @logger ||= make_logger
10
- end
11
-
12
- def self.make_logger
13
- logger = Logger.new(STDOUT)
14
- logger.formatter = proc do |_severity, _datetime, _progname, msg|
15
- "jekyll-recker: #{msg}\n"
16
- end
17
- logger
18
- end
19
- end
20
- end
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'slack-notifier'
4
-
5
- module Jekyll
6
- # Recker
7
- module Recker
8
- # Slack
9
- class Slack
10
- include Jekyll::Recker::Mixins::Logging
11
-
12
- def self.each_in_config(dry: false)
13
- Configuration.slack.map do |key, body|
14
- yield new(key, body, dry: dry)
15
- end
16
- end
17
-
18
- attr_reader :key
19
-
20
- def initialize(config_key, config_body, dry: false)
21
- @key = config_key
22
- @data = config_body
23
- @webhook = nil
24
- @dry = dry
25
- end
26
-
27
- def discover_webhook!
28
- @webhook = ENV["SLACK_#{@key.upcase}_WEBHOOK"] || extract_from_config
29
- raise ReckerError, 'cannot find slack credentials!' if @webhook.nil?
30
- end
31
-
32
- def latest
33
- @latest ||= Configuration.latest_post
34
- end
35
-
36
- def post_latest!
37
- if @dry
38
- logger.info('postign in dry mode, printing message')
39
- logger.info("BEGIN MESSAGE\n#{message_body.strip}\nEND MESSAGE")
40
- else
41
- ::Slack::Notifier.new(
42
- @webhook.strip,
43
- channel: @data.fetch('channel'),
44
- username: @data.fetch('username'),
45
- icon_emoji: @data.fetch('emoji')
46
- ).post(text: message_body)
47
- end
48
- end
49
-
50
- private
51
-
52
- def message_body
53
- url = File.join Configuration.jekyll['url'], latest.url
54
- body = <<~MSG
55
- #{latest.data['date'].strftime('%A, %B %-d %Y')}
56
- #{latest.data['title']}
57
- #{url}
58
- MSG
59
- ::Slack::Notifier::Util::LinkFormatter.format(body)
60
- end
61
-
62
- def extract_from_config
63
- cmd = @data['webhook_cmd']
64
- return nil if cmd.nil?
65
-
66
- Recker.shell(cmd)
67
- end
68
- end
69
- end
70
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'twitter'
4
-
5
- module Jekyll
6
- module Recker
7
- # Twitter Client
8
- class Twitter
9
- include Mixins::Logging
10
-
11
- def initialize(dry: false)
12
- @dry = dry
13
- end
14
-
15
- def discover_credentials!
16
- @creds = extract_from_env || extract_from_config
17
- raise ReckerError, 'cannot find twitter credentials!' if @creds.nil?
18
-
19
- set_credentials!
20
- end
21
-
22
- def post_latest!
23
- if @dry
24
- logger.info('tweeting in dry mode, printing message')
25
- logger.info("BEGIN TWEET\n#{tweet_body.strip}\nEND TWEET")
26
- else
27
- @client.update(tweet_body)
28
- end
29
- end
30
-
31
- def latest
32
- Configuration.latest_post
33
- end
34
-
35
- private
36
-
37
- def tweet_body
38
- url = File.join Configuration.jekyll['url'], latest.url
39
- <<~TWEET
40
- #{latest.data['date'].strftime('%A, %B %-d %Y')}
41
- #{latest.data['title']}
42
- #{url}
43
- TWEET
44
- end
45
-
46
- def set_credentials!
47
- @client ||= ::Twitter::REST::Client.new do |settings|
48
- settings.consumer_key = @creds['consumer_api_key']
49
- settings.consumer_secret = @creds['consumer_api_secret']
50
- settings.access_token = @creds['access_token']
51
- settings.access_token_secret = @creds['access_token_secret']
52
- end
53
- end
54
-
55
- def extract_from_env
56
- values = cred_fieldnames.map { |k| ENV[k.upcase] }
57
-
58
- return nil if values.any? { |v| v.nil? || v.empty? }
59
-
60
- Hash[cred_fieldnames.zip(values)]
61
- end
62
-
63
- def extract_from_config
64
- values = cred_fieldnames.map do |k|
65
- Recker.shell(Configuration.twitter["#{k}_cmd"]).strip
66
- end
67
-
68
- return nil if values.any? { |v| v.nil? || v.empty? }
69
-
70
- Hash[cred_fieldnames.zip(values)]
71
- end
72
-
73
- def cred_fieldnames
74
- %w[
75
- access_token_secret
76
- access_token
77
- consumer_api_key
78
- consumer_api_secret
79
- ]
80
- end
81
- end
82
- end
83
- end
@@ -1,82 +0,0 @@
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