As I mentioned earlier I really like the things that the Yoast SEO plugin does for WordPress for search engine optimization (SEO). One of those things is the readability check.

Yoast checks each article you write for its readability, in other words: Is your article easy to read? You are writing for your readers, are you not?

I slightly modified the rakefile from www.mikemackintosh.com to suit my own needs. The original checked if the Flesch-Kinkaid readability was below 80. If it was, it failed the task, so the site wouldn’t be build.

I on the other hand wanted to know what the score was for each post, so I modified it to show each score.

Just like the other SEO tests I put it in a rake task.

If you want to know more about readability and the Flesch-Kinkaid tests in speficic, go to Flesch-Kinkaid Wikipedia page

###The task
For the task to work you need to use the Lingua gem. install it with ‘gem install lingua’ or put it into your Gemfile

Here is the script:

task :readability do
  require 'find'
  require 'lingua'
  # Create a simple function to do this
  def calculate_score(text)
    # Remove the frontmatter, and codeblocks, because this will impact the score
    frontmatter = /(---)((?:(?:r?n)+(?:w|s).*)+r?n)(?=---r?n)(.*?)/x
    fenced_code = /`{3}(?:(.*$)n)?([sS]*)`{3}/mx
    nested_code = /((?:^(?:[ ]{4}|t).*$(?:r?n|z))+)/x
    parsed = text.gsub(frontmatter, "#{$3}").gsub(fenced_code, "").gsub(nested_code, "")
    score = Lingua::EN::Readability.new( parsed ).flesch
    if score > 100
      return score, "an Elementary Schooler"
    elsif score.between?(80,100)
      return score, "a Middle Schooler"
    elsif score.between?(50,80)
      return score, "a High Schooler"
    elsif score.between?(30,50)
      return score, "an Average Adult"
    elsif score.between?(0,30)
      return score, "a College Level Student"
    else
      return score, "a PhD Academic"
    end
  end
  # Get all posts in ./_posts
  Find.find("./_posts/") do |post|
    if File.file?(post)
      score, level = calculate_score(File.read(post))
      puts "#{post} has a score of #{(score).round(1)}, which is suitable for #{level}"
    end
  end
end