loading
Generated 2021-01-27T15:17:03+00:00

All Files ( 81.21% covered at 1.3 hits/line )

18 files in total.
463 relevant lines, 376 lines covered and 87 lines missed. ( 81.21% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
spec/entry_spec.rb 100.00 % 88 49 49 0 1.18
spec/files_spec.rb 100.00 % 23 12 12 0 1.50
spec/filters_spec.rb 100.00 % 21 12 12 0 1.33
spec/math_spec.rb 100.00 % 32 14 14 0 1.43
spec/site_spec.rb 100.00 % 116 69 69 0 1.51
spec/time_spec.rb 100.00 % 131 33 33 0 1.42
src/blog.rb 100.00 % 19 13 13 0 1.00
src/blog/commands.rb 35.29 % 30 17 6 11 0.35
src/blog/entry.rb 100.00 % 43 21 21 0 4.90
src/blog/files.rb 100.00 % 14 6 6 0 1.17
src/blog/filters.rb 100.00 % 18 8 8 0 1.00
src/blog/generators.rb 53.49 % 192 86 46 40 0.53
src/blog/git.rb 63.64 % 24 11 7 4 0.64
src/blog/logging.rb 63.64 % 24 11 7 4 0.64
src/blog/math.rb 100.00 % 22 11 11 0 3.00
src/blog/shell.rb 47.83 % 43 23 11 12 0.48
src/blog/site.rb 70.21 % 97 47 33 14 0.98
src/blog/time.rb 90.00 % 44 20 18 2 2.70

spec/entry_spec.rb

100.0% lines covered

49 relevant lines. 49 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'spec_helper'
  3. # rubocop:disable Metrics/BlockLength
  4. 1 describe Blog::Entry do
  5. 10 let(:doc) { double('doc') }
  6. 1 describe '#date' do
  7. 1 it 'should convert Time to a Date' do
  8. 1 expect(doc).to receive('date').and_return Time.parse('2020-07-03').localtime
  9. 1 actual = Blog::Entry.new(doc).date
  10. 1 expected = Date.new(2020, 0o7, 0o3)
  11. 1 expect(actual).to eq(expected)
  12. end
  13. end
  14. 1 describe '#word_count' do
  15. 1 it 'should count the words in content' do
  16. 1 expect(doc).to receive(:content).and_return 'This is a test, see?'
  17. 1 actual = Blog::Entry.new(doc).word_count
  18. 1 expect(actual).to eq(5)
  19. end
  20. end
  21. 1 describe '#title' do
  22. 1 it 'should convert the date to UYD format' do
  23. 1 entry = Blog::Entry.new(doc)
  24. 1 expect(entry).to receive(:date).and_return Date.new(2020, 1, 1)
  25. 1 expect(entry.title).to eq('Wednesday, January 1 2020')
  26. end
  27. end
  28. 1 describe '#subtitle' do
  29. 1 it 'should return the document title' do
  30. 1 expect(doc).to receive(:data).and_return({ 'title' => 'boop' })
  31. 1 expect(Blog::Entry.new(doc).subtitle).to eq('boop')
  32. end
  33. end
  34. 1 describe '#url' do
  35. 1 it 'should return the document url' do
  36. 1 expect(doc).to receive(:url).and_return 'boop'
  37. 1 expect(Blog::Entry.new(doc).url).to eq('boop')
  38. end
  39. end
  40. 1 describe '#words' do
  41. 1 it 'should remove punctuation' do
  42. 1 expect(doc).to receive(:content).and_return 'alex...!'
  43. 1 actual = Blog::Entry.new(doc).words
  44. 1 expected = ['alex']
  45. 1 expect(actual).to eq(expected)
  46. end
  47. 1 it 'should leave apostrophes' do
  48. 1 expect(doc).to receive(:content).and_return "This is Alex\'s blog"
  49. 1 actual = Blog::Entry.new(doc).words
  50. 1 expected = ['this', 'is', "alex\'s", 'blog']
  51. 1 expect(actual).to eq(expected)
  52. end
  53. 1 it 'should make all words lowercase' do
  54. 1 expect(doc).to receive(:content).and_return 'Alex Martin Recker'
  55. 1 actual = Blog::Entry.new(doc).words
  56. 1 expected = %w[alex martin recker]
  57. 1 expect(actual).to eq(expected)
  58. end
  59. 1 it 'should remove newlines and whitespace' do
  60. 1 content = <<~TEXT
  61. But soft!
  62. What light through yonder window breaks?
  63. It is the east, and Juliet, is the sun!
  64. TEXT
  65. 1 expect(doc).to receive(:content).and_return content
  66. 1 expected = %w[
  67. but soft what light through
  68. yonder window breaks it is
  69. the east and juliet is the sun
  70. ]
  71. 1 actual = Blog::Entry.new(doc).words
  72. 1 expect(actual).to eq(expected)
  73. end
  74. end
  75. end
  76. # rubocop:enable Metrics/BlockLength

spec/files_spec.rb

100.0% lines covered

12 relevant lines. 12 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 describe Blog::Files do
  3. 7 let(:k) { Class.new { extend ::Blog::Files } }
  4. 1 describe '#root' do
  5. 1 it 'should return a real path' do
  6. 1 expect(File.directory?(k.root)).to be true
  7. end
  8. end
  9. 1 describe '#join' do
  10. 1 it 'should take one argument' do
  11. 1 actual = k.join('images')
  12. 1 expect(File.basename(actual)).to eq('images')
  13. end
  14. 1 it 'should take multiple arguments' do
  15. 1 actual = k.join('a', 'b')
  16. 1 expect(actual.split('/').last(2)).to eq(%w[a b])
  17. end
  18. end
  19. end

spec/filters_spec.rb

100.0% lines covered

12 relevant lines. 12 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 describe Blog::Filters do
  3. 5 let(:k) { Class.new { extend ::Blog::Filters } }
  4. 1 describe '#uyd_date' do
  5. 1 it 'should convert a date into standard UYD format' do
  6. 1 actual = k.uyd_date(Date.new(2020, 7, 21))
  7. 1 expected = 'Tuesday, July 21 2020'
  8. 1 expect(actual).to eq(expected)
  9. end
  10. end
  11. 1 describe '#pretty' do
  12. 1 it 'should add commas to a number' do
  13. 1 actual = k.pretty(1_000_001)
  14. 1 expected = '1,000,001'
  15. 1 expect(actual).to eq(expected)
  16. end
  17. end
  18. end

spec/math_spec.rb

100.0% lines covered

14 relevant lines. 14 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 describe Blog::Math do
  3. 7 let(:k) { Class.new { extend ::Blog::Math } }
  4. 1 describe '#average' do
  5. 1 it 'should average a list of integers' do
  6. 1 expect(k.average([1, 1, 2, 2, 3, 3])).to eq(2)
  7. end
  8. end
  9. 1 describe '#total' do
  10. 1 it 'should total a list of integers' do
  11. 1 expect(k.total([1, 1, 2, 2, 3, 3])).to eq(12)
  12. end
  13. end
  14. 1 describe '#occurences' do
  15. 1 it 'should count occurances of keys in a list of targets' do
  16. 1 keys = %w[Kelly Alex Sarah Frank]
  17. 1 text = 'Kelly and Alex and Sarah are siblings. Kelly and Sarah are sisters'
  18. expected = {
  19. 1 'Kelly' => 2,
  20. 'Alex' => 1,
  21. 'Sarah' => 2
  22. }
  23. 1 expect(k.occurences(keys, text.split)).to eq(expected)
  24. end
  25. end
  26. end

spec/site_spec.rb

100.0% lines covered

69 relevant lines. 69 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. # rubocop:disable Metrics/BlockLength
  3. 1 describe Blog::Site do
  4. 4 let(:site) { double('site') }
  5. 1 describe '#entries' do
  6. 1 it 'should return an ordered list of descending posts' do
  7. 4 dates = (1..3).map { |n| Date.new(2020, 7, n) }
  8. 1 posts = dates.map do |date|
  9. 3 post = double('post')
  10. 3 allow(post).to receive(:published?).and_return true
  11. 3 allow(post).to receive(:date).and_return date
  12. 3 post
  13. end
  14. 1 expect(site).to receive_message_chain(:posts, :docs).and_return(posts)
  15. 1 actual = Blog::Site.new(site).entries.collect(&:date)
  16. 1 expect(actual).to eq(dates.reverse)
  17. end
  18. 1 it 'should return published posts' do
  19. 1 posts = []
  20. 1 published = double('published')
  21. 1 expect(published).to receive(:published?).and_return true
  22. 1 posts << published
  23. 1 unpublished = double('unpublished')
  24. 1 expect(unpublished).to receive(:published?).and_return false
  25. 1 posts << unpublished
  26. 1 posts.each_with_index do |post, i|
  27. 2 date = Date.new(2020, 7, i + 1)
  28. 2 allow(post).to receive(:date).and_return date
  29. end
  30. 1 expect(site).to receive_message_chain(:posts, :docs).and_return(posts)
  31. 1 actual = Blog::Site.new(site).entries
  32. 1 expect(actual.count).to eq(1)
  33. 1 expect(actual.first.date).to eq(Date.new(2020, 7, 1))
  34. end
  35. 1 describe '#data' do
  36. 1 it 'should pass through to @site.data' do
  37. 1 site = double('site')
  38. 1 data = {}
  39. 1 expect(site).to receive(:data).and_return(data)
  40. 1 Blog::Site.new(site).data['hello'] = 'world'
  41. 1 expect(data).to eq({ 'hello' => 'world' })
  42. end
  43. end
  44. 1 describe '#word_counts' do
  45. 1 it 'should aggregate entry word counts' do
  46. 1 entries = []
  47. 1 3.times do
  48. 3 entry = double('entry')
  49. 3 expect(entry).to receive(:word_count).and_return 100
  50. 3 entries << entry
  51. end
  52. 1 site = Blog::Site.new({})
  53. 1 expect(site).to receive(:entries).and_return entries
  54. 1 expect(site.word_counts).to eq([100, 100, 100])
  55. end
  56. end
  57. 1 describe '#dates' do
  58. 1 it 'should aggregate entry dates' do
  59. 4 dates = (1..3).map { |n| ::Date.new(2020, 1, n) }
  60. 1 entries = dates.map do |date|
  61. 3 entry = double('entry')
  62. 3 expect(entry).to receive(:date).and_return(date)
  63. 3 entry
  64. end
  65. 1 site = Blog::Site.new(site)
  66. 1 expect(site).to receive(:entries).and_return entries.reverse
  67. 1 expect(site.dates).to eq(dates.reverse)
  68. end
  69. end
  70. 1 describe '#recker_config' do
  71. 1 it 'should default to empty' do
  72. 1 expect(site).to receive(:config).and_return({})
  73. 1 expect(Blog::Site.new(site).recker_config).to eq({})
  74. end
  75. end
  76. 1 describe '#production?' do
  77. 3 let(:k) { Blog::Site.new({}) }
  78. 1 context 'JEKYLL_ENV=production' do
  79. 2 before(:each) { expect(ENV).to receive(:[]).with('JEKYLL_ENV').and_return('production') }
  80. 1 it 'should return true' do
  81. 1 expect(k.production?).to be true
  82. end
  83. end
  84. 1 context 'JEKYLL_ENV=development' do
  85. 2 before(:each) { expect(ENV).to receive(:[]).with('JEKYLL_ENV').and_return('development') }
  86. 1 it 'should return false' do
  87. 1 expect(k.production?).to be false
  88. end
  89. end
  90. end
  91. end
  92. end
  93. # rubocop:enable Metrics/BlockLength

spec/time_spec.rb

100.0% lines covered

33 relevant lines. 33 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. # rubocop:disable Metrics/BlockLength
  3. 1 describe Blog::Time do
  4. 15 let(:k) { Class.new { extend ::Blog::Time } }
  5. 1 describe '#to_uyd_date' do
  6. 1 it 'should convert a date into UYD show opening format' do
  7. 1 expect(k.to_uyd_date(::Date.new(2020, 1, 1))).to eq 'Wednesday, January 1 2020'
  8. end
  9. end
  10. 1 describe '#slice_by_consecutive' do
  11. 1 it 'should slice a list of ascending dates' do
  12. dates = [
  13. 1 ::Date.new(2001, 2, 3),
  14. ::Date.new(2001, 2, 4),
  15. ::Date.new(2001, 2, 6),
  16. ::Date.new(2001, 2, 7),
  17. ::Date.new(2001, 2, 8)
  18. ]
  19. expected = [
  20. [
  21. 1 ::Date.new(2001, 2, 3),
  22. ::Date.new(2001, 2, 4)
  23. ],
  24. [
  25. ::Date.new(2001, 2, 6),
  26. ::Date.new(2001, 2, 7),
  27. ::Date.new(2001, 2, 8)
  28. ]
  29. ]
  30. 1 expect(k.slice_by_consecutive(dates)).to eq(expected)
  31. end
  32. 1 it 'should slice a list of descending dates' do
  33. dates = [
  34. 1 ::Date.new(2001, 2, 8),
  35. ::Date.new(2001, 2, 7),
  36. ::Date.new(2001, 2, 6),
  37. ::Date.new(2001, 2, 4),
  38. ::Date.new(2001, 2, 3)
  39. ]
  40. expected = [
  41. [
  42. 1 ::Date.new(2001, 2, 8),
  43. ::Date.new(2001, 2, 7),
  44. ::Date.new(2001, 2, 6)
  45. ],
  46. [
  47. ::Date.new(2001, 2, 4),
  48. ::Date.new(2001, 2, 3)
  49. ]
  50. ]
  51. 1 expect(k.slice_by_consecutive(dates)).to eq(expected)
  52. end
  53. end
  54. 1 describe '#calculate_streaks' do
  55. 1 it 'should calculate streaks from ascending dates' do
  56. dates = [
  57. 1 ::Date.new(2001, 2, 3),
  58. ::Date.new(2001, 2, 4),
  59. ::Date.new(2001, 2, 6),
  60. ::Date.new(2001, 2, 7),
  61. ::Date.new(2001, 2, 8)
  62. ]
  63. expected = [
  64. {
  65. 1 'days' => 1,
  66. 'start' => ::Date.new(2001, 2, 3),
  67. 'end' => ::Date.new(2001, 2, 4)
  68. },
  69. {
  70. 'days' => 2,
  71. 'start' => ::Date.new(2001, 2, 6),
  72. 'end' => ::Date.new(2001, 2, 8)
  73. }
  74. ]
  75. 1 expect(k.calculate_streaks(dates)).to eq(expected)
  76. end
  77. 1 it 'should calculate streaks from descending dates' do
  78. dates = [
  79. 1 ::Date.new(2001, 2, 8),
  80. ::Date.new(2001, 2, 7),
  81. ::Date.new(2001, 2, 6),
  82. ::Date.new(2001, 2, 4),
  83. ::Date.new(2001, 2, 3)
  84. ]
  85. expected = [
  86. {
  87. 1 'days' => 2,
  88. 'start' => ::Date.new(2001, 2, 6),
  89. 'end' => ::Date.new(2001, 2, 8)
  90. },
  91. {
  92. 'days' => 1,
  93. 'start' => ::Date.new(2001, 2, 3),
  94. 'end' => ::Date.new(2001, 2, 4)
  95. }
  96. ]
  97. 1 expect(k.calculate_streaks(dates)).to eq(expected)
  98. end
  99. end
  100. 1 describe '#time_to_date' do
  101. 1 it 'should convert a time to a date' do
  102. 1 actual = k.time_to_date(Time.parse('2020-07-03').localtime)
  103. 1 expected = Date.new(2020, 0o7, 0o3)
  104. 1 expect(actual).to eq(expected)
  105. end
  106. end
  107. 1 describe '#date_to_time' do
  108. 1 it 'should convert a date to a time' do
  109. 1 actual = k.date_to_time(::Date.new(2020, 1, 1))
  110. 1 expect(actual).to be_a ::DateTime
  111. 1 expect([actual.hour, actual.minute, actual.second]).to eq([0, 0, 0])
  112. end
  113. end
  114. end
  115. # rubocop:enable Metrics/BlockLength

src/blog.rb

100.0% lines covered

13 relevant lines. 13 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. # Blog
  3. 1 module Blog
  4. 1 autoload :Entry, 'blog/entry'
  5. 1 autoload :Files, 'blog/files'
  6. 1 autoload :Git, 'blog/git'
  7. 1 autoload :Logging, 'blog/logging'
  8. 1 autoload :Math, 'blog/math'
  9. 1 autoload :Shell, 'blog/shell'
  10. 1 autoload :Site, 'blog/site'
  11. 1 autoload :Social, 'blog/social'
  12. 1 autoload :Time, 'blog/time'
  13. # Eager Loads
  14. 1 require 'blog/commands'
  15. 1 require 'blog/filters'
  16. 1 require 'blog/generators'
  17. end

src/blog/commands.rb

35.29% lines covered

17 relevant lines. 6 lines covered and 11 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'jekyll'
  3. 1 module Blog
  4. # Commands
  5. 1 module Commands
  6. # Share Command
  7. 1 class Share < Jekyll::Command
  8. 1 def self.init_with_program(prog)
  9. prog.command(:share) do |c|
  10. c.syntax 'share'
  11. c.description 'Share latest post with each configured backend'
  12. c.option 'dry', '-d', '--dry', 'perform dry run'
  13. c.action { |args, opts| action(args, opts) }
  14. end
  15. end
  16. 1 def self.action(args, options)
  17. site = ::Jekyll::Site.new(configuration_from_options(options))
  18. site.reset
  19. site.read
  20. Social.action(site, args, options)
  21. rescue StandardError => e
  22. Jekyll.logger.error e.message
  23. exit 1
  24. end
  25. end
  26. end
  27. end

src/blog/entry.rb

100.0% lines covered

21 relevant lines. 21 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 module Blog
  3. # Entry
  4. 1 class Entry
  5. 1 include Blog::Time
  6. 1 def initialize(doc)
  7. 13 @doc = doc
  8. end
  9. 1 def content
  10. 5 @doc.content
  11. end
  12. 1 def date
  13. 5 @date ||= time_to_date(@doc.date)
  14. end
  15. 1 def title
  16. 1 to_uyd_date(date)
  17. end
  18. 1 def subtitle
  19. 1 @doc.data['title']
  20. end
  21. 1 def url
  22. 1 @doc.url
  23. end
  24. 1 def words
  25. 5 content.split.map do |token|
  26. 30 token.gsub!(/[^0-9a-z ']/i, '')
  27. 30 token.downcase
  28. end
  29. end
  30. 1 def word_count
  31. 1 @word_count ||= words.size
  32. end
  33. end
  34. end

src/blog/files.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 module Blog
  3. # Files
  4. 1 module Files
  5. 1 def root
  6. 1 File.expand_path(File.join(__dir__, '../../'))
  7. end
  8. 1 def join(*subpaths)
  9. 2 File.join(*subpaths)
  10. end
  11. end
  12. end

src/blog/filters.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'liquid'
  3. 1 module Blog
  4. # Filters
  5. 1 module Filters
  6. 1 def uyd_date(date)
  7. 1 date.strftime('%A, %B %-d %Y')
  8. end
  9. 1 def pretty(num)
  10. 1 num.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
  11. end
  12. end
  13. end
  14. 1 ::Liquid::Template.register_filter(Blog::Filters)

src/blog/generators.rb

53.49% lines covered

86 relevant lines. 46 lines covered and 40 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'jekyll'
  3. 1 require 'rake'
  4. 1 module Blog
  5. # Generators
  6. 1 module Generators
  7. # Base
  8. 1 module Base
  9. 1 include Blog::Logging
  10. 1 include Blog::Time
  11. end
  12. # Stats Generator
  13. 1 class Stats < Jekyll::Generator
  14. 1 include Base
  15. 1 include Blog::Math
  16. 1 attr_reader :site
  17. 1 def generate(site)
  18. @site = Site.new(site)
  19. site.data['stats'] = if @site.production?
  20. info 'calculating statistics'
  21. real_stats
  22. else
  23. info 'stubbing out statistics'
  24. stub_stats
  25. end
  26. end
  27. 1 def real_stats
  28. {
  29. 'total_words' => total(site.word_counts),
  30. 'average_words' => average(site.word_counts).round(0),
  31. 'total_posts' => site.entries.size,
  32. 'consecutive_posts' => consecutive_posts,
  33. 'swears' => calculate_swears
  34. }
  35. end
  36. 1 def stub_stats
  37. {
  38. 'total_words' => 0,
  39. 'average_words' => 0,
  40. 'total_posts' => 0,
  41. 'consecutive_posts' => 0,
  42. 'swears' => 0
  43. }
  44. end
  45. 1 private
  46. 1 def consecutive_posts
  47. calculate_streaks(site.dates).first['days']
  48. end
  49. 1 def calculate_swears
  50. results = Hash[count_swears]
  51. results['total'] = total(results.values)
  52. results
  53. end
  54. 1 def count_swears
  55. occurences(swears, site.words).reject { |_k, v| v.zero? }.sort_by { |_k, v| -v }
  56. end
  57. 1 def swears
  58. %w[
  59. ass asshole booger
  60. crap damn fart fuck hell jackass
  61. piss poop shit
  62. ]
  63. end
  64. end
  65. # GitGenerator
  66. 1 class GitGenerator < Jekyll::Generator
  67. 1 include Base
  68. 1 include Blog::Git
  69. 1 attr_reader :site
  70. 1 def generate(site)
  71. @site = Site.new(site)
  72. site.data.merge!(data)
  73. end
  74. 1 def data
  75. if site.production?
  76. info 'reading git history'
  77. real_data
  78. else
  79. info 'stubbing out git history'
  80. stub_data
  81. end
  82. end
  83. 1 def real_data
  84. {
  85. 'git_head' => git_head,
  86. 'git_head_summary' => git_head_summary,
  87. 'git_shorthead' => git_short_head,
  88. 'git_commit_count' => git_commit_count
  89. }
  90. end
  91. 1 def stub_data
  92. {
  93. 'git_head' => '',
  94. 'git_head_summary' => '',
  95. 'git_shorthead' => '',
  96. 'git_commit_count' => 0
  97. }
  98. end
  99. end
  100. # ResizeGenerator
  101. 1 class ResizeGenerator < Jekyll::Generator
  102. 1 include Base
  103. 1 def generate(site); end
  104. end
  105. # FrontmatterGenerator
  106. 1 class FrontmatterGenerator < Jekyll::Generator
  107. 1 include Base
  108. 1 def generate(site)
  109. info 'setting default frontmatter'
  110. scan_pages!(site)
  111. scan_posts!(site)
  112. end
  113. 1 def scan_pages!(site)
  114. site.pages.each do |page|
  115. filename = "#{File.basename(page.name, '.*')}.html"
  116. page.data['filename'] = filename
  117. page.data['permalink'] = filename if page.data['permalink'].nil?
  118. end
  119. end
  120. 1 def scan_posts!(site)
  121. site.posts.docs.each do |post|
  122. post.data.merge!(
  123. {
  124. 'title' => to_uyd_date(post.date),
  125. 'description' => post.data['title'],
  126. 'permalink' => "/#{to_filename_date(post.date)}.html",
  127. 'filename' => "#{to_filename_date(post.date)}.html"
  128. }
  129. )
  130. end
  131. end
  132. end
  133. # Nav Generator
  134. 1 class NavGenerator < Jekyll::Generator
  135. 1 include Base
  136. 1 attr_reader :site
  137. 1 def generate(site)
  138. @site = Site.new(site)
  139. info 'building site navigation'
  140. site.data['nav'] = nav
  141. end
  142. 1 def nav
  143. flagged_pages.sort_by { |p| p.data['nav'].to_i }
  144. end
  145. 1 def flagged_pages
  146. site.pages.select { |p| p.data.key? 'nav' }
  147. end
  148. end
  149. # CoverageGenerator
  150. 1 class CoverageGenerator < Jekyll::Generator
  151. 1 include Base
  152. 1 include Blog::Files
  153. 1 include Blog::Shell
  154. 1 def generate(site)
  155. info 'reading code coverage'
  156. data_file = join('_site/coverage/data.json')
  157. site.data['coverage'] = JSON.parse(File.read(data_file))
  158. end
  159. end
  160. end
  161. end

src/blog/git.rb

63.64% lines covered

11 relevant lines. 7 lines covered and 4 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 module Blog
  3. # Git
  4. 1 module Git
  5. 1 include Blog::Shell
  6. 1 def git_short_head
  7. shell('git rev-parse --short HEAD').chomp
  8. end
  9. 1 def git_head
  10. shell('git rev-parse HEAD').chomp
  11. end
  12. 1 def git_head_summary
  13. shell('git log -1 --pretty=format:"%s" HEAD').chomp
  14. end
  15. 1 def git_commit_count
  16. shell('git rev-list --count master').chomp.to_i
  17. end
  18. end
  19. end

src/blog/logging.rb

63.64% lines covered

11 relevant lines. 7 lines covered and 4 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'jekyll'
  3. 1 module Blog
  4. # Logging
  5. 1 module Logging
  6. 1 def info(msg)
  7. Jekyll.logger.info 'blog:', msg
  8. end
  9. 1 def debug(msg)
  10. Jekyll.logger.debug 'blog:', msg
  11. end
  12. 1 def error(msg)
  13. Jekyll.logger.error 'blog:', msg
  14. end
  15. 1 def warn(msg)
  16. Jekyll.logger.warn 'blog:', msg
  17. end
  18. end
  19. end

src/blog/math.rb

100.0% lines covered

11 relevant lines. 11 lines covered and 0 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 module Blog
  3. # Math
  4. 1 module Math
  5. 1 def average(numlist)
  6. 6 numlist.inject { |sum, el| sum + el }.to_f / numlist.size
  7. end
  8. 1 def total(numlist)
  9. 7 numlist.inject(0) { |sum, x| sum + x }
  10. end
  11. 1 def occurences(keys, targets)
  12. 1 results = Hash.new(0)
  13. 1 targets.each do |target|
  14. 12 results[target] += 1 if keys.include? target
  15. end
  16. 1 results
  17. end
  18. end
  19. end

src/blog/shell.rb

47.83% lines covered

23 relevant lines. 11 lines covered and 12 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'open3'
  3. 1 module Blog
  4. # Shell
  5. 1 module Shell
  6. # ShellCommand
  7. 1 class ShellCommand
  8. 1 include Blog::Logging
  9. 1 attr_reader :cmd, :stdout, :stderr, :status
  10. 1 def initialize(cmd)
  11. @cmd = cmd
  12. end
  13. 1 def run!
  14. @stdout, @err, @status = Open3.capture3(cmd)
  15. debug(to_s)
  16. end
  17. 1 def failed?
  18. !@status.success?
  19. end
  20. 1 def to_s
  21. msg = "`#{cmd}` returned #{status}"
  22. msg += "\n--- STDOUT\n#{stdout}" if stdout
  23. msg += "\n--- STDERR\n#{stderr}" if stderr
  24. msg
  25. end
  26. end
  27. 1 def shell(cmd, raises: true)
  28. result = ShellCommand.new(cmd)
  29. result.run!
  30. raise result.to_s if raises && result.failed?
  31. result.stdout
  32. end
  33. end
  34. end

src/blog/site.rb

70.21% lines covered

47 relevant lines. 33 lines covered and 14 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 module Blog
  3. # Site
  4. 1 class Site
  5. 1 def initialize(site)
  6. 8 @site = site
  7. end
  8. 1 def entries
  9. 2 @entries ||= build_entries
  10. end
  11. 1 def latest
  12. entries.first
  13. end
  14. 1 def pages
  15. @site.pages
  16. end
  17. 1 def production?
  18. 2 ENV['JEKYLL_ENV'] == 'production'
  19. end
  20. 1 def data
  21. 1 @site.data
  22. end
  23. 1 def url
  24. @site.config['url']
  25. end
  26. 1 def word_counts
  27. 1 entries.collect(&:word_count)
  28. end
  29. 1 def words
  30. entries.collect(&:words).flatten
  31. end
  32. 1 def dates
  33. 1 entries.collect(&:date)
  34. end
  35. 1 def images
  36. exts = ['.jpg', 'jpeg', '.png', '.svg']
  37. @site.static_files.collect(&:path).select { |f| exts.include? File.extname(f) }
  38. end
  39. 1 def root
  40. File.absolute_path(File.join(__dir__, '../../'))
  41. end
  42. 1 def root_join(path)
  43. File.join(root, path)
  44. end
  45. 1 def recker_config
  46. 1 @site.config.fetch('recker', {})
  47. end
  48. 1 def config
  49. @site.config
  50. end
  51. 1 def graphs_dir
  52. recker_config.fetch('graphs', 'assets/images/graphs/')
  53. end
  54. 1 def data_dir
  55. File.join root, '_data'
  56. end
  57. 1 def tmp_join(path)
  58. File.join root, 'tmp', path
  59. end
  60. 1 def graphs_join(path)
  61. File.join root, 'assets/images/graphs/', path
  62. end
  63. 1 def site_join(path)
  64. File.join(root, '_site', path)
  65. end
  66. 1 private
  67. 1 def build_entries
  68. 2 @site.posts.docs
  69. .select(&:published?)
  70. .sort_by(&:date)
  71. .reverse
  72. 4 .map { |p| Entry.new(p) }
  73. end
  74. end
  75. end

src/blog/time.rb

90.0% lines covered

20 relevant lines. 18 lines covered and 2 lines missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'date'
  3. 1 require 'time'
  4. 1 module Blog
  5. # Time
  6. 1 module Time
  7. 1 def time_to_date(time)
  8. 6 ::Date.parse(time.strftime('%Y-%m-%d'))
  9. end
  10. 1 def date_to_time(date)
  11. 1 date.to_time.to_datetime
  12. end
  13. 1 def to_uyd_date(date)
  14. 2 date.strftime('%A, %B %-d %Y')
  15. end
  16. 1 def to_filename_date(date)
  17. date.strftime('%Y-%m-%d')
  18. end
  19. 1 def parse_date(datestr)
  20. ::Date.parse(datestr).to_datetime.new_offset(offset).to_date
  21. end
  22. 1 def slice_by_consecutive(dates)
  23. 20 dates.slice_when { |p, c| c != p - 1 && c != p + 1 }.to_a
  24. end
  25. 1 def calculate_streaks(dates)
  26. 2 slice_by_consecutive(dates).map do |pair|
  27. 4 first, last = pair.minmax
  28. {
  29. 8 'days' => (last - first).to_i,
  30. 'start' => first,
  31. 'end' => last
  32. }
  33. end
  34. end
  35. end
  36. end