Module: Aspire::Caching::Util

Includes:
Util
Included in:
Builder, Cache, CacheEntry
Defined in:
lib/aspire/caching/util.rb

Overview

Cache utility methods

Constant Summary collapse

CACHEABLE =

Rules for determining whether an object URL is cacheable Each rule is a Proc which accepts a parsed URL from #parse_url and the CacheEntry instance, and returns true if the object is cacheable or false if not. Rules are applied in the order specified and all rules must return true for an object to be cacheable.

[
  # The URL must be set and the host must mach the canonical tenancy host
  proc { |u, e| u && u[:tenancy_host] == e.cache.tenancy_host },
  # Catalog objects are not cacheable
  proc { |u, _e| u[:type] != 'catalog' },
  # User objects themselves are not cacheable but child objects e.g. notes
  # are cacheable
  proc { |u, _e| u[:type] != 'users' || !u[:child_type].nil? },
  # Importance URI values are not cacheable
  proc do |u, _e|
    u[:type] != 'config' || !u[:id].to_s.start_with?('importance')
  end
].freeze

Constants included from Util

Util::LD_API_URI

Instance Method Summary collapse

Methods included from Util

#child_url?, #duration, #id_from_uri, #item?, #linked_data, #linked_data_path, #list?, #list_url?, #module?, #parent_url?, #parse_url, #resource?, #section?, #url_for_comparison, #url_path, #user?

Instance Method Details

#add_filename_prefix(filename, prefix) ⇒ String

Adds a prefix to a filename

Parameters:

  • filename (String)

    the filename

  • prefix (String)

    the prefix

Returns:

  • (String)

    the filename with prefix



39
40
41
42
43
# File 'lib/aspire/caching/util.rb', line 39

def add_filename_prefix(filename, prefix)
  filename = filename.rpartition(File.basename(filename))
  filename[1] = "#{prefix}#{filename[1]}"
  filename.join
end

#add_filename_suffix(filename, suffix) ⇒ String

Adds a suffix to a filename preserving any file extension e.g. add_filename_suffix(‘file.txt’, ‘-suffix’) == ‘file-suffix.txt’

Parameters:

  • filename (String)

    the filename

  • suffix (String)

    the suffix

Returns:

  • (String)

    the filename with suffix



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/aspire/caching/util.rb', line 50

def add_filename_suffix(filename, suffix)
  f = filename.split(File::SEPARATOR)
  # If the filename is '.' or '..' add the suffix to the parent path,
  # otherwise add it to the basename
  i = %w[. ..].include?(f[-1]) ? -2 : -1
  # Split the basename around the file extension and prepend the suffix
  # to the extension
  if f[i]
    file_ext = f[i].rpartition(File.extname(f[i]))
    file_ext[1] = "#{suffix}#{file_ext[1]}"
    f[i] = file_ext.join
  end
  # Reconstruct the filename, preserving any trailing path separator
  f.push('') if filename.end_with?(File::SEPARATOR)
  File.join(f)
end

#cacheable_url(u) ⇒ MarchData

Parses the URL and checks that it is cacheable

Parameters:

  • u (String)

    the URL of the API object

Returns:

  • (MarchData)

    the parsed URL

Raises:



72
73
74
75
76
77
78
79
80
# File 'lib/aspire/caching/util.rb', line 72

def cacheable_url(u)
  # All rules must return true for the URL to be cacheable
  u = parse_url(u)
  CACHEABLE.each do |r|
    raise Aspire::Exceptions::NotCacheable unless r.call(u, self)
  end
  # Return the parsed URL
  u
end

#end_of_path?(dir, root = nil) ⇒ Boolean

Returns true if the directory path has no more parents, false otherwise

Parameters:

  • dir (String)

    the directory path

  • root (String) (defaults to: nil)

    the directory root - paths above this are ignored

Returns:

  • (Boolean)

    true if there are no more parents, false otherwise



86
87
88
# File 'lib/aspire/caching/util.rb', line 86

def end_of_path?(dir, root = nil)
  dir.nil? || dir.empty? || dir == '.' || dir == root
end

#mkdir(dir, logger = nil, success = nil, failure = nil) ⇒ void

This method returns an undefined value.

Creates a directory and its parents, logs errors

Parameters:

  • dir (String)

    the directory name

  • logger (Aspire::Caching::CacheLogger) (defaults to: nil)

    the logger for messages

  • failure (String) (defaults to: nil)

    the error message on failure

Raises:

  • (ArgumentError)

    if the directory is not specified

  • (Aspire::Cache::Exceptions::WriteError)

    if the operation fails



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/aspire/caching/util.rb', line 97

def mkdir(dir, logger = nil, success = nil, failure = nil)
  raise ArgumentError, 'Directory expected' if dir.nil? || dir.empty?
  FileUtils.mkdir_p(dir, mode: mode)
  return if logger.nil? || success.nil? || success.empty?
  logger.log(Logger::DEBUG, success)
rescue SystemCallError => e
  failure ||= "Create directory #{dir} failed"
  message = "#{failure}: #{e}"
  raise WriteError, message if logger.nil?
  logger.log_exception(message, WriteError)
