module Jekyll::Algolia::Utils
Generic language-wide utils
Public Class Methods
Public: Remove all keys with a nil value or an empty string from a hash
hash - The input hash
# File lib/jekyll/algolia/utils.rb, line 53 def self.compact_empty(hash) new_hash = {} hash.each do |key, value| next if value.nil? next if value.is_a?(String) && value.empty? new_hash[key] = value end new_hash end
Public: Get a hash representing the difference between two hashes
It only checks that all keys of alpha are also in beta, with the same value. If not, it remember what was the value of beta and return it in the output
# File lib/jekyll/algolia/utils.rb, line 139 def self.diff_keys(alpha, beta) diff = {} alpha.each do |key, value| diff[key] = beta[key] if beta[key] != value end return nil if diff.empty? diff end
Public: Find an item from an array based on the value of one of its key
items - The array of hashes to search key - The key to search for value - The value of the key to filter
It is basically a wrapper around [].find, handling more edge-cases
# File lib/jekyll/algolia/utils.rb, line 87 def self.find_by_key(items, key, value) return nil if items.nil? items.find do |item| item[key] == value end end
Public: Convert an HTML string to its content only
html - String representation of the HTML node
# File lib/jekyll/algolia/utils.rb, line 43 def self.html_to_text(html) return nil if html.nil? text = Nokogiri::HTML(html).text text.tr("\n", ' ').squeeze(' ').strip end
Public: Check if a variable is an instance of a specific class
input - the variable to test classname - the string representation of the class
# File lib/jekyll/algolia/utils.rb, line 33 def self.instance_of?(input, classname) input.instance_of? Object.const_get(classname) rescue StandardError # The class might not even exist false end
Public: Convert an object into an object that can easily be converted to JSON, to be stored as a record
item - The object to convert
It will keep any string, number, boolean,boolean,array or nested object, but will try to stringify other objects, excluding the one that contain a unique identifier once serialized.
# File lib/jekyll/algolia/utils.rb, line 103 def self.jsonify(item) simple_types = [ NilClass, TrueClass, FalseClass, Integer, Float, String ] # Integer arrived in Ruby 2.4. Before that it was Fixnum and Bignum if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0') # rubocop:disable Lint/UnifiedInteger simple_types += [Fixnum, Bignum] # rubocop:enable Lint/UnifiedInteger end return item if simple_types.member?(item.class) # Recursive types return item.map { |value| jsonify(value) } if item.is_a?(Array) if item.is_a?(Hash) return item.map { |key, value| [key, jsonify(value)] }.to_h end # Can't be stringified, discard it return nil unless item.respond_to?(:to_s) # Discard also if is a serialized version with unique identifier stringified = item.to_s return nil if match?(stringified, /#<[^ ].*@[0-9]* .*>/) stringified end
Public: Convert a hash with string keys to a hash with symbol keys
hash - The input hash, with string keys
# File lib/jekyll/algolia/utils.rb, line 25 def self.keys_to_symbols(hash) Hash[hash.map { |key, value| [key.to_sym, value] }] end
Public: Check if a string matches a regex
string - The string to test regex - The regex to match against
Newer versions of Ruby have easy ways to test this, but a wrapper is needed for older versions.
# File lib/jekyll/algolia/utils.rb, line 71 def self.match?(string, regex) # Ruby 2.4 introduces .match? return regex.match?(string) if regex.respond_to?(:match?) # Older versions of Ruby have to deal with =~ returning nil if no match # is found !(string =~ regex).nil? end
Public: Allow redefining an instance method on the fly with a new one
instance - The instance to overwrite method - The method symbol to overwrite block - The new block to use for replacing (as a proc)
Solution found on stackoverflow.com/questions/803020/redefining-a-single-ruby-method-on-a-single-instance-with-a-lambda/16631789
# File lib/jekyll/algolia/utils.rb, line 17 def self.monkey_patch(instance, method, block) metaclass = class << instance; self; end metaclass.send(:define_method, method, block) end
Public: Split a long text into lines of specific length
It takes care to not cut words
# File lib/jekyll/algolia/utils.rb, line 153 def self.split_lines(input, max_length) # Force splitting on actual new lines first if input.include?("\n") output = [] input.split("\n").each do |line| output += split_lines(line, max_length) end return output end output = [] words = input.split(' ') current_line = words.shift || '' test_line = '' # must be defined outside of the loop words.each do |word| test_line = "#{current_line} #{word}" if test_line.length > max_length output << current_line current_line = word next end current_line = test_line end output << current_line # Making sure all lines are the same length output.map { |line| line.ljust(max_length, ' ') } end