Module: Jekyll::Algolia::Utils

Defined in:
lib/jekyll/algolia/utils.rb

Overview

Generic language-wide utils

Class Method Summary collapse

Class Method Details

.compact_empty(hash) ⇒ Object

Public: Remove all keys with a nil value or an empty string from a hash

hash - The input hash



53
54
55
56
57
58
59
60
61
62
# 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

.diff_keys(alpha, beta) ⇒ Object

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



139
140
141
142
143
144
145
146
147
148
# 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

.find_by_key(items, key, value) ⇒ Object

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



87
88
89
90
91
92
93
# 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

.html_to_text(html) ⇒ Object

Public: Convert an HTML string to its content only

html - String representation of the HTML node



43
44
45
46
47
48
# 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

.instance_of?(input, classname) ⇒ Boolean

Public: Check if a variable is an instance of a specific class

input - the variable to test classname - the string representation of the class

Returns:

  • (Boolean)


33
34
35
36
37
38
# 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

.jsonify(item) ⇒ Object

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.



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# 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

.keys_to_symbols(hash) ⇒ Object

Public: Convert a hash with string keys to a hash with symbol keys

hash - The input hash, with string keys



25
26
27
# File 'lib/jekyll/algolia/utils.rb', line 25

def self.keys_to_symbols(hash)
  Hash[hash.map { |key, value| [key.to_sym, value] }]
end

.match?(string, regex) ⇒ Boolean

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.

Returns:

  • (Boolean)


71
72
73
74
75
76
77
78
# 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

.monkey_patch(instance, method, block) ⇒ Object

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



17
18
19
20
# 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

.split_lines(input, max_length) ⇒ Object

Public: Split a long text into lines of specific length

It takes care to not cut words



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# 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