end

#references(url, data = nil) ⇒ Array<String>

Returns the list of URI references from a linked data API object

Parameters:

  • url (String)

    the URL of the API object

  • data (Hash) (defaults to: nil)

    the parsed JSON data for the object

Returns:

  • (Array<String>)

    the list of URIs referenced by the object



113
114
115
116
117
118
119
120
121
# File 'lib/aspire/caching/util.rb', line 113

def references(url, data = nil)
  return [] if data.nil? || data.empty?
  # Enumerate the URIs and add them as keys of a hash to de-duplicate
  enum = Aspire::Enumerator::LinkedDataURIEnumerator.new.enumerator(url, data)
  uris = {}
  enum.each { |_k, hash, _i| uris[hash['value']] = true }
  # Return the list of URIs
  uris.keys
end

#rm(glob, logger = nil, success = nil, failure = nil) ⇒ void

This method returns an undefined value.

Removes the specified files

Parameters:

  • glob (String)

    the file pattern to be removed

  • logger (Aspire::Caching::CacheLogger) (defaults to: nil)

    the logger for messages

  • success (String) (defaults to: nil)

    the text for success log messages

  • failure (String) (defaults to: nil)

    the text for failure exception/log messages

Raises:

  • (Aspire::Cache::Exceptions::RemoveError)

    if the removal fails



130
131
132
133
134
135
136
137
138
139
140
# File 'lib/aspire/caching/util.rb', line 130

def rm(glob, logger = nil, success = nil, failure = nil)
  raise ArgumentError, 'file path required' if glob.nil? || glob.empty?
  FileUtils.rm_rf(Dir.glob(glob), secure: true)
  return if logger.nil? || success.nil? || success.empty?
  logger.log(Logger::INFO, success)
rescue SystemCallError => e
  failure ||= "Remove #{glob} failed"
  message = "#{failure}: #{e}"
  raise RemoveError, message if logger.nil?
  logger.log_exception("#{failure}: #{e}", RemoveError)
end

#rmdir_empty(path, root) ⇒ void

This method returns an undefined value.

Remove empty directories in a directory path

Parameters:

  • path (String)

    the starting file or directory

  • root

Raises:



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/aspire/caching/util.rb', line 147

def rmdir_empty(path, root)
  # The starting path is assumed to be a filename, so we append a dummy
  # filename if it's a directory
  path = File.directory?(path) ? File.join(path, '.') : path
  loop do
    # Get the parent of the current directory/file
    path = File.dirname(path)
    # Stop at the end of the directory path or a non-empty directory
    break if end_of_path?(path, root) || !Dir.empty?(path)
    # Remove the directory
    Dir.rmdir(path)
  end
rescue Errno::ENOTEMPTY, Errno::ENOTDIR
  # Stop without error if the directory is not empty or not a directory
  nil
rescue SystemCallError => e
  raise RemoveError, "Rmdir #{dir} failed: #{e}"
end

#strip_ext(path) ⇒ String

Removes the file extension from a path

Parameters:

  • path (String)

    the file path

Returns:

  • (String)

    the file path with any extension removed



169
170
171
# File 'lib/aspire/caching/util.rb', line 169

def strip_ext(path)
  path.rpartition(File.extname(path))[0]
end

#strip_filename_prefix(filename, prefix) ⇒ String

Removes a prefix from a filename

Parameters:

  • filename (String)

    the filename

  • prefix (String)

    the prefix

Returns:

  • (String)

    the filename without prefix



177
178
179
180
181
# File 'lib/aspire/caching/util.rb', line 177

def strip_filename_prefix(filename, prefix)
  f = filename.rpartition(File.basename(filename))
  f[1] = strip_prefix(f[1], prefix)
  f.join
end

#strip_filename_suffix(filename, suffix) ⇒ String

Removes a suffix from a filename

Parameters:

  • filename (String)

    the filename

  • suffix (String)

    the suffix

Returns:

  • (String)

    the filename without suffix



187
188
189
190
191
# File 'lib/aspire/caching/util.rb', line 187

def strip_filename_suffix(filename, suffix)
  f = filename.rpartition(File.extname(filename))
  f[0] = strip_suffix(f[0], suffix)
  f.join
end

#strip_prefix(str, prefix) ⇒ String

Removes a prefix from a string

Parameters:

  • str (String)

    the string to remove the prefix from

  • prefix (String)

    the prefix to remove

Returns:

  • (String)

    the string with the prefix removed



197
198
199
# File 'lib/aspire/caching/util.rb', line 197

def strip_prefix(str, prefix)
  str.start_with?(prefix) ? str.slice(prefix.length..-1) : str
end

#strip_suffix(str, suffix) ⇒ String

Removes a suffix from a string

Parameters:

  • str (String)

    the string to remove the suffix from

  • suffix (String)

    the suffix to remove

Returns:

  • (String)

    the string with the suffix removed



205
206
207
# File 'lib/aspire/caching/util.rb', line 205

def strip_suffix(str, suffix)
  str.end_with?(suffix) ? str.slice(0...-suffix.length) : str
end