lib/jekyll-twitter-plugin.rb in jekyll-twitter-plugin-2.0.0 vs lib/jekyll-twitter-plugin.rb in jekyll-twitter-plugin-2.1.0

- old
+ new

@@ -1,6 +1,7 @@ # frozen_string_literal: true + require "fileutils" require "net/http" require "uri" require "ostruct" require "json" @@ -9,16 +10,18 @@ ## # A Liquid tag plugin for Jekyll that renders Tweets from Twitter API. # https://github.com/rob-murray/jekyll-twitter-plugin # module TwitterJekyll + VERSION = "2.0.0".freeze + REFER_TO_README = "Please see 'https://github.com/rob-murray/jekyll-twitter-plugin' for usage.".freeze + LIBRARY_VERSION = "jekyll-twitter-plugin-v#{VERSION}".freeze + REQUEST_HEADERS = { "User-Agent" => LIBRARY_VERSION }.freeze + # TODO: remove after deprecation cycle CONTEXT_API_KEYS = %w(consumer_key consumer_secret access_token access_token_secret).freeze ENV_API_KEYS = %w(TWITTER_CONSUMER_KEY TWITTER_CONSUMER_SECRET TWITTER_ACCESS_TOKEN TWITTER_ACCESS_TOKEN_SECRET).freeze - REFER_TO_README = "Please see 'https://github.com/rob-murray/jekyll-twitter-plugin' for usage.".freeze - LIBRARY_VERSION = "jekyll-twitter-plugin-v2.0.0".freeze - REQUEST_HEADERS = { "User-Agent" => LIBRARY_VERSION }.freeze # Cache class that writes to filesystem # TODO: Do i really need to cache? # @api private class FileCache @@ -26,27 +29,26 @@ @cache_folder = File.expand_path path FileUtils.mkdir_p @cache_folder end def read(key) - file_to_read = cache_file(cache_filename(key)) + file_to_read = cache_file(key) JSON.parse(File.read(file_to_read)) if File.exist?(file_to_read) end def write(key, data) - file_to_write = cache_file(cache_filename(key)) - data_to_write = JSON.generate data.to_h + file_to_write = cache_file(key) File.open(file_to_write, "w") do |f| - f.write(data_to_write) + f.write(JSON.generate(data.to_h)) end end private - def cache_file(filename) - File.join(@cache_folder, filename) + def cache_file(key) + File.join(@cache_folder, cache_filename(key)) end def cache_filename(cache_key) "#{cache_key}.cache" end @@ -73,11 +75,10 @@ http.open_timeout = 5 http.get uri.request_uri, REQUEST_HEADERS end handle_response(api_request, response) - rescue Timeout::Error => e ErrorResponse.new(api_request, e.class.name).to_h end private @@ -140,15 +141,26 @@ # @api public class TwitterTag < Liquid::Tag ERROR_BODY_TEXT = "<p>Tweet could not be processed</p>".freeze OEMBED_ARG = "oembed".freeze + URL_OR_STRING_PARAM = /^("|')?(http|https):\/\//i + attr_writer :cache # for testing def initialize(_name, params, _tokens) super - @api_request = parse_params(params) + + # Test if first arg is a URL or starts with oembed, + # otherwise its a Jekyll variable. TODO: remove oembed after deprecation cycle + if params =~ URL_OR_STRING_PARAM || params.to_s.start_with?(OEMBED_ARG) + @fetch_from_context = false + @api_request = parse_params_from_string(params) + else + @fetch_from_context = true + @variable_params = normalize_string_params(params) + end end # Class that implements caching strategy # @api private def self.cache_klass @@ -156,17 +168,27 @@ end # Return html string for Jekyll engine # @api public def render(context) + if fetch_from_context? + variable_name, *params = @variable_params + tweet_url = context[variable_name] + @api_request = parse_params_from_array [tweet_url, *params] + end + api_secrets_deprecation_warning(context) # TODO: remove after deprecation cycle response = cached_response || live_response html_output_for(response) end private + def fetch_from_context? + @fetch_from_context + end + def cache @cache ||= self.class.cache_klass.new("./.tweet-cache") end def api_client @@ -195,40 +217,54 @@ def cached_response response = cache.read(@api_request.cache_key) build_response(response) unless response.nil? end + def parse_params_from_string(str) + args = normalize_string_params(str) + parse_params(args) + end + + def parse_params_from_array(arr) + parse_params(arr) + end + # Return an `ApiRequest` with the url and arguments # @api private - def parse_params(params) - args = params.split(/\s+/).map(&:strip) - invalid_args!(args) unless args.any? + def parse_params(args) + invalid_args!(args) unless args.compact.any? if args[0].to_s == OEMBED_ARG # TODO: remove after deprecation cycle arguments_deprecation_warning(args) args.shift end url, *api_args = args - ApiRequest.new(url, parse_args(api_args)) + ApiRequest.new(url, hash_from_args(api_args)) end + # Take input arguments, remove quotes & return array of argument values + # @api private + def normalize_string_params(str) + str.to_s.gsub(/"|'/, "").split(/\s+/).map(&:strip) + end + # Transform 'a=b x=y' tag arguments into { "a" => "b", "x" => "y" } # @api private - def parse_args(args) - args.each_with_object({}) do |arg, params| + def hash_from_args(args) + args.each_with_object({}) do |arg, results| k, v = arg.split("=").map(&:strip) if k && v v = Regexp.last_match[1] if v =~ /^'(.*)'$/ - params[k] = v + results[k] = v end end end # Format a response hash # @api private - def build_response(h) - OpenStruct.new(h) + def build_response(response_hash) + OpenStruct.new(response_hash) end # TODO: remove after deprecation cycle def arguments_deprecation_warning(args) warn "#{LIBRARY_VERSION}: Passing '#{OEMBED_ARG}' as the first argument is not required anymore. This will result in an error in future versions.\nCalled with #{args.inspect}